~ubuntu-branches/ubuntu/trusty/gcompris/trusty

« back to all changes in this revision

Viewing changes to src/boards/chess.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2006-12-15 23:08:17 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20061215230817-exr5ks1hd73s3tlk
Tags: 8.2.2-1
* New upstream bugfix release, fixes among other things the support for
  the version of gnucap shipped in etch.
* Add missing dependency on python-gtk2 (Closes: #396523).
* Removed reference to non-existent sound file from memory.c (upstream
  fix - impacts 8.2 as well).  
* Now suggests gnuchess, gnucap, and tuxpaint.
* Updated extended description for the main package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 */
19
19
 
20
 
#include <ctype.h>
21
 
#include <math.h>
22
 
#include <assert.h>
23
 
 
24
20
#include <stdarg.h>
25
21
#include <stdio.h>
26
22
#include <stdlib.h>
28
24
#include <unistd.h>
29
25
#include <signal.h>
30
26
 
31
 
#include "sys/wait.h"
32
 
 
33
27
#include "chess_notation.h"
34
28
 
35
29
#include "gcompris/gcompris.h"
36
30
 
 
31
#if defined _WIN32 || defined __WIN32__
 
32
# undef WIN32   /* avoid warning on mingw32 */
 
33
# define WIN32
 
34
#endif
37
35
 
38
36
#define SOUNDLISTFILE PACKAGE
39
37
 
40
38
static GcomprisBoard *gcomprisBoard = NULL;
41
39
static gboolean board_paused = TRUE;
42
40
 
 
41
static GPid      gnuchess_pid;
43
42
static void      start_board (GcomprisBoard *agcomprisBoard);
44
43
static void      pause_board (gboolean pause);
45
44
static void      end_board (void);
48
47
static int       gamewon;
49
48
static void      game_won(void);
50
49
 
51
 
static void      engine_local_destroy ();
 
50
static void      engine_local_destroy (GPid gnuchess_pid);
52
51
 
53
52
static gboolean  engine_local_cb     (GIOChannel *source,
54
53
                                      GIOCondition condition,
58
57
                                      gpointer data);
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);
63
61
 
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
72
70
 
73
71
#define TURN_X          (BOARDWIDTH-(BOARDWIDTH-(CHESSBOARD_X+(SQUARE_WIDTH*8)))/2)
74
72
#define TURN_Y          (CHESSBOARD_Y+15)
88
86
static GIOChannel *read_chan;
89
87
static GIOChannel *write_chan;
90
88
 
91
 
static pid_t childpid;
92
 
 
93
89
static gint read_cb;
94
90
static gint err_cb;
95
91
 
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,
121
 
                                      char       **arg,
 
116
static gboolean          start_child (char        *cmd,
122
117
                                      GIOChannel **read_chan,
123
118
                                      GIOChannel **write_chan,
124
 
                                      pid_t       *childpid);
 
119
                                      GPid       *gnuchess_pid);
125
120
 
126
121
static void              write_child (GIOChannel  *write_chan,
127
122
                                      char        *format,
128
123
                                      ...);
129
124
 
130
 
static int               stop_child  (pid_t        childpid);
131
125
 
132
126
/* Description of this plugin */
133
127
static BoardPlugin menu_bp =
134
128
  {
135
129
    NULL,
136
130
    NULL,
137
 
    N_("Learning Chess"),
138
 
    N_("Play chess against tux in a learning mode"),
 
131
    "Learning Chess",
 
132
    "Play chess against tux in a learning mode",
139
133
    "Bruno Coudoin <bruno.coudoin@free.fr>",
140
134
    NULL,
141
135
    NULL,
149
143
    NULL,
150
144
    set_level,
151
145
    NULL,
 
146
    NULL,
 
147
    NULL,
152
148
    NULL
153
149
  };
154
150
 
158
154
 *
159
155
 */
160
156
 
161
 
BoardPlugin
162
 
*get_bplugin_info(void)
163
 
{
164
 
  return &menu_bp;
165
 
}
 
157
GET_BPLUGIN_INFO(chess)
166
158
 
167
159
/*
168
160
 * in : boolean TRUE = PAUSE : FALSE = CONTINUE
181
173
  board_paused = pause;
182
174
}
183
175
 
 
176
void gnuchess_died(int signum)
 
177
{
 
178
  gnuchess_pid = 0;
 
179
  gc_dialog(_("Error: The external program gnuchess died unexpectedly"), gc_board_stop);
 
180
}
 
181
 
184
182
/*
185
183
 */
186
184
static void start_board (GcomprisBoard *agcomprisBoard)
187
185
{
188
 
  
189
 
  if (g_file_test ("/usr/bin/gnuchessx", G_FILE_TEST_EXISTS)) {
190
 
    
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);
192
 
    
193
 
    return;
194
 
  }
195
 
  
196
 
  if (!g_file_test (GNUCHESS, G_FILE_TEST_EXISTS)) {
197
 
    
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);
199
 
    
200
 
    return;
201
 
  }
202
 
  
 
186
 
 
187
  gnuchess_pid = 0;
 
188
 
 
189
#ifndef WIN32
 
190
  signal(SIGTRAP, gnuchess_died);
 
191
  signal(SIGPIPE, gnuchess_died);
 
192
  if (!g_file_test (GNUCHESS, G_FILE_TEST_EXISTS))
 
193
    {
 
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),
 
197
              gc_board_stop);
 
198
    return;
 
199
  }
 
200
#endif
 
201
 
203
202
  if(agcomprisBoard!=NULL)
204
203
    {
205
 
      char *param[2];
206
 
 
207
 
      param[0] = "xboard";
208
 
      param[1] = NULL;
209
204
 
210
205
      gcomprisBoard=agcomprisBoard;
211
 
      
 
206
 
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;
221
 
      
 
216
 
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' */
226
 
      
 
221
 
227
222
      switch(gameType)
228
223
        {
229
224
        case PARTYEND:
230
225
        case MOVELEARN:
231
226
          gcomprisBoard->maxlevel=9;
232
 
          gcompris_bar_set(GCOMPRIS_BAR_LEVEL);
 
227
          gc_bar_set(GC_BAR_LEVEL);
233
228
          break;
234
229
        default:
235
 
          gcompris_bar_set(0);
236
 
        }
237
 
      
238
 
      start_child (GNUCHESS, param, &read_chan,
239
 
                   &write_chan, &childpid);
240
 
      
241
 
      read_cb = g_io_add_watch (read_chan, G_IO_IN,
 
230
          gc_bar_set(0);
 
231
        }
 
232
 
 
233
      if(start_child (GNUCHESS, &read_chan,
 
234
                      &write_chan, &gnuchess_pid)==FALSE)
 
235
        {
 
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);
 
239
          return;
 
240
        }
 
241
 
 
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);
245
 
      
 
246
 
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");
252
 
      
 
253
      write_child (write_chan, "time 500\n");
 
254
 
253
255
      chess_next_level();
254
 
      
 
256
 
255
257
      gamewon = FALSE;
256
258
      pause_board(FALSE);
 
259
 
257
260
    }
258
261
}
259
262
 
260
263
/* ======================================= */
261
264
static void end_board ()
262
265
{
 
266
#ifndef WIN32
 
267
  signal(SIGTRAP, NULL);
 
268
  signal(SIGPIPE, NULL);
 
269
#endif
263
270
  if(gcomprisBoard!=NULL)
264
271
    {
265
272
      pause_board(TRUE);
271
278
  info_item     = NULL;
272
279
 
273
280
 
274
 
  engine_local_destroy();
 
281
  engine_local_destroy(gnuchess_pid);
275
282
}
276
283
 
277
284
/* ======================================= */
307
314
static void chess_next_level()
308
315
{
309
316
  register Square square;
310
 
  register Piece piece;
311
317
  register gshort rank;
312
 
 
313
 
  gcompris_set_background(gnome_canvas_root(gcomprisBoard->canvas), 
314
 
                          gcompris_image_to_skin("gcompris-bg.jpg"));
315
 
 
316
 
  gcompris_bar_set_level(gcomprisBoard);
 
318
  gchar *img;
 
319
 
 
320
  img = gc_skin_image_get("gcompris-bg.jpg");
 
321
  gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
 
322
                          img);
 
323
  g_free(img);
 
324
 
 
325
  gc_bar_set_level(gcomprisBoard);
317
326
 
318
327
  chess_destroy_all_items();
319
328
  gamewon = FALSE;
331
340
      break;
332
341
    }
333
342
  /* Init our internal chessboard */
334
 
  for (rank = 1; rank <= 8; rank++) { 
335
 
    for (square = A1 + ((rank - 1) * 10); 
 
343
  for (rank = 1; rank <= 8; rank++) {
 
344
    for (square = A1 + ((rank - 1) * 10);
336
345
         square <= H1 + ((rank - 1) * 10);
337
346
         square++) {
338
347
 
343
352
        chessboard[square] = gsquare;
344
353
        chessboard[square]->piece_item = NULL;
345
354
        chessboard[square]->square = square;
346
 
        
 
355
 
347
356
    }
348
 
  }    
349
 
   
 
357
  }
 
358
 
350
359
  /* Try the next level */
351
360
  chess_create_item(gnome_canvas_root(gcomprisBoard->canvas));
352
361
}
356
365
static void chess_destroy_all_items()
357
366
{
358
367
  register Square square;
359
 
  register Piece piece;
360
368
  register gshort rank;
361
369
 
362
370
  if(boardRootItem!=NULL)
371
379
 
372
380
  position = NULL;
373
381
 
374
 
  for (rank = 1; rank <= 8; rank++) { 
375
 
    for (square = A1 + ((rank - 1) * 10); 
 
382
  for (rank = 1; rank <= 8; rank++) {
 
383
    for (square = A1 + ((rank - 1) * 10);
376
384
         square <= H1 + ((rank - 1) * 10);
377
385
         square++) {
378
 
      
 
386
 
379
387
      if(chessboard[square]!=NULL)
380
388
        {
381
389
          g_free(chessboard[square]);
386
394
}
387
395
 
388
396
/* ==================================== */
389
 
static GnomeCanvasItem *chess_create_item(GnomeCanvasGroup *parent)
 
397
static GnomeCanvasItem *
 
398
chess_create_item(GnomeCanvasGroup *parent)
390
399
{
391
400
  guint color;
392
401
  GnomeCanvasItem *item = NULL;
405
414
 
406
415
                                                            NULL));
407
416
 
408
 
  for (rank = 1; rank <= 8; rank++) { 
409
 
    for (square = A1 + ((rank - 1) * 10); 
 
417
  for (rank = 1; rank <= 8; rank++) {
 
418
    for (square = A1 + ((rank - 1) * 10);
410
419
         square <= H1 + ((rank - 1) * 10);
411
420
         square++) {
412
421
      int x,y;
413
 
      
 
422
 
414
423
      x = square % 10 - 1;
415
424
      y = square / 10 - 2;
416
425
 
417
426
      color=((x+y)%2?BLACK_COLOR:WHITE_COLOR);
418
 
      
 
427
 
419
428
      item  = gnome_canvas_item_new (boardRootItem,
420
429
                                     gnome_canvas_rect_get_type (),
421
430
                                     "x1", (double) CHESSBOARD_X + (x * SQUARE_WIDTH),
424
433
                                     "y2", (double)  CHESSBOARD_Y + ((7-y) * SQUARE_HEIGHT) + SQUARE_HEIGHT -1,
425
434
                                     "fill_color_rgba", color,
426
435
                                     "outline_color", "black",
427
 
                                     "width_units", (double)1,
 
436
                                     "width_units", (double)2,
428
437
                                     NULL);
429
438
      chessboard[square]->square_item = item;
430
439
    }
439
448
  need_slash = FALSE;
440
449
 
441
450
  /* Display the pieces */
442
 
  for (rank = 8; rank >= 1; rank--) { 
443
 
    for (square = A1 + ((rank - 1) * 10); 
 
451
  for (rank = 8; rank >= 1; rank--) {
 
452
    for (square = A1 + ((rank - 1) * 10);
444
453
         square <= H1 + ((rank - 1) * 10);
445
 
         square++) 
 
454
         square++)
446
455
      {
447
456
        GdkPixbuf *pixmap = NULL;
448
457
        char *str;
449
458
        gint x, y;
450
 
        char *temp;
451
 
        char *san;
452
459
 
453
460
        piece = position->square[square];
454
461
 
455
462
        x = square % 10 - 1;
456
463
        y = square / 10 - 2;
457
464
 
458
 
        /* Destination square */
459
 
        san = g_new0 (char, 12);
460
 
        temp = san;
461
 
        square_to_ascii (&temp, square);
462
465
        //      printf ( "%c%s\n", piece_to_ascii(piece), san);
463
466
 
464
467
        if(need_slash)
470
473
        if(piece!=NONE)
471
474
          {
472
475
 
473
 
            if(white_side && BPIECE(piece) ||
474
 
               !white_side && WPIECE(piece)) 
 
476
            if( (white_side && BPIECE(piece)) ||
 
477
                (!white_side && WPIECE(piece)) )
475
478
              {
476
479
                white_side = !white_side;
477
480
                //              write_child (write_chan, "c\n");
498
501
            need_slash = TRUE;
499
502
          }
500
503
 
501
 
        temp = san;
502
 
        san = g_strdup (temp);
503
 
        g_free (temp);
504
 
 
505
504
        //      printf("square=%d piece=%d x=%d y=%d\n", square, piece, x, y);
506
505
        if(piece != EMPTY)
507
506
          {
508
 
            str = g_strdup_printf("chess/%c.png", piece_to_ascii(piece));
509
 
            
510
 
            pixmap = gcompris_load_pixmap(str);
 
507
            if(BPIECE(piece))
 
508
              str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
 
509
            else
 
510
              str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
 
511
 
 
512
            pixmap = gc_pixmap_load(str);
511
513
            //      g_warning("loading piece %s\n",   str);
512
514
            g_free(str);
513
515
            item = gnome_canvas_item_new (boardRootItem,
514
516
                                          gnome_canvas_pixbuf_get_type (),
515
 
                                          "pixbuf", pixmap, 
 
517
                                          "pixbuf", pixmap,
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),
520
522
                                          NULL);
521
 
            
 
523
 
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);
526
528
            else
527
 
              gtk_signal_connect(GTK_OBJECT(item), "event", 
 
529
              gtk_signal_connect(GTK_OBJECT(item), "event",
528
530
                                 (GtkSignalFunc) item_event_black, NULL);
529
531
 
530
532
            gdk_pixbuf_unref(pixmap);
549
551
    gcomprisBoard->sublevel=1;
550
552
    gcomprisBoard->level++;
551
553
    if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
552
 
      board_finished(BOARD_FINISHED_RANDOM);
 
554
      gc_bonus_end_display(BOARD_FINISHED_RANDOM);
553
555
      return;
554
556
    }
555
 
    gcompris_play_ogg ("bonus", NULL);
 
557
    gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
556
558
  }
557
559
  chess_next_level();
558
560
}
566
568
      turn_item = gnome_canvas_item_new (boardRootItem,
567
569
                                         gnome_canvas_text_get_type (),
568
570
                                         "text",       " ",
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,
574
576
                                         NULL);
575
577
    }
576
578
 
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")),
578
580
                        NULL);
579
581
}
580
582
 
587
589
      info_item = gnome_canvas_item_new (boardRootItem,
588
590
                                         gnome_canvas_text_get_type (),
589
591
                                         "text",       " ",
590
 
                                         "font",       gcompris_skin_font_board_big,
 
592
                                         "font",       gc_skin_font_board_big,
591
593
                                         "x", (double) INFO_X,
592
594
                                         "y", (double) INFO_Y,
593
595
                                         "anchor",     GTK_ANCHOR_CENTER,
594
 
                                         "fill_color_rgba", gcompris_skin_color_subtitle,
 
596
                                         "fill_color_rgba", gc_skin_color_subtitle,
595
597
                                         NULL);
596
598
    }
597
599
 
612
614
  double ofset_x, ofset_y;
613
615
  double x1, y1, x2, y2;
614
616
  Piece piece = NONE;
615
 
      
 
617
 
616
618
 
617
619
  g_warning("move_piece_to from=%d to=%d\n", from, to);
618
620
 
631
633
    {
632
634
      if (to & 128) {
633
635
        piece = ((to & 127) >> 3 ) + WP - 1;
634
 
        to = (to & 7) + A8;            
 
636
        to = (to & 7) + A8;
635
637
        printf("  Promoting white piece to %d\n", piece);
636
638
      }
637
639
    }
647
649
  /* Show the moved piece */
648
650
  gnome_canvas_item_set(source_square->square_item,
649
651
                        "outline_color",
650
 
                        (BPIECE(position->square[to])?"red":"green"),
 
652
                        (BPIECE(position->square[to])?"red":"blue"),
651
653
                        NULL);
652
654
 
653
655
  display_white_turn(BPIECE(position->square[to]));
654
656
 
655
657
  x = to % 10;
656
658
  y = to / 10 -1;
657
 
  
 
659
 
658
660
  g_warning("   move_piece_to to    x=%d y=%d\n", x, y);
659
661
 
660
662
  dest_square = chessboard[to];
661
663
 
662
664
  /* Show the moved piece */
663
665
  gnome_canvas_item_set(dest_square->square_item,
664
 
                        "outline_color", 
665
 
                        (BPIECE(position->square[to])?"red":"green"),
 
666
                        "outline_color",
 
667
                        (BPIECE(position->square[to])?"red":"blue"),
666
668
                        NULL);
667
669
 
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));
704
706
 
705
 
      str = g_strdup_printf("chess/%c.png", piece_to_ascii(piece));
706
 
              
707
 
      pixmap = gcompris_load_pixmap(str);
 
707
      if(BPIECE(piece))
 
708
        str = g_strdup_printf("chess/B%c.png", piece_to_ascii(piece));
 
709
      else
 
710
        str = g_strdup_printf("chess/W%c.png", piece_to_ascii(piece));
 
711
 
 
712
      pixmap = gc_pixmap_load(str);
708
713
      g_free(str);
709
714
      g_warning("loading piece %c\n",  piece_to_ascii(piece));
710
715
      gnome_canvas_item_set (dest_square->piece_item,
711
 
                             "pixbuf", pixmap, 
 
716
                             "pixbuf", pixmap,
712
717
                             NULL);
713
718
 
714
719
    }
715
720
 
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"));
721
726
  else
722
727
    display_info(" ");
723
728
 
727
732
 * Return a square suitable for position functions
728
733
 */
729
734
static int
730
 
get_square (double x, double y)
731
 
{
732
 
 
733
 
  return (A1 + (Square) (x-1)
734
 
          + 10 * (Square)(y-1));
735
 
 
736
 
}
737
 
 
738
 
/*
739
 
 * Return a square suitable for position functions
740
 
 */
741
 
static int
742
735
get_square_from_coord (double x, double y)
743
736
{
744
737
 
752
745
  Square square_test;
753
746
  guint color;
754
747
  register Square square;
755
 
  register Piece piece;
756
748
  register gshort rank;
757
749
  short    current_color;
758
750
 
767
759
  else
768
760
    position_set_color_to_move(position, BLACK);
769
761
 
770
 
  for (rank = 1; rank <= 8; rank++) { 
771
 
    for (square = A1 + ((rank - 1) * 10); 
 
762
  for (rank = 1; rank <= 8; rank++) {
 
763
    for (square = A1 + ((rank - 1) * 10);
772
764
         square <= H1 + ((rank - 1) * 10);
773
765
         square++) {
774
766
 
775
767
 
776
768
        square_test = position_move_normalize (position, gsquare->square, chessboard[square]->square);
777
769
 
778
 
        if (square_test) 
 
770
        if (square_test)
779
771
          {
780
772
            color=((rank+square)%2?BLACK_COLOR_H:WHITE_COLOR_H);
781
773
 
793
785
                                  "outline_color", "black",
794
786
                                  NULL);
795
787
          }
796
 
      }      
 
788
      }
797
789
  }
798
790
 
799
791
  /* Set back the current color to move */
802
794
  /* Show the current piece */
803
795
  gnome_canvas_item_set(gsquare->square_item,
804
796
                        "outline_color",
805
 
                        (BPIECE(position->square[gsquare->square])?"red":"green"),
 
797
                        (BPIECE(position->square[gsquare->square])?"red":"blue"),
806
798
                        NULL);
807
 
  
 
799
 
808
800
}
809
801
 
810
802
/* ==================================== */
839
831
 
840
832
        x = item_x;
841
833
        y = item_y;
842
 
        
 
834
 
843
835
        fleur = gdk_cursor_new(GDK_FLEUR);
844
836
        gnome_canvas_item_raise_to_top(item);
845
 
        gnome_canvas_item_grab(item,
846
 
                               GDK_POINTER_MOTION_MASK | 
 
837
        gc_canvas_item_grab(item,
 
838
                               GDK_POINTER_MOTION_MASK |
847
839
                               GDK_BUTTON_RELEASE_MASK,
848
840
                               fleur,
849
841
                               event->button.time);
854
846
      }
855
847
      break;
856
848
    case GDK_MOTION_NOTIFY:
857
 
       if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) 
 
849
       if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
858
850
         {
859
851
           new_x = item_x;
860
852
           new_y = item_y;
864
856
           y = new_y;
865
857
         }
866
858
       break;
867
 
           
 
859
 
868
860
     case GDK_BUTTON_RELEASE:
869
 
       if(dragging) 
 
861
       if(dragging)
870
862
         {
871
863
           guint x, y;
872
864
           double ofset_x, ofset_y;
875
867
           Square to;
876
868
 
877
869
           to = get_square_from_coord(event->button.x, event->button.y);
878
 
           g_warning("===== Source square = %d Destination square = %d\n", gsquare->square, 
 
870
           g_warning("===== Source square = %d Destination square = %d\n", gsquare->square,
879
871
                  to);
880
872
 
881
873
           to = position_move_normalize (position, gsquare->square, to);
894
886
           else
895
887
             {
896
888
               g_warning("====== MOVE from %d REFUSED\n", gsquare->square);
897
 
           
 
889
 
898
890
               /* Find the ofset to move the piece back to where it was*/
899
891
               gnome_canvas_item_get_bounds  (item,
900
892
                                              &x1,
901
893
                                              &y1,
902
894
                                              &x2,
903
895
                                              &y2);
904
 
               
 
896
 
905
897
               x = gsquare->square % 10;
906
898
               y = gsquare->square / 10 -1;
907
 
               
 
899
 
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);
911
 
               
 
903
 
912
904
               gnome_canvas_item_move(item, ofset_x, ofset_y);
913
905
             }
914
906
 
915
 
           gnome_canvas_item_ungrab(item, event->button.time);
 
907
           gc_canvas_item_ungrab(item, event->button.time);
916
908
           dragging = FALSE;
917
909
 
918
910
           position_display(position);
949
941
        hightlight_possible_moves(gsquare);
950
942
      }
951
943
      break;
 
944
    default:
 
945
      break;
952
946
    }
 
947
  return(FALSE);
953
948
}
954
949
 
955
950
/*======================================================================*/
957
952
/*======================================================================*/
958
953
/*======================================================================*/
959
954
static void
960
 
engine_local_destroy () 
 
955
engine_local_destroy (GPid gnuchess_pid)
961
956
{
962
957
 
 
958
  if(!gnuchess_pid)
 
959
    return;
 
960
 
963
961
  g_warning("engine_local_destroy () \n");
964
 
  //  write_child (write_chan, "quit\n");
 
962
  write_child (write_chan, "quit\n");
965
963
 
966
964
  g_source_remove(read_cb);
967
965
  g_source_remove(err_cb);
968
966
 
969
967
  g_io_channel_close (read_chan);
970
968
  g_io_channel_unref (read_chan);
971
 
  
 
969
 
972
970
  g_io_channel_close (write_chan);
973
971
  g_io_channel_unref (write_chan);
974
 
  
975
 
  stop_child (childpid);  
 
972
 
 
973
  if(gnuchess_pid)
 
974
    g_spawn_close_pid(gnuchess_pid);
976
975
}
977
976
 
 
977
/** We got data back from gnuchess, we parse them here
 
978
 *
 
979
 */
978
980
static gboolean
979
981
engine_local_cb (GIOChannel *source,
980
982
                 GIOCondition condition,
981
983
                 gpointer data)
982
984
{
983
 
  static char buf[1024];
984
 
  static char *b=buf;
985
 
  
 
985
  gchar buf[1000];
 
986
  char *b=buf;
 
987
  GError *err = NULL;
986
988
  char *p,*q;
987
 
  ssize_t len;
988
 
  
989
 
  g_io_channel_read (read_chan, b, sizeof (buf) - 1 - (b - buf), &len);
990
 
  
 
989
  gsize len = 0;
 
990
  GIOStatus status = G_IO_STATUS_NORMAL;
 
991
 
 
992
  g_warning("engine_local_cb");
 
993
 
 
994
  status = g_io_channel_read_chars(source,
 
995
                                   buf,
 
996
                                   1000,
 
997
                                   &len,
 
998
                                   &err);
 
999
 
 
1000
  g_warning("g_io_channel_read_line len=%d", (int)len);
 
1001
  if(status == G_IO_STATUS_ERROR)
 
1002
    {
 
1003
      g_warning("g_io_channel_read_chars error=%s",
 
1004
                err->message);
 
1005
      /* FIXME: Not sure what to do */
 
1006
      return FALSE;
 
1007
    }
 
1008
 
 
1009
  if(status != G_IO_STATUS_NORMAL)
 
1010
    {
 
1011
      g_warning("g_io_channel_read_chars error=%d",
 
1012
                status);
 
1013
      /* FIXME: Not sure what to do */
 
1014
      return FALSE;
 
1015
    }
 
1016
 
 
1017
  g_warning("engine_local_cb read=%s\n", buf);
 
1018
 
991
1019
  if (len > 0) {
992
1020
    b[len] = 0;
993
1021
    b += len;
994
1022
  }
995
 
  
 
1023
 
996
1024
  while (1) {
997
1025
    char tmp;
998
 
    
 
1026
 
999
1027
    q = strchr (buf,'\n');
1000
1028
    if (q == NULL) break;
1001
1029
    tmp = *(q+1);
1002
 
    *(q+1) = 0;
1003
 
    
1004
 
    *q=0;
 
1030
    *(q+1) = '\0';
 
1031
 
 
1032
    *q='\0';
1005
1033
    *(q+1) = tmp;
1006
 
    
1007
 
    g_warning("engine_local_cb read=%s\n", &buf);
1008
 
    
 
1034
 
 
1035
    g_warning("engine_local_cb read=%s\n", buf);
 
1036
 
1009
1037
    /* parse for  NUMBER ... MOVE */
1010
1038
    if (isdigit (*buf))
1011
 
      if ((p = strstr (buf, "...")))
1012
 
        {
1013
 
          Square from, to;
1014
 
          
1015
 
          g_warning("computer number moves to %s\n", p+4);
1016
 
          
1017
 
          if (san_to_move (position, p+4, &from, &to))
1018
 
            ascii_to_move (position, p+4, &from, &to);
1019
 
          
1020
 
          position_move (position, from, to);
1021
 
          move_piece_to(from , to);
1022
 
        }
1023
 
      else if ((p = strstr (buf, " ")))
1024
 
        {
1025
 
          /* It's a legal move case */
1026
 
          g_warning("Legal move to %s\n", p+1);
1027
 
        }
1028
 
    
 
1039
      {
 
1040
        if ((p = strstr (buf, "...")))
 
1041
          {
 
1042
            Square from, to;
 
1043
 
 
1044
            g_warning("computer number moves to %s\n", p+4);
 
1045
 
 
1046
            if (san_to_move (position, p+4, &from, &to))
 
1047
              ascii_to_move (position, p+4, &from, &to);
 
1048
 
 
1049
            position_move (position, from, to);
 
1050
            move_piece_to(from , to);
 
1051
          }
 
1052
        else if ((p = strstr (buf, " ")))
 
1053
          {
 
1054
            /* It's a legal move case */
 
1055
            g_warning("Legal move to %s\n", p+1);
 
1056
          }
 
1057
      }
 
1058
 
1029
1059
    /* parse for move MOVE */
1030
1060
    if (!strncmp ("My move is : ",buf,13))
1031
1061
      {
1032
1062
        Square from, to;
1033
1063
 
1034
1064
        p = strstr (buf, ":");
1035
 
        printf("computer moves to %s\n", p+1);
 
1065
        g_warning("computer moves to %s\n", p+1);
1036
1066
 
1037
1067
        if (san_to_move (position, p+1, &from, &to))
1038
1068
          ascii_to_move (position, p+1, &from, &to);
1040
1070
        position_move (position, from, to);
1041
1071
        move_piece_to(from , to);
1042
1072
      }
1043
 
    
 
1073
 
1044
1074
    /* parse for illegal move */
1045
1075
    if (!strncmp ("Illegal move",buf,12))
1046
1076
      {
1077
1107
    memmove (buf, q+1, sizeof(buf) - ( q + 1 - buf));
1078
1108
    b -= (q + 1 - buf);
1079
1109
  }
1080
 
  
 
1110
 
1081
1111
  return TRUE;
1082
1112
}
1083
1113
 
1086
1116
                     GIOCondition condition,
1087
1117
                     gpointer data)
1088
1118
{
1089
 
  g_error ("Local Engine connection died");
1090
 
  
 
1119
  gnuchess_pid = 0;
 
1120
  gc_dialog(_("Error: The external program gnuchess died unexpectingly"), gc_board_stop);
1091
1121
  return FALSE;
1092
1122
}
1093
1123
 
1094
 
/*
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.
1099
 
 */
1100
 
 
1101
 
/* =====================================================================
1102
 
 * Process the cleanup of the child (no zombies)
1103
 
 * =====================================================================*/
1104
 
void chess_child_end(int  signum)
1105
 
{
1106
 
  pid_t pid;
1107
 
 
1108
 
  g_warning("chess child_end signal=%d\n", signum);
1109
 
 
1110
 
  pid = waitpid(childpid, NULL, WNOHANG);
1111
 
  g_warning("chess child_end pid=%d\n", pid);
1112
 
 
1113
 
  if (pid == -1)
1114
 
    g_error("chess_child_end Error waitpid");
1115
 
 
1116
 
}
1117
 
 
1118
1124
/*----------------------------------------
1119
1125
 * Subprocess creation
 
1126
 * Return TRUE if gnuchess is started, false instead
1120
1127
 *----------------------------------------*/
1121
1128
 
1122
 
static int 
1123
 
start_child (char *cmd, 
1124
 
             char **arg, 
1125
 
             GIOChannel **read_chan, 
1126
 
             GIOChannel **write_chan, 
1127
 
             pid_t *childpid)
 
1129
static gboolean
 
1130
start_child (char *cmd,
 
1131
             GIOChannel **read_chan,
 
1132
             GIOChannel **write_chan,
 
1133
             GPid *Child_Process)
1128
1134
{
1129
 
  int pipe1[2], pipe2[2];
1130
 
 
1131
 
  if ((pipe (pipe1) <0) || (pipe (pipe2) < 0)) {
1132
 
    perror ("pipe");
1133
 
    exit (-1);
1134
 
  }
1135
 
 
1136
 
  signal(SIGCHLD, chess_child_end);
1137
 
 
1138
 
  if ((*childpid = fork ()) < 0) {
1139
 
    perror ("fork");
1140
 
    exit (-1);
1141
 
  } else if (*childpid > 0) /* Parent */ {
1142
 
    close (pipe1[0]);
1143
 
    close (pipe2[1]);
1144
 
 
1145
 
    *read_chan = g_io_channel_unix_new (pipe2[0]);
1146
 
    *write_chan = g_io_channel_unix_new (pipe1[1]);
1147
 
 
1148
 
    return *childpid;
1149
 
  } else   /* Child */ {
1150
 
    close (pipe1[1]);
1151
 
    close (pipe2[0]);
1152
 
 
1153
 
    dup2 (pipe1[0],0);
1154
 
    dup2 (pipe2[1],1);
1155
 
 
1156
 
    close (pipe1[0]);
1157
 
    close (pipe2[1]);
1158
 
 
1159
 
    if (execvp (cmd, arg) < 0)
1160
 
      {
1161
 
        g_warning("In order to play chess, you need to have gnuchess installed as " GNUCHESS);
1162
 
        perror (cmd);
1163
 
      }
1164
 
    _exit (1);
1165
 
  }
1166
 
 
1167
 
  g_assert_not_reached ();
1168
 
 
1169
 
  return 0;
 
1135
  gint   Child_In, Child_Out, Child_Err;
 
1136
  GError *gerror = NULL;
 
1137
 
 
1138
  gchar *Child_Argv[]={ cmd, "-e", NULL };
 
1139
 
 
1140
  g_warning("Ready to start child");
 
1141
 
 
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)) {
 
1146
 
 
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);
 
1151
    return(FALSE);
 
1152
 
 
1153
  }
 
1154
 
 
1155
  g_warning("gnuchess subprocess is started");
 
1156
 
 
1157
  *read_chan = g_io_channel_unix_new (Child_Out);
 
1158
  *write_chan = g_io_channel_unix_new (Child_In);
 
1159
 
 
1160
  if(g_io_channel_set_encoding(*write_chan, NULL, NULL) != G_IO_STATUS_NORMAL)
 
1161
    g_warning("Failed to set NULL encoding");
 
1162
 
 
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");
 
1165
 
 
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");
 
1168
 
 
1169
  return(TRUE);
1170
1170
}
1171
1171
 
1172
 
static void 
1173
 
write_child (GIOChannel *write_chan, char *format, ...) 
 
1172
/** Write a command to the gnuchess backend
 
1173
 *
 
1174
 */
 
1175
static void
 
1176
write_child (GIOChannel *write_chan, char *format, ...)
1174
1177
{
1175
 
  GIOError err;
 
1178
  GIOStatus err;
1176
1179
  va_list ap;
1177
 
  char *buf;
1178
 
  int len;      
 
1180
  gchar *buf;
 
1181
  gsize len;
 
1182
  GError *error = NULL;
1179
1183
 
1180
1184
  va_start (ap, format);
1181
1185
 
1182
1186
  buf = g_strdup_vprintf (format, ap);
1183
1187
 
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);
 
1189
 
 
1190
  if (err == G_IO_STATUS_ERROR)
 
1191
    g_error ("Error writing: %s\n", error->message);
 
1192
 
 
1193
  if (err != G_IO_STATUS_NORMAL)
1186
1194
    g_warning ("Writing to child process failed");
 
1195
  else
 
1196
    g_warning ("Wrote '%s' to gnuchess", buf);
1187
1197
 
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);
1189
1201
 
1190
1202
  va_end (ap);
1191
1203
 
1192
1204
  g_free (buf);
1193
1205
}
1194
 
 
1195
 
/* Kill Child */
1196
 
static int 
1197
 
stop_child (pid_t childpid) 
1198
 
{
1199
 
 
1200
 
  g_warning("stop_child (childpid=%d) () \n", childpid);
1201
 
 
1202
 
  if (childpid && kill (childpid, SIGTERM) ) { 
1203
 
    g_message ("Failed to kill child!\n");
1204
 
    return 1;
1205
 
  }
1206
 
 
1207
 
  return 0;
1208
 
}