Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Coudoin <bruno.coudoin@free.fr>2009-07-05 14:42:37 (GMT)
committer Bruno Coudoin <bruno.coudoin@free.fr>2009-07-05 14:42:37 (GMT)
commit6396aed48fd988759f9c80ea48184660468602a1 (patch)
tree96ef4495f260cd66193b6ff84abe107b786e53af
parentd74481f4443d25d2fd89419a1314b5f298ae614c (diff)
The version of chess that works on windows.
-rw-r--r--src/boards/chess_windows.c1158
1 files changed, 1158 insertions, 0 deletions
diff --git a/src/boards/chess_windows.c b/src/boards/chess_windows.c
new file mode 100644
index 0000000..6570da0
--- /dev/null
+++ b/src/boards/chess_windows.c
@@ -0,0 +1,1158 @@
+/* gcompris - chess.c
+ *
+ * Copyright (C) 2002 Bruno Coudoin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "chess_notation.h"
+
+#include "gcompris/gcompris.h"
+
+#if defined _WIN32 || defined __WIN32__
+# undef WIN32 /* avoid warning on mingw32 */
+# define WIN32
+#endif
+
+#define SOUNDLISTFILE PACKAGE
+
+static GcomprisBoard *gcomprisBoard = NULL;
+static gboolean board_paused = TRUE;
+
+static GPid gnuchess_pid;
+static void start_board (GcomprisBoard *agcomprisBoard);
+static void pause_board (gboolean pause);
+static void end_board (void);
+static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
+static void set_level (guint level);
+static int gamewon;
+static void game_won(void);
+
+static void engine_local_destroy (GPid gnuchess_pid);
+
+static gboolean engine_local_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data);
+static gboolean engine_local_err_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data);
+static void display_white_turn (gboolean whiteturn);
+static void display_info (gchar *info);
+static int get_square (double x, double y);
+static int get_square_from_coord (double x, double y);
+
+#define CHESSBOARD_X 50
+#define CHESSBOARD_Y 20
+#define SQUARE_WIDTH 60
+#define SQUARE_HEIGHT 60
+#define WHITE_COLOR 0xFFFF99FF
+#define BLACK_COLOR 0x9999FFFF
+#define WHITE_COLOR_H 0x99FF99FF
+#define BLACK_COLOR_H 0x99FF99FF
+
+#define TURN_X (BOARDWIDTH-(BOARDWIDTH-(CHESSBOARD_X+(SQUARE_WIDTH*8)))/2)
+#define TURN_Y (CHESSBOARD_Y+15)
+
+#define INFO_X TURN_X
+#define INFO_Y (TURN_Y+40)
+
+/* Game Type */
+#define COMPUTER 1
+#define PARTYEND 2
+#define MOVELEARN 3
+
+static char gameType = COMPUTER;
+
+static GnomeCanvasGroup *boardRootItem = NULL;
+
+static GIOChannel *read_chan;
+static GIOChannel *write_chan;
+
+static gint read_cb;
+static gint err_cb;
+
+static Position *position;
+
+/*
+ * Contains the squares structure
+ */
+typedef struct {
+ GnomeCanvasItem *square_item;
+ GnomeCanvasItem *piece_item;
+ Square square;
+} GSquare;
+
+static GSquare *currentHighlightedGsquare;
+
+static GnomeCanvasItem *turn_item = NULL;
+static GnomeCanvasItem *info_item = NULL;
+
+/* Need more space to fit notation.h definition */
+static GSquare *chessboard[100];
+
+static GnomeCanvasItem *chess_create_item(GnomeCanvasGroup *parent);
+static void chess_destroy_all_items(void);
+static void chess_next_level(void);
+static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
+static gint item_event_black(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
+static gboolean start_child (char *cmd,
+ GIOChannel **read_chan,
+ GIOChannel **write_chan,
+ GPid *gnuchess_pid);
+
+static void write_child (GIOChannel *write_chan,
+ char *format,
+ ...);
+
+
+/* Description of this plugin */
+static BoardPlugin menu_bp =
+ {
+ NULL,
+ NULL,
+ "Learning Chess",
+ "Play chess against tux in a learning mode",
+ "Bruno Coudoin <bruno.coudoin@free.fr>",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ start_board,
+ pause_board,
+ end_board,
+ is_our_board,
+ NULL,
+ NULL,
+ set_level,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+/*
+ * Main entry point mandatory for each Gcompris's game
+ * ---------------------------------------------------
+ *
+ */
+
+GET_BPLUGIN_INFO(chess)
+
+/*
+ * in : boolean TRUE = PAUSE : FALSE = CONTINUE
+ *
+ */
+static void pause_board (gboolean pause)
+{
+ if(gcomprisBoard==NULL)
+ return;
+
+ if(gamewon == TRUE && pause == FALSE) /* the game is won */
+ {
+ game_won();
+ }
+
+ board_paused = pause;
+}
+
+/*
+ */
+static void start_board (GcomprisBoard *agcomprisBoard)
+{
+
+#ifndef WIN32
+ if (!g_file_test (GNUCHESS, G_FILE_TEST_EXISTS)) {
+
+ gc_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 located here: "GNUCHESS), gc_board_end);
+
+ return;
+ }
+#endif
+
+ if(agcomprisBoard!=NULL)
+ {
+
+ gcomprisBoard=agcomprisBoard;
+
+ /* Default mode */
+ if(!gcomprisBoard->mode)
+ gameType=COMPUTER;
+ else if(g_strncasecmp(gcomprisBoard->mode, "computer", 1)==0)
+ gameType=COMPUTER;
+ else if(g_strncasecmp(gcomprisBoard->mode, "partyend", 1)==0)
+ gameType=PARTYEND;
+ else if(g_strncasecmp(gcomprisBoard->mode, "movelearn", 1)==0)
+ gameType=MOVELEARN;
+
+ gcomprisBoard->level=1;
+ gcomprisBoard->maxlevel=1;
+ gcomprisBoard->sublevel=1;
+ gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
+
+ switch(gameType)
+ {
+ case PARTYEND:
+ case MOVELEARN:
+ gcomprisBoard->maxlevel=9;
+ gc_bar_set(GC_BAR_LEVEL);
+ break;
+ default:
+ gc_bar_set(0);
+ }
+
+ if(start_child (GNUCHESS, &read_chan,
+ &write_chan, &gnuchess_pid)==FALSE) {
+ gc_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), gc_board_end);
+ return;
+ }
+
+ read_cb = g_io_add_watch (read_chan, G_IO_IN,
+ engine_local_cb, NULL);
+ err_cb = g_io_add_watch (read_chan, G_IO_HUP,
+ engine_local_err_cb, NULL);
+
+ write_child (write_chan, "xboard\n");
+ write_child (write_chan, "protover 2\n");
+ write_child (write_chan, "post\n");
+ write_child (write_chan, "easy\n");
+ write_child (write_chan, "level 100 1 0\n");
+ write_child (write_chan, "depth 1\n");
+
+ chess_next_level();
+
+ gamewon = FALSE;
+ pause_board(FALSE);
+ }
+}
+
+/* ======================================= */
+static void end_board ()
+{
+ if(gcomprisBoard!=NULL)
+ {
+ pause_board(TRUE);
+ chess_destroy_all_items();
+ }
+ gcomprisBoard = NULL;
+
+ turn_item = NULL;
+ info_item = NULL;
+
+
+ engine_local_destroy(gnuchess_pid);
+}
+
+/* ======================================= */
+static void set_level (guint level)
+{
+
+ if(gcomprisBoard!=NULL)
+ {
+ gcomprisBoard->level=level;
+ gcomprisBoard->sublevel=1;
+ chess_next_level();
+ }
+}
+/* ======================================= */
+static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
+{
+ if (gcomprisBoard)
+ {
+ if(g_strcasecmp(gcomprisBoard->type, "chess")==0)
+ {
+ /* Set the plugin entry */
+ gcomprisBoard->plugin=&menu_bp;
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*-------------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------------*/
+/* set initial values for the next level */
+static void chess_next_level()
+{
+ register Square square;
+ register gshort rank;
+
+ gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
+ gc_skin_image_get("gcompris-bg.jpg"));
+
+ gc_bar_set_level(gcomprisBoard);
+
+ chess_destroy_all_items();
+ gamewon = FALSE;
+
+ /* Initial position */
+ position = POSITION (position_new_initial ());
+
+ switch(gameType)
+ {
+ case PARTYEND:
+ position_set_initial_partyend(position, gcomprisBoard->level);
+ break;
+ case MOVELEARN:
+ position_set_initial_movelearn(position, gcomprisBoard->level);
+ break;
+ }
+ /* Init our internal chessboard */
+ for (rank = 1; rank <= 8; rank++) {
+ for (square = A1 + ((rank - 1) * 10);
+ square <= H1 + ((rank - 1) * 10);
+ square++) {
+
+ GSquare *gsquare;
+
+ gsquare = g_malloc(sizeof(GSquare));
+
+ chessboard[square] = gsquare;
+ chessboard[square]->piece_item = NULL;
+ chessboard[square]->square = square;
+
+ }
+ }
+
+ /* Try the next level */
+ chess_create_item(gnome_canvas_root(gcomprisBoard->canvas));
+}
+
+/* ==================================== */
+/* Destroy all the items */
+static void chess_destroy_all_items()
+{
+ register Square square;
+ register gshort rank;
+
+ if(boardRootItem!=NULL)
+ gtk_object_destroy (GTK_OBJECT(boardRootItem));
+
+ boardRootItem = NULL;
+ turn_item = NULL;
+ info_item = NULL;
+
+ if(position!=NULL)
+ gtk_object_destroy (GTK_OBJECT (position));
+
+ position = NULL;
+
+ for (rank = 1; rank <= 8; rank++) {
+ for (square = A1 + ((rank - 1) * 10);
+ square <= H1 + ((rank - 1) * 10);
+ square++) {
+
+ if(chessboard[square]!=NULL)
+ {
+ g_free(chessboard[square]);
+ chessboard[square]=NULL;
+ }
+ }
+ }
+}
+
+/* ==================================== */
+static GnomeCanvasItem *chess_create_item(GnomeCanvasGroup *parent)
+{
+ guint color;
+ GnomeCanvasItem *item = NULL;
+ Square square;
+ Piece piece;
+ gshort rank;
+ gboolean white_side = TRUE;
+ guint empty_case = 0;
+ gboolean need_slash = TRUE;
+
+ boardRootItem = GNOME_CANVAS_GROUP(
+ gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
+ gnome_canvas_group_get_type (),
+ "x", (double) 0,
+ "y", (double) 0,
+
+ NULL));
+
+ for (rank = 1; rank <= 8; rank++) {
+ for (square = A1 + ((rank - 1) * 10);
+ square <= H1 + ((rank - 1) * 10);
+ square++) {
+ int x,y;
+
+ x = square % 10 - 1;
+ y = square / 10 - 2;
+
+ color=((x+y)%2?BLACK_COLOR:WHITE_COLOR);
+
+ item = gnome_canvas_item_new (boardRootItem,
+ gnome_canvas_rect_get_type (),
+ "x1", (double) CHESSBOARD_X + (x * SQUARE_WIDTH),
+ "y1", (double) CHESSBOARD_Y + ((7-y) * SQUARE_HEIGHT),
+ "x2", (double) CHESSBOARD_X + (x * SQUARE_WIDTH) + SQUARE_WIDTH -1,
+ "y2", (double) CHESSBOARD_Y + ((7-y) * SQUARE_HEIGHT) + SQUARE_HEIGHT -1,
+ "fill_color_rgba", color,
+ "outline_color", "black",
+ "width_units", (double)2,
+ NULL);
+ chessboard[square]->square_item = item;
+ }
+ }
+
+ /* Enter the gnuchess edit mode */
+ write_child (write_chan, "force\n");
+ write_child (write_chan, "new\n");
+ write_child (write_chan, "setboard ");
+
+ empty_case = 0;
+ need_slash = FALSE;
+
+ /* Display the pieces */
+ for (rank = 8; rank >= 1; rank--) {
+ for (square = A1 + ((rank - 1) * 10);
+ square <= H1 + ((rank - 1) * 10);
+ square++)
+ {
+ GdkPixbuf *pixmap = NULL;
+ char *str;
+ gint x, y;
+ char *temp;
+ char *san;
+
+ piece = position->square[square];
+
+ x = square % 10 - 1;
+ y = square / 10 - 2;
+
+ /* Destination square */
+ san = g_new0 (char, 12);
+ temp = san;
+ square_to_ascii (&temp, square);
+ // printf ( "%c%s\n", piece_to_ascii(piece), san);
+
+ if(need_slash)
+ {
+ write_child (write_chan, "/");
+ need_slash = FALSE;
+ }
+
+ if(piece!=NONE)
+ {
+
+ if( (white_side && BPIECE(piece)) ||
+ (!white_side && WPIECE(piece)) )
+ {
+ white_side = !white_side;
+ // write_child (write_chan, "c\n");
+ }
+ if(empty_case>0)
+ write_child (write_chan, "%d", empty_case);
+
+ empty_case=0;
+
+ write_child (write_chan, "%c", piece_to_ascii(piece));
+ }
+ else
+ {
+ empty_case++;
+ }
+
+ if(x==7)
+ {
+ if(empty_case>0)
+ write_child (write_chan, "%d", empty_case);
+
+ empty_case=0;
+
+ need_slash = TRUE;
+ }
+
+ temp = san;
+ san = g_strdup (temp);
+ g_free (temp);
+
+ // printf("square=%d piece=%d x=%d y=%d\n", square, piece, x, y);
+ if(piece != EMPTY)
+ {
+ if(BPIECE(piece))
+ str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
+ else
+ str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
+
+ pixmap = gc_pixmap_load(str);
+ // g_warning("loading piece %s\n", str);
+ g_free(str);
+ item = gnome_canvas_item_new (boardRootItem,
+ gnome_canvas_pixbuf_get_type (),
+ "pixbuf", pixmap,
+ "x", (double)CHESSBOARD_X + (x * SQUARE_WIDTH) +
+ (guint)((SQUARE_WIDTH-gdk_pixbuf_get_width(pixmap))/2),
+ "y", (double) CHESSBOARD_Y + ((7-y) * SQUARE_HEIGHT) +
+ (guint)((SQUARE_HEIGHT-gdk_pixbuf_get_height(pixmap))/2),
+ NULL);
+
+ chessboard[square]->piece_item = item;
+ if(WPIECE(piece))
+ gtk_signal_connect(GTK_OBJECT(item), "event",
+ (GtkSignalFunc) item_event, NULL);
+ else
+ gtk_signal_connect(GTK_OBJECT(item), "event",
+ (GtkSignalFunc) item_event_black, NULL);
+
+ gdk_pixbuf_unref(pixmap);
+ }
+ }
+ }
+
+ /* Quit the gnuchess edit mode */
+ write_child (write_chan, " w KQkq\n");
+
+ display_white_turn(TRUE);
+
+ return NULL;
+}
+/* ==================================== */
+static void game_won()
+{
+ gcomprisBoard->sublevel++;
+
+ if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
+ /* Try the next level */
+ gcomprisBoard->sublevel=1;
+ gcomprisBoard->level++;
+ if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
+ gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
+ return;
+ }
+ gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
+ }
+ chess_next_level();
+}
+
+static void display_white_turn(gboolean whiteturn)
+{
+
+ if(turn_item == NULL)
+ {
+
+ turn_item = gnome_canvas_item_new (boardRootItem,
+ gnome_canvas_text_get_type (),
+ "text", " ",
+ "font", gc_skin_font_board_big,
+ "x", (double) TURN_X,
+ "y", (double) TURN_Y,
+ "anchor", GTK_ANCHOR_CENTER,
+ "fill_color_rgba", gc_skin_color_content,
+ NULL);
+ }
+
+ gnome_canvas_item_set(turn_item, "text", (whiteturn ? _("White's Turn") : _("Black's Turn")),
+ NULL);
+}
+
+
+static void display_info(gchar *info)
+{
+
+ if(info_item == NULL)
+ {
+ info_item = gnome_canvas_item_new (boardRootItem,
+ gnome_canvas_text_get_type (),
+ "text", " ",
+ "font", gc_skin_font_board_big,
+ "x", (double) INFO_X,
+ "y", (double) INFO_Y,
+ "anchor", GTK_ANCHOR_CENTER,
+ "fill_color_rgba", gc_skin_color_subtitle,
+ NULL);
+ }
+
+ gnome_canvas_item_set(info_item, "text", info,
+ NULL);
+}
+
+
+/*
+ * Move a piece to the given position using chess_notation notation
+ *
+ */
+static void move_piece_to(Square from, Square to)
+{
+ GSquare *source_square, *dest_square;
+ GnomeCanvasItem *item;
+ guint x, y;
+ double ofset_x, ofset_y;
+ double x1, y1, x2, y2;
+ Piece piece = NONE;
+
+
+ g_warning("move_piece_to from=%d to=%d\n", from, to);
+
+ source_square = chessboard[from];
+ item = source_square->piece_item;
+ source_square->piece_item = NULL;
+
+ if(item == NULL)
+ {
+ g_warning("Warning: Problem in chess.c, bad move request in move_piece_to\n");
+ return;
+ }
+
+ /* If we are promoting a pawn */
+ if(position_get_color_to_move(position)==BLACK)
+ {
+ if (to & 128) {
+ piece = ((to & 127) >> 3 ) + WP - 1;
+ to = (to & 7) + A8;
+ printf(" Promoting white piece to %d\n", piece);
+ }
+ }
+ else
+ {
+ if (to & 128) {
+ piece = ((to & 127) >> 3) + BP - 1;
+ to = (to & 7) + A1;
+ printf(" Promoting black piece to %d\n", piece);
+ }
+ }
+
+ /* Show the moved piece */
+ gnome_canvas_item_set(source_square->square_item,
+ "outline_color",
+ (BPIECE(position->square[to])?"red":"blue"),
+ NULL);
+
+ display_white_turn(BPIECE(position->square[to]));
+
+ x = to % 10;
+ y = to / 10 -1;
+
+ g_warning(" move_piece_to to x=%d y=%d\n", x, y);
+
+ dest_square = chessboard[to];
+
+ /* Show the moved piece */
+ gnome_canvas_item_set(dest_square->square_item,
+ "outline_color",
+ (BPIECE(position->square[to])?"red":"blue"),
+ NULL);
+
+ if(dest_square->piece_item != NULL)
+ /* Oups I loose a piece */
+ gtk_object_destroy (GTK_OBJECT(dest_square->piece_item));
+
+ dest_square->piece_item = item;
+
+ /* Find the ofset to move the piece */
+ gnome_canvas_item_get_bounds (item,
+ &x1,
+ &y1,
+ &x2,
+ &y2);
+
+
+ ofset_x = (CHESSBOARD_X + SQUARE_WIDTH * (x-1)) - x1 + (SQUARE_WIDTH - (x2-x1))/2;
+ ofset_y = (CHESSBOARD_Y + SQUARE_HEIGHT * (8-y)) - y1 + (SQUARE_HEIGHT - (y2-y1))/2;
+
+ gnome_canvas_item_move(item, ofset_x, ofset_y);
+
+ /* Manage rock */
+ if(position->square[to]==WK && from==E1 && to==C1)
+ move_piece_to(A1, D1);
+ else if(position->square[to]==WK && from==E1 && to==G1)
+ move_piece_to(H1, F1);
+ else if(position->square[to]==BK && from==E8 && to==C8)
+ move_piece_to(A8, D8);
+ else if(position->square[to]==BK && from==E8 && to==G8)
+ move_piece_to(H8, F8);
+
+ /* Manage promotion */
+ if(piece != NONE)
+ {
+ GdkPixbuf *pixmap = NULL;
+ char *str;
+ g_warning(" WARNING promoting a pawn from=%d to=%d piece=%d\n", from, to, piece);
+ g_warning(" piece_to_ascii returns %c\n", piece_to_ascii(piece));
+
+ if(BPIECE(piece))
+ str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
+ else
+ str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
+
+ pixmap = gc_pixmap_load(str);
+ g_free(str);
+ g_warning("loading piece %c\n", piece_to_ascii(piece));
+ gnome_canvas_item_set (dest_square->piece_item,
+ "pixbuf", pixmap,
+ NULL);
+
+ }
+
+ /* Display check info */
+ if(position_white_king_attack(position))
+ display_info(_("White checks"));
+ else if(position_black_king_attack(position))
+ display_info(_("Black checks"));
+ else
+ display_info(" ");
+
+}
+
+/*
+ * Return a square suitable for position functions
+ */
+static int
+get_square (double x, double y)
+{
+
+ return (A1 + (Square) (x-1)
+ + 10 * (Square)(y-1));
+
+}
+
+/*
+ * Return a square suitable for position functions
+ */
+static int
+get_square_from_coord (double x, double y)
+{
+
+ return (A1 + (Square) ((x - CHESSBOARD_X) / SQUARE_WIDTH)
+ + 10 * (7 - (Square)((y - CHESSBOARD_Y) / SQUARE_HEIGHT)));
+
+}
+
+void hightlight_possible_moves(GSquare *gsquare)
+{
+ Square square_test;
+ guint color;
+ register Square square;
+ register gshort rank;
+ short current_color;
+
+ if(currentHighlightedGsquare == gsquare)
+ return;
+
+ /* Remember the current color to move */
+ current_color = position_get_color_to_move(position);
+
+ if(WPIECE(position->square[gsquare->square]))
+ position_set_color_to_move(position, WHITE);
+ else
+ position_set_color_to_move(position, BLACK);
+
+ for (rank = 1; rank <= 8; rank++) {
+ for (square = A1 + ((rank - 1) * 10);
+ square <= H1 + ((rank - 1) * 10);
+ square++) {
+
+
+ square_test = position_move_normalize (position, gsquare->square, chessboard[square]->square);
+
+ if (square_test)
+ {
+ color=((rank+square)%2?BLACK_COLOR_H:WHITE_COLOR_H);
+
+ gnome_canvas_item_set(chessboard[square]->square_item,
+ "fill_color_rgba", color,
+ "outline_color", "black",
+ NULL);
+ }
+ else
+ {
+ color=((rank+square)%2?BLACK_COLOR:WHITE_COLOR);
+
+ gnome_canvas_item_set(chessboard[square]->square_item,
+ "fill_color_rgba", color,
+ "outline_color", "black",
+ NULL);
+ }
+ }
+ }
+
+ /* Set back the current color to move */
+ position_set_color_to_move(position, current_color);
+
+ /* Show the current piece */
+ gnome_canvas_item_set(gsquare->square_item,
+ "outline_color",
+ (BPIECE(position->square[gsquare->square])?"red":"blue"),
+ NULL);
+
+}
+
+/* ==================================== */
+static gint
+item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
+{
+ static double x, y;
+ static GSquare *gsquare;
+ double new_x, new_y;
+ GdkCursor *fleur;
+ static int dragging;
+ double item_x, item_y;
+
+ if(board_paused)
+ return FALSE;
+
+ item_x = event->button.x;
+ item_y = event->button.y;
+ gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ {
+ guint x1, y1;
+ Square square;
+
+ square = get_square_from_coord(event->button.x, event->button.y);
+ x1 = square % 10;
+ y1 = square / 10 -1;
+ gsquare = chessboard[square];
+
+ x = item_x;
+ y = item_y;
+
+ fleur = gdk_cursor_new(GDK_FLEUR);
+ gnome_canvas_item_raise_to_top(item);
+ gnome_canvas_item_grab(item,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK,
+ fleur,
+ event->button.time);
+ gdk_cursor_destroy(fleur);
+ dragging = TRUE;
+
+ hightlight_possible_moves(gsquare);
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
+ {
+ new_x = item_x;
+ new_y = item_y;
+
+ gnome_canvas_item_move(item, new_x - x, new_y - y);
+ x = new_x;
+ y = new_y;
+ }
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ if(dragging)
+ {
+ guint x, y;
+ double ofset_x, ofset_y;
+ double x1, y1, x2, y2;
+ char pos[6];
+ Square to;
+
+ to = get_square_from_coord(event->button.x, event->button.y);
+ g_warning("===== Source square = %d Destination square = %d\n", gsquare->square,
+ to);
+
+ to = position_move_normalize (position, gsquare->square, to);
+ if (to) {
+ position_move (position, gsquare->square, to);
+
+ x = 1 + (event->button.x - CHESSBOARD_X) / SQUARE_WIDTH;
+ y = 1 + (event->button.y - CHESSBOARD_Y) / SQUARE_HEIGHT;
+ move_to_ascii((char *)&pos, gsquare->square, to);
+
+ /* Tell gnuchess what our move is */
+ write_child (write_chan, (char *)&pos);
+ write_child (write_chan, "\n");
+ move_piece_to(gsquare->square, to);
+ }
+ else
+ {
+ g_warning("====== MOVE from %d REFUSED\n", gsquare->square);
+
+ /* Find the ofset to move the piece back to where it was*/
+ gnome_canvas_item_get_bounds (item,
+ &x1,
+ &y1,
+ &x2,
+ &y2);
+
+ x = gsquare->square % 10;
+ y = gsquare->square / 10 -1;
+
+ ofset_x = (CHESSBOARD_X + SQUARE_WIDTH * (x-1)) - x1 + (SQUARE_WIDTH - (x2-x1))/2;
+ ofset_y = (CHESSBOARD_Y + SQUARE_HEIGHT * (8-y)) - y1 + (SQUARE_HEIGHT - (y2-y1))/2;
+ g_warning("ofset = x=%f y=%f\n", ofset_x, ofset_y);
+
+ gnome_canvas_item_move(item, ofset_x, ofset_y);
+ }
+
+ gnome_canvas_item_ungrab(item, event->button.time);
+ dragging = FALSE;
+
+ position_display(position);
+
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/* ==================================== */
+/* The user clicked on a black piece */
+static gint
+item_event_black(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
+{
+ static GSquare *gsquare;
+
+ if(board_paused)
+ return FALSE;
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ {
+ Square square;
+
+ square = get_square_from_coord(event->button.x, event->button.y);
+ gsquare = chessboard[square];
+
+ hightlight_possible_moves(gsquare);
+ }
+ break;
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+/*======================================================================*/
+/*======================================================================*/
+/*======================================================================*/
+/*======================================================================*/
+static void
+engine_local_destroy (GPid gnuchess_pid)
+{
+
+ g_warning("engine_local_destroy () \n");
+ write_child (write_chan, "quit\n");
+
+ g_source_remove(read_cb);
+ g_source_remove(err_cb);
+
+ g_io_channel_close (read_chan);
+ g_io_channel_unref (read_chan);
+
+ g_io_channel_close (write_chan);
+ g_io_channel_unref (write_chan);
+
+ if(gnuchess_pid)
+ g_spawn_close_pid(gnuchess_pid);
+}
+
+static gboolean
+engine_local_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ static char buf[1024];
+ static char *b=buf;
+
+ char *p,*q;
+ ssize_t len;
+
+ g_io_channel_read (read_chan, b, sizeof (buf) - 1 - (b - buf), &len);
+
+ if (len > 0) {
+ b[len] = 0;
+ b += len;
+ }
+
+ while (1) {
+ char tmp;
+
+ q = strchr (buf,'\n');
+ if (q == NULL) break;
+ tmp = *(q+1);
+ *(q+1) = '\0';
+
+ *q='\0';
+ *(q+1) = tmp;
+
+ g_warning("engine_local_cb read=%s\n", buf);
+
+ /* parse for NUMBER ... MOVE */
+ if (isdigit (*buf))
+ {
+ if ((p = strstr (buf, "...")))
+ {
+ Square from, to;
+
+ g_warning("computer number moves to %s\n", p+4);
+
+ if (san_to_move (position, p+4, &from, &to))
+ ascii_to_move (position, p+4, &from, &to);
+
+ position_move (position, from, to);
+ move_piece_to(from , to);
+ }
+ else if ((p = strstr (buf, " ")))
+ {
+ /* It's a legal move case */
+ g_warning("Legal move to %s\n", p+1);
+ }
+ }
+
+ /* parse for move MOVE */
+ if (!strncmp ("My move is : ",buf,13))
+ {
+ Square from, to;
+
+ p = strstr (buf, ":");
+ printf("computer moves to %s\n", p+1);
+
+ if (san_to_move (position, p+1, &from, &to))
+ ascii_to_move (position, p+1, &from, &to);
+
+ position_move (position, from, to);
+ move_piece_to(from , to);
+ }
+
+ /* parse for illegal move */
+ if (!strncmp ("Illegal move",buf,12))
+ {
+ g_warning("Illegal move to %s : SHOULD NOT HAPPEN", buf+31);
+ }
+
+ if (!strncmp ("0-1",buf,3))
+ {
+ display_info(_("Black mates"));
+ }
+
+ if (!strncmp ("1-0",buf,3))
+ {
+ display_info(_("White mates"));
+ }
+
+ if (!strncmp ("1/2-1/2",buf,7))
+ {
+ display_info(_("Drawn game"));
+ }
+
+ /* parse for feature */
+ if (!strncmp ("feature",buf,7))
+ {
+ write_child(write_chan, "accepted setboard\n");
+ write_child(write_chan, "accepted analyze\n");
+ write_child(write_chan, "accepted ping\n");
+ write_child(write_chan, "accepted draw\n");
+ write_child(write_chan, "accepted variants\n");
+ write_child(write_chan, "accepted myname\n");
+ write_child(write_chan, "accepted done\n");
+ }
+
+ memmove (buf, q+1, sizeof(buf) - ( q + 1 - buf));
+ b -= (q + 1 - buf);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+engine_local_err_cb (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ g_error ("Local Engine connection died");
+
+ return FALSE;
+}
+
+/*----------------------------------------
+ * Subprocess creation
+ * Return TRUE if gnuchess is started, false instead
+ *----------------------------------------*/
+
+static gboolean
+start_child (char *cmd,
+ GIOChannel **read_chan,
+ GIOChannel **write_chan,
+ GPid *Child_Process)
+{
+ gint Child_In, Child_Out, Child_Err;
+ GError *gerror = NULL;
+
+ gchar *Child_Argv[]={ cmd, NULL };
+
+ g_warning("Ready to start child");
+
+ if (!g_spawn_async_with_pipes(NULL, Child_Argv, NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL, NULL, Child_Process, &Child_In, &Child_Out,
+ &Child_Err, &gerror)) {
+
+ g_warning("Error message '%s'", gerror->message);
+ g_warning("Error code '%d'", gerror->code);
+ g_error_free (gerror);
+ g_warning("In order to play chess, you need to have gnuchess installed as " GNUCHESS);
+ return(FALSE);
+
+ }
+
+ g_warning("gnuchess subprocess is started");
+
+ *read_chan = g_io_channel_unix_new (Child_Out);
+ *write_chan = g_io_channel_unix_new (Child_In);
+
+ return(TRUE);
+}
+
+
+static void
+write_child (GIOChannel *write_chan, char *format, ...)
+{
+ GIOError err;
+ va_list ap;
+ char *buf;
+ int len;
+
+ va_start (ap, format);
+
+ buf = g_strdup_vprintf (format, ap);
+
+ err = g_io_channel_write (write_chan, buf, strlen (buf), &len);
+ if (err != G_IO_ERROR_NONE)
+ g_warning ("Writing to child process failed");
+
+ g_warning ("%s", buf);
+
+ va_end (ap);
+
+ g_free (buf);
+}
+
+
+