59
58
static void display_white_turn (gboolean whiteturn);
60
59
static void display_info (gchar *info);
61
static int get_square (double x, double y);
62
60
static int get_square_from_coord (double x, double y);
64
62
#define CHESSBOARD_X 50
65
63
#define CHESSBOARD_Y 20
66
64
#define SQUARE_WIDTH 60
67
65
#define SQUARE_HEIGHT 60
68
#define BLACK_COLOR 0x206070FF
69
#define WHITE_COLOR 0x4ACCFAFF
70
#define BLACK_COLOR_H 0x6B96A2FF
71
#define WHITE_COLOR_H 0xA6E7FFFF
66
#define WHITE_COLOR 0xFFFF99FF
67
#define BLACK_COLOR 0x9999FFFF
68
#define WHITE_COLOR_H 0x99FF99FF
69
#define BLACK_COLOR_H 0x99FF99FF
73
71
#define TURN_X (BOARDWIDTH-(BOARDWIDTH-(CHESSBOARD_X+(SQUARE_WIDTH*8)))/2)
74
72
#define TURN_Y (CHESSBOARD_Y+15)
117
113
static void chess_next_level(void);
118
114
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
119
115
static gint item_event_black(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
120
static int start_child (char *cmd,
116
static gboolean start_child (char *cmd,
122
117
GIOChannel **read_chan,
123
118
GIOChannel **write_chan,
126
121
static void write_child (GIOChannel *write_chan,
130
static int stop_child (pid_t childpid);
132
126
/* Description of this plugin */
133
127
static BoardPlugin menu_bp =
137
N_("Learning Chess"),
138
N_("Play chess against tux in a learning mode"),
132
"Play chess against tux in a learning mode",
139
133
"Bruno Coudoin <bruno.coudoin@free.fr>",
181
173
board_paused = pause;
176
void gnuchess_died(int signum)
179
gc_dialog(_("Error: The external program gnuchess died unexpectedly"), gc_board_stop);
186
184
static void start_board (GcomprisBoard *agcomprisBoard)
189
if (g_file_test ("/usr/bin/gnuchessx", G_FILE_TEST_EXISTS)) {
191
gcompris_dialog(_("Error: /usr/bin/gnuchessx is installed\nwhich means you have an old version\nof gnuchess.\nPlease upgrade to gnuchess 5 or above."), gcompris_end_board);
196
if (!g_file_test (GNUCHESS, G_FILE_TEST_EXISTS)) {
198
gcompris_dialog(_("Error: The external program gnuchess is mandatory\nto play chess in gcompris.\nFind this program on http://www.rpmfind.net or in your\nGNU/Linux distribution\nAnd check it is in "GNUCHESS), gcompris_end_board);
190
signal(SIGTRAP, gnuchess_died);
191
signal(SIGPIPE, gnuchess_died);
192
if (!g_file_test (GNUCHESS, G_FILE_TEST_EXISTS))
194
gc_dialog(_("Error: The external program gnuchess is required\nto play chess in gcompris.\n"
195
"Find this program on http://www.rpmfind.net or in your\nGNU/Linux distribution\n"
196
"And check it is located here: "GNUCHESS),
203
202
if(agcomprisBoard!=NULL)
210
205
gcomprisBoard=agcomprisBoard;
212
207
/* Default mode */
213
208
if(!gcomprisBoard->mode)
214
209
gameType=COMPUTER;
218
213
gameType=PARTYEND;
219
214
else if(g_strncasecmp(gcomprisBoard->mode, "movelearn", 1)==0)
220
215
gameType=MOVELEARN;
222
217
gcomprisBoard->level=1;
223
218
gcomprisBoard->maxlevel=1;
224
219
gcomprisBoard->sublevel=1;
225
220
gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
231
226
gcomprisBoard->maxlevel=9;
232
gcompris_bar_set(GCOMPRIS_BAR_LEVEL);
227
gc_bar_set(GC_BAR_LEVEL);
238
start_child (GNUCHESS, param, &read_chan,
239
&write_chan, &childpid);
241
read_cb = g_io_add_watch (read_chan, G_IO_IN,
233
if(start_child (GNUCHESS, &read_chan,
234
&write_chan, &gnuchess_pid)==FALSE)
236
gc_dialog(_("Error: The external program gnuchess is mandatory\n"
237
"to play chess in gcompris.\n"
238
"First install it, and check it is in "GNUCHESS), gc_board_stop);
242
read_cb = g_io_add_watch (read_chan, G_IO_IN|G_IO_PRI,
242
243
engine_local_cb, NULL);
243
244
err_cb = g_io_add_watch (read_chan, G_IO_HUP,
244
245
engine_local_err_cb, NULL);
246
247
write_child (write_chan, "xboard\n");
247
248
write_child (write_chan, "protover 2\n");
248
249
write_child (write_chan, "post\n");
249
250
write_child (write_chan, "easy\n");
250
251
write_child (write_chan, "level 100 1 0\n");
251
252
write_child (write_chan, "depth 1\n");
253
write_child (write_chan, "time 500\n");
253
255
chess_next_level();
256
258
pause_board(FALSE);
260
263
/* ======================================= */
261
264
static void end_board ()
267
signal(SIGTRAP, NULL);
268
signal(SIGPIPE, NULL);
263
270
if(gcomprisBoard!=NULL)
265
272
pause_board(TRUE);
498
501
need_slash = TRUE;
502
san = g_strdup (temp);
505
504
// printf("square=%d piece=%d x=%d y=%d\n", square, piece, x, y);
506
505
if(piece != EMPTY)
508
str = g_strdup_printf("chess/%c.png", piece_to_ascii(piece));
510
pixmap = gcompris_load_pixmap(str);
508
str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
510
str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
512
pixmap = gc_pixmap_load(str);
511
513
// g_warning("loading piece %s\n", str);
513
515
item = gnome_canvas_item_new (boardRootItem,
514
516
gnome_canvas_pixbuf_get_type (),
516
518
"x", (double)CHESSBOARD_X + (x * SQUARE_WIDTH) +
517
519
(guint)((SQUARE_WIDTH-gdk_pixbuf_get_width(pixmap))/2),
518
520
"y", (double) CHESSBOARD_Y + ((7-y) * SQUARE_HEIGHT) +
519
521
(guint)((SQUARE_HEIGHT-gdk_pixbuf_get_height(pixmap))/2),
522
524
chessboard[square]->piece_item = item;
523
525
if(WPIECE(piece))
524
gtk_signal_connect(GTK_OBJECT(item), "event",
526
gtk_signal_connect(GTK_OBJECT(item), "event",
525
527
(GtkSignalFunc) item_event, NULL);
527
gtk_signal_connect(GTK_OBJECT(item), "event",
529
gtk_signal_connect(GTK_OBJECT(item), "event",
528
530
(GtkSignalFunc) item_event_black, NULL);
530
532
gdk_pixbuf_unref(pixmap);
566
568
turn_item = gnome_canvas_item_new (boardRootItem,
567
569
gnome_canvas_text_get_type (),
569
"font", gcompris_skin_font_board_big,
571
"font", gc_skin_font_board_big,
570
572
"x", (double) TURN_X,
571
573
"y", (double) TURN_Y,
572
574
"anchor", GTK_ANCHOR_CENTER,
573
"fill_color_rgba", gcompris_skin_color_content,
575
"fill_color_rgba", gc_skin_color_content,
577
gnome_canvas_item_set(turn_item, "text", (whiteturn ? _("White Turn") : _("Black Turn")),
579
gnome_canvas_item_set(turn_item, "text", (whiteturn ? _("White's Turn") : _("Black's Turn")),
647
649
/* Show the moved piece */
648
650
gnome_canvas_item_set(source_square->square_item,
650
(BPIECE(position->square[to])?"red":"green"),
652
(BPIECE(position->square[to])?"red":"blue"),
653
655
display_white_turn(BPIECE(position->square[to]));
658
660
g_warning(" move_piece_to to x=%d y=%d\n", x, y);
660
662
dest_square = chessboard[to];
662
664
/* Show the moved piece */
663
665
gnome_canvas_item_set(dest_square->square_item,
665
(BPIECE(position->square[to])?"red":"green"),
667
(BPIECE(position->square[to])?"red":"blue"),
668
670
if(dest_square->piece_item != NULL)
702
704
g_warning(" WARNING promoting a pawn from=%d to=%d piece=%d\n", from, to, piece);
703
705
g_warning(" piece_to_ascii returns %c\n", piece_to_ascii(piece));
705
str = g_strdup_printf("chess/%c.png", piece_to_ascii(piece));
707
pixmap = gcompris_load_pixmap(str);
708
str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
710
str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
712
pixmap = gc_pixmap_load(str);
709
714
g_warning("loading piece %c\n", piece_to_ascii(piece));
710
715
gnome_canvas_item_set (dest_square->piece_item,
716
721
/* Display check info */
717
722
if(position_white_king_attack(position))
718
display_info(_("White check"));
723
display_info(_("White checks"));
719
724
else if(position_black_king_attack(position))
720
display_info(_("Black check"));
725
display_info(_("Black checks"));
722
727
display_info(" ");
896
888
g_warning("====== MOVE from %d REFUSED\n", gsquare->square);
898
890
/* Find the ofset to move the piece back to where it was*/
899
891
gnome_canvas_item_get_bounds (item,
905
897
x = gsquare->square % 10;
906
898
y = gsquare->square / 10 -1;
908
900
ofset_x = (CHESSBOARD_X + SQUARE_WIDTH * (x-1)) - x1 + (SQUARE_WIDTH - (x2-x1))/2;
909
901
ofset_y = (CHESSBOARD_Y + SQUARE_HEIGHT * (8-y)) - y1 + (SQUARE_HEIGHT - (y2-y1))/2;
910
902
g_warning("ofset = x=%f y=%f\n", ofset_x, ofset_y);
912
904
gnome_canvas_item_move(item, ofset_x, ofset_y);
915
gnome_canvas_item_ungrab(item, event->button.time);
907
gc_canvas_item_ungrab(item, event->button.time);
916
908
dragging = FALSE;
918
910
position_display(position);
957
952
/*======================================================================*/
958
953
/*======================================================================*/
960
engine_local_destroy ()
955
engine_local_destroy (GPid gnuchess_pid)
963
961
g_warning("engine_local_destroy () \n");
964
// write_child (write_chan, "quit\n");
962
write_child (write_chan, "quit\n");
966
964
g_source_remove(read_cb);
967
965
g_source_remove(err_cb);
969
967
g_io_channel_close (read_chan);
970
968
g_io_channel_unref (read_chan);
972
970
g_io_channel_close (write_chan);
973
971
g_io_channel_unref (write_chan);
975
stop_child (childpid);
974
g_spawn_close_pid(gnuchess_pid);
977
/** We got data back from gnuchess, we parse them here
979
981
engine_local_cb (GIOChannel *source,
980
982
GIOCondition condition,
983
static char buf[1024];
989
g_io_channel_read (read_chan, b, sizeof (buf) - 1 - (b - buf), &len);
990
GIOStatus status = G_IO_STATUS_NORMAL;
992
g_warning("engine_local_cb");
994
status = g_io_channel_read_chars(source,
1000
g_warning("g_io_channel_read_line len=%d", (int)len);
1001
if(status == G_IO_STATUS_ERROR)
1003
g_warning("g_io_channel_read_chars error=%s",
1005
/* FIXME: Not sure what to do */
1009
if(status != G_IO_STATUS_NORMAL)
1011
g_warning("g_io_channel_read_chars error=%d",
1013
/* FIXME: Not sure what to do */
1017
g_warning("engine_local_cb read=%s\n", buf);
999
1027
q = strchr (buf,'\n');
1000
1028
if (q == NULL) break;
1007
g_warning("engine_local_cb read=%s\n", &buf);
1035
g_warning("engine_local_cb read=%s\n", buf);
1009
1037
/* parse for NUMBER ... MOVE */
1010
1038
if (isdigit (*buf))
1011
if ((p = strstr (buf, "...")))
1015
g_warning("computer number moves to %s\n", p+4);
1017
if (san_to_move (position, p+4, &from, &to))
1018
ascii_to_move (position, p+4, &from, &to);
1020
position_move (position, from, to);
1021
move_piece_to(from , to);
1023
else if ((p = strstr (buf, " ")))
1025
/* It's a legal move case */
1026
g_warning("Legal move to %s\n", p+1);
1040
if ((p = strstr (buf, "...")))
1044
g_warning("computer number moves to %s\n", p+4);
1046
if (san_to_move (position, p+4, &from, &to))
1047
ascii_to_move (position, p+4, &from, &to);
1049
position_move (position, from, to);
1050
move_piece_to(from , to);
1052
else if ((p = strstr (buf, " ")))
1054
/* It's a legal move case */
1055
g_warning("Legal move to %s\n", p+1);
1029
1059
/* parse for move MOVE */
1030
1060
if (!strncmp ("My move is : ",buf,13))
1032
1062
Square from, to;
1034
1064
p = strstr (buf, ":");
1035
printf("computer moves to %s\n", p+1);
1065
g_warning("computer moves to %s\n", p+1);
1037
1067
if (san_to_move (position, p+1, &from, &to))
1038
1068
ascii_to_move (position, p+1, &from, &to);
1086
1116
GIOCondition condition,
1089
g_error ("Local Engine connection died");
1120
gc_dialog(_("Error: The external program gnuchess died unexpectingly"), gc_board_stop);
1095
* FIXME : This should be centralised in gcompris core because only
1096
* the last signal command is kept at system level
1097
* there is a potential risk because signal child is also used
1098
* to manage ogg123 sounds.
1101
/* =====================================================================
1102
* Process the cleanup of the child (no zombies)
1103
* =====================================================================*/
1104
void chess_child_end(int signum)
1108
g_warning("chess child_end signal=%d\n", signum);
1110
pid = waitpid(childpid, NULL, WNOHANG);
1111
g_warning("chess child_end pid=%d\n", pid);
1114
g_error("chess_child_end Error waitpid");
1118
1124
/*----------------------------------------
1119
1125
* Subprocess creation
1126
* Return TRUE if gnuchess is started, false instead
1120
1127
*----------------------------------------*/
1123
start_child (char *cmd,
1125
GIOChannel **read_chan,
1126
GIOChannel **write_chan,
1130
start_child (char *cmd,
1131
GIOChannel **read_chan,
1132
GIOChannel **write_chan,
1133
GPid *Child_Process)
1129
int pipe1[2], pipe2[2];
1131
if ((pipe (pipe1) <0) || (pipe (pipe2) < 0)) {
1136
signal(SIGCHLD, chess_child_end);
1138
if ((*childpid = fork ()) < 0) {
1141
} else if (*childpid > 0) /* Parent */ {
1145
*read_chan = g_io_channel_unix_new (pipe2[0]);
1146
*write_chan = g_io_channel_unix_new (pipe1[1]);
1149
} else /* Child */ {
1159
if (execvp (cmd, arg) < 0)
1161
g_warning("In order to play chess, you need to have gnuchess installed as " GNUCHESS);
1167
g_assert_not_reached ();
1135
gint Child_In, Child_Out, Child_Err;
1136
GError *gerror = NULL;
1138
gchar *Child_Argv[]={ cmd, "-e", NULL };
1140
g_warning("Ready to start child");
1142
if (!g_spawn_async_with_pipes(NULL, Child_Argv, NULL,
1143
G_SPAWN_SEARCH_PATH,
1144
NULL, NULL, Child_Process, &Child_In, &Child_Out,
1145
&Child_Err, &gerror)) {
1147
g_warning("Error message '%s'", gerror->message);
1148
g_warning("Error code '%d'", gerror->code);
1149
g_error_free (gerror);
1150
g_warning("In order to play chess, you need to have gnuchess installed as " GNUCHESS);
1155
g_warning("gnuchess subprocess is started");
1157
*read_chan = g_io_channel_unix_new (Child_Out);
1158
*write_chan = g_io_channel_unix_new (Child_In);
1160
if(g_io_channel_set_encoding(*write_chan, NULL, NULL) != G_IO_STATUS_NORMAL)
1161
g_warning("Failed to set NULL encoding");
1163
if(g_io_channel_set_flags (*read_chan, G_IO_FLAG_NONBLOCK, NULL) != G_IO_STATUS_NORMAL)
1164
g_warning("Failed to set NON BLOCKING IO");
1166
if(g_io_channel_set_flags (*write_chan, G_IO_FLAG_NONBLOCK, NULL) != G_IO_STATUS_NORMAL)
1167
g_warning("Failed to set NON BLOCKING IO");
1173
write_child (GIOChannel *write_chan, char *format, ...)
1172
/** Write a command to the gnuchess backend
1176
write_child (GIOChannel *write_chan, char *format, ...)
1182
GError *error = NULL;
1180
1184
va_start (ap, format);
1182
1186
buf = g_strdup_vprintf (format, ap);
1184
err = g_io_channel_write (write_chan, buf, strlen (buf), &len);
1185
if (err != G_IO_ERROR_NONE)
1188
err = g_io_channel_write_chars (write_chan, buf, strlen (buf), &len, &error);
1190
if (err == G_IO_STATUS_ERROR)
1191
g_error ("Error writing: %s\n", error->message);
1193
if (err != G_IO_STATUS_NORMAL)
1186
1194
g_warning ("Writing to child process failed");
1196
g_warning ("Wrote '%s' to gnuchess", buf);
1188
g_warning ("%s", buf);
1198
err = g_io_channel_flush (write_chan, &error);
1199
if (err == G_IO_STATUS_ERROR)
1200
g_error ("Error flushing: %s\n", error->message);
1197
stop_child (pid_t childpid)
1200
g_warning("stop_child (childpid=%d) () \n", childpid);
1202
if (childpid && kill (childpid, SIGTERM) ) {
1203
g_message ("Failed to kill child!\n");