Correct the preprocessor condition introduced in r20112, also include FS#9958 by...
[kugel-rb.git] / apps / plugins / chessbox / chessbox.c
blobc1e6092f3a299cf4517e5e502d3a5e92a77129f5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Miguel A. Arévalo
11 * Color graphics from eboard
12 * GNUChess v2 chess engine Copyright (c) 1988 John Stanback
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 #include "plugin.h"
26 #ifdef HAVE_LCD_BITMAP
28 #if (MEMORYSIZE > 8) /* Lowmem doesn't have playback in chessbox */
29 #define HAVE_PLAYBACK_CONTROL
30 #endif
33 #ifdef HAVE_PLAYBACK_CONTROL
34 #include "lib/playback_control.h"
35 #endif
37 #include "gnuchess.h"
38 #include "opening.h"
39 #include "chessbox_pgn.h"
41 /* type definitions */
42 struct cb_command {
43 int type;
44 char mv_s[5];
45 unsigned short mv;
48 /* External bitmaps */
49 extern const fb_data chessbox_pieces[];
52 PLUGIN_HEADER
54 /* Tile size defined by the assigned bitmap */
55 #include "pluginbitmaps/chessbox_pieces.h"
56 #define TILE_WIDTH BMPWIDTH_chessbox_pieces
57 #define TILE_HEIGHT (BMPHEIGHT_chessbox_pieces/26)
59 /* Calculate Offsets */
60 #define XOFS ((LCD_WIDTH-8*TILE_WIDTH)/2)
61 #define YOFS ((LCD_HEIGHT-8*TILE_HEIGHT)/2)
63 /* save files */
64 #define SAVE_FILE PLUGIN_GAMES_DIR "/chessbox.save"
66 /* commands enum */
67 #define COMMAND_NOP 0
68 #define COMMAND_MOVE 1
69 #define COMMAND_PLAY 2
70 #define COMMAND_LEVEL 3
71 #define COMMAND_RESTART 4
72 #define COMMAND_QUIT 5
73 #define COMMAND_MENU 6
74 #define COMMAND_SAVE 7
75 #define COMMAND_RESTORE 8
76 #define COMMAND_RESUME 9
77 #define COMMAND_SELECT 10
78 #define COMMAND_NEXT 11
79 #define COMMAND_PREV 12
81 short plugin_mode;
83 /* level+1's string */
84 const char *level_string[] = { "Level 1: 60 moves / 5 min" ,
85 "Level 2: 60 moves / 15 min" ,
86 "Level 3: 60 moves / 30 min" ,
87 "Level 4: 40 moves / 30 min" ,
88 "Level 5: 40 moves / 60 min" ,
89 "Level 6: 40 moves / 120 min" ,
90 "Level 7: 40 moves / 240 min" ,
91 "Level 8: 1 move / 15 min" ,
92 "Level 9: 1 move / 60 min" ,
93 "Level 10: 1 move / 600 min" };
95 /* "While thinking" command */
96 int wt_command = COMMAND_NOP;
98 /* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */
99 void xy2cr ( short x, short y, short *c, short *r ) {
100 if (computer == black ) {
101 *c = x ;
102 *r = y ;
103 } else {
104 *c = 7 - x ;
105 *r = 7 - y ;
109 /* ---- get physical x y for a board column and row (e2 f.e.) ---- */
110 void cr2xy ( short c, short r, short *x, short *y ) {
111 if ( computer == black ) {
112 *x = c ;
113 *y = r ;
114 } else {
115 *x = 7 - c ;
116 *y = 7 - r ;
120 /* ---- Draw a complete board ---- */
121 static void cb_drawboard (void) {
122 short r , c , x , y ;
123 short l , piece , p_color ;
124 int b_color=1;
126 rb->lcd_clear_display();
128 for (r = 0; r < 8; r++) {
129 for (c = 0; c < 8; c++) {
130 l = locn[r][c];
131 piece = board[l] ;
132 p_color = color[l] ;
133 cr2xy ( c , r , &x , &y );
134 if ( piece == no_piece ) {
135 rb->lcd_bitmap_part ( chessbox_pieces , 0 ,
136 TILE_HEIGHT * b_color ,
137 TILE_WIDTH ,
138 XOFS + x*TILE_WIDTH ,
139 YOFS + ( 7 - y )*TILE_HEIGHT ,
140 TILE_WIDTH ,
141 TILE_HEIGHT );
142 } else {
143 rb->lcd_bitmap_part ( chessbox_pieces ,
145 2 * TILE_HEIGHT +
146 4 * TILE_HEIGHT * ( piece - 1 ) +
147 2 * TILE_HEIGHT * p_color +
148 TILE_HEIGHT * b_color ,
149 TILE_WIDTH ,
150 XOFS + x*TILE_WIDTH ,
151 YOFS + (7 - y)*TILE_HEIGHT ,
152 TILE_WIDTH ,
153 TILE_HEIGHT );
155 b_color = (b_color == 1) ? 0 : 1 ;
157 b_color = (b_color == 1) ? 0 : 1 ;
160 /* draw board limits */
161 #if (LCD_WIDTH > TILE_WIDTH*8) && (LCD_HEIGHT > TILE_HEIGHT*8)
162 rb->lcd_drawrect(XOFS - 1, YOFS - 1, TILE_WIDTH*8 + 2, TILE_HEIGHT*8 + 2);
163 #elif LCD_WIDTH > TILE_WIDTH*8
164 rb->lcd_vline(XOFS - 1, 0, LCD_HEIGHT - 1);
165 rb->lcd_vline(XOFS + 8*TILE_WIDTH, 0, LCD_HEIGHT - 1);
166 #elif LCD_HEIGHT > TILE_HEIGHT*8
167 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS - 1);
168 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS + TILE_HEIGHT*8);
169 #endif
171 rb->lcd_update();
174 /* ---- Switch mark on board ---- */
175 void cb_switch ( short x , short y ) {
176 rb->lcd_set_drawmode ( DRMODE_COMPLEMENT );
177 rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 ,
178 YOFS + ( 7 - y )*TILE_HEIGHT +1 ,
179 TILE_WIDTH-2 , TILE_HEIGHT-2 );
180 rb->lcd_update();
181 rb->lcd_set_drawmode ( DRMODE_SOLID );
184 /* ---- callback for capturing interaction while thinking ---- */
185 void cb_wt_callback ( void ) {
186 int button = BUTTON_NONE;
188 wt_command = COMMAND_NOP;
189 button = rb->button_get(false);
190 switch (button) {
191 #ifdef CB_RC_QUIT
192 case CB_RC_QUIT:
193 wt_command = COMMAND_QUIT;
194 timeout = true;
195 break;
196 #endif
197 case CB_MENU:
198 wt_command = COMMAND_MENU;
199 timeout = true;
200 break;
201 case CB_PLAY:
202 wt_command = COMMAND_PLAY;
203 timeout = true;
204 break;
208 /* ---- set playing parameters depending on level ---- */
209 void cb_setlevel ( int lev ) {
210 Level = (lev > 7) ? 7 : ( (lev < 1) ? 1 : lev ) ;
211 switch (Level) {
212 case 1 :
213 TCmoves = 60;
214 TCminutes = 5;
215 break;
216 case 2 :
217 TCmoves = 60;
218 TCminutes = 15;
219 break;
220 case 3 :
221 TCmoves = 60;
222 TCminutes = 30;
223 break;
224 case 4 :
225 TCmoves = 40;
226 TCminutes = 30;
227 break;
228 case 5 :
229 TCmoves = 40;
230 TCminutes = 60;
231 break;
232 case 6 :
233 TCmoves = 40;
234 TCminutes = 120;
235 break;
236 case 7 :
237 TCmoves = 40;
238 TCminutes = 240;
239 break;
240 case 8 :
241 TCmoves = 1;
242 TCminutes = 15;
243 break;
244 case 9 :
245 TCmoves = 1;
246 TCminutes = 60;
247 break;
248 case 10 :
249 TCmoves = 1;
250 TCminutes = 600;
251 break;
253 TCflag = (TCmoves > 1);
254 SetTimeControl();
257 /* ---- increase playing level ---- */
258 void cb_levelup ( void ) {
259 if ( Level == 7 )
260 cb_setlevel ( 1 );
261 else
262 cb_setlevel ( Level+1 );
263 rb->splash ( HZ/2 , level_string[Level-1] );
266 /* ---- Save current position ---- */
267 void cb_saveposition ( void ) {
268 int fd;
269 short sq,i,c;
270 unsigned short temp;
272 rb->splash ( 0 , "Saving position" );
274 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
276 computer++; rb->write(fd, &(computer), sizeof(computer)); computer--;
277 opponent++; rb->write(fd, &(opponent), sizeof(opponent)); opponent--;
278 rb->write(fd, &(Game50), sizeof(Game50));
280 rb->write(fd, &(castld[white]), sizeof(castld[white]));
281 rb->write(fd, &(castld[black]), sizeof(castld[black]));
282 rb->write(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
283 rb->write(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
285 rb->write(fd, &(withbook), sizeof(withbook));
286 rb->write(fd, &(Level), sizeof(Level));
287 rb->write(fd, &(TCflag), sizeof(TCflag));
288 rb->write(fd, &(OperatorTime), sizeof(OperatorTime));
290 rb->write(fd, &(TimeControl.clock[white]),
291 sizeof(TimeControl.clock[white]) );
292 rb->write(fd, &(TimeControl.clock[black]),
293 sizeof(TimeControl.clock[black]) );
294 rb->write(fd, &(TimeControl.moves[white]),
295 sizeof(TimeControl.moves[white]) );
296 rb->write(fd, &(TimeControl.moves[black]),
297 sizeof(TimeControl.moves[black]) );
298 for (sq = 0; sq < 64; sq++) {
299 if (color[sq] == neutral) c = 0; else c = color[sq]+1;
300 temp = 256*board[sq] + c ;
301 rb->write(fd, &(temp), sizeof(temp));
303 for (i = 0; i <= GameCnt; i++) {
304 if (GameList[i].color == neutral)
305 c = 0;
306 else
307 c = GameList[i].color + 1;
308 rb->write(fd, &(GameList[i].gmove), sizeof(GameList[i].gmove));
309 rb->write(fd, &(GameList[i].score), sizeof(GameList[i].score));
310 rb->write(fd, &(GameList[i].depth), sizeof(GameList[i].depth));
311 rb->write(fd, &(GameList[i].nodes), sizeof(GameList[i].nodes));
312 rb->write(fd, &(GameList[i].time), sizeof(GameList[i].time));
313 rb->write(fd, &(GameList[i].piece), sizeof(GameList[i].piece));
314 rb->write(fd, &(c), sizeof(c));
316 rb->close(fd);
319 /* ---- Restore saved position ---- */
320 void cb_restoreposition ( void ) {
321 int fd;
322 int c;
323 short sq;
324 unsigned short m;
326 if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) {
327 rb->splash ( 0 , "Loading position" );
328 rb->read(fd, &(computer), sizeof(computer));
329 rb->read(fd, &(opponent), sizeof(opponent));
330 rb->read(fd, &(Game50), sizeof(Game50));
332 rb->read(fd, &(castld[white]), sizeof(castld[white]));
333 rb->read(fd, &(castld[black]), sizeof(castld[black]));
334 rb->read(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
335 rb->read(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
337 rb->read(fd, &(withbook), sizeof(withbook));
338 rb->read(fd, &(Level), sizeof(Level));
339 rb->read(fd, &(TCflag), sizeof(TCflag));
340 rb->read(fd, &(OperatorTime), sizeof(OperatorTime));
342 rb->read(fd, &(TimeControl.clock[white]),
343 sizeof(TimeControl.clock[white]));
344 rb->read(fd, &(TimeControl.clock[black]),
345 sizeof(TimeControl.clock[black]));
346 rb->read(fd, &(TimeControl.moves[white]),
347 sizeof(TimeControl.moves[white]));
348 rb->read(fd, &(TimeControl.moves[black]),
349 sizeof(TimeControl.moves[black]));
350 for (sq = 0; sq < 64; sq++) {
351 rb->read(fd, &(m), sizeof(m));
352 board[sq] = (m >> 8); color[sq] = (m & 0xFF);
353 if (color[sq] == 0)
354 color[sq] = neutral;
355 else
356 --color[sq];
358 GameCnt = -1; c = '?';
359 while (rb->read(fd, &(GameList[++GameCnt].gmove),
360 sizeof(GameList[GameCnt].gmove)) > 0) {
361 rb->read(fd, &(GameList[GameCnt].score),
362 sizeof(GameList[GameCnt].score));
363 rb->read(fd, &(GameList[GameCnt].depth),
364 sizeof(GameList[GameCnt].depth));
365 rb->read(fd, &(GameList[GameCnt].nodes),
366 sizeof(GameList[GameCnt].nodes));
367 rb->read(fd, &(GameList[GameCnt].time),
368 sizeof(GameList[GameCnt].time));
369 rb->read(fd, &(GameList[GameCnt].piece),
370 sizeof(GameList[GameCnt].piece));
371 rb->read(fd, &(GameList[GameCnt].color),
372 sizeof(GameList[GameCnt].color));
373 if (GameList[GameCnt].color == 0)
374 GameList[GameCnt].color = neutral;
375 else
376 --GameList[GameCnt].color;
378 GameCnt--;
379 if (TimeControl.clock[white] > 0)
380 TCflag = true;
381 computer--; opponent--;
383 rb->close(fd);
384 cb_setlevel(Level);
385 InitializeStats();
386 Sdepth = 0;
389 /* ---- show menu in viewer mode---- */
390 static int cb_menu_viewer(void)
392 int selection;
393 int result = 0;
394 bool menu_quit = false;
396 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"Restart Game",
397 "Select Other Game", "Quit");
399 while(!menu_quit)
401 switch(rb->do_menu(&menu, &selection, NULL, false))
403 case 0:
404 menu_quit = true;
405 result = COMMAND_RESTART;
406 break;
407 case 1:
408 result = COMMAND_SELECT;
409 menu_quit = true;
410 break;
411 case 2:
412 result = COMMAND_QUIT;
413 menu_quit = true;
414 break;
417 return result;
420 /* ---- get a command in game mode ---- */
421 struct cb_command cb_get_viewer_command (void) {
422 int button;
423 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
425 /* main loop */
426 while ( true ) {
427 button = rb->button_get(true);
428 switch (button) {
429 #ifdef CB_RC_QUIT
430 case CB_RC_QUIT:
431 result.type = COMMAND_QUIT;
432 return result;
433 #endif
434 case CB_MENU:
435 result.type = cb_menu_viewer();
436 return result;
437 case CB_LEFT:
438 result.type = COMMAND_PREV;
439 return result;
440 case CB_RIGHT:
441 result.type = COMMAND_NEXT;
442 return result;
448 /* ---- viewer main loop ---- */
449 void cb_start_viewer(char* filename){
450 struct pgn_game_node *first_game, *selected_game;
451 struct pgn_ply_node *curr_ply;
452 bool exit_game = false;
453 bool exit_viewer = false;
454 struct cb_command command;
456 first_game = pgn_list_games(filename);
457 if (first_game == NULL){
458 rb->splash ( HZ*2 , "No games found !" );
459 return;
462 do {
463 selected_game = pgn_show_game_list(first_game);
464 if (selected_game == NULL){
465 break;
468 pgn_parse_game(filename, selected_game);
469 if (selected_game->first_ply != NULL) {
471 /* init board */
472 GNUChess_Initialize();
474 /* draw the board */
475 cb_drawboard();
477 curr_ply = selected_game->first_ply;
478 exit_game = false;
480 do {
481 command = cb_get_viewer_command ();
482 switch (command.type) {
483 case COMMAND_PREV:
484 /* unapply the previous ply */
485 if (curr_ply->prev_node != NULL){
486 curr_ply = curr_ply->prev_node;
487 } else {
488 rb->splash ( HZ*2 , "At the begining of the game" );
489 break;
491 board[locn[curr_ply->row_from][curr_ply->column_from]]
492 = board[locn[curr_ply->row_to][curr_ply->column_to]];
493 color[locn[curr_ply->row_from][curr_ply->column_from]]
494 = color[locn[curr_ply->row_to][curr_ply->column_to]];
495 board[locn[curr_ply->row_to][curr_ply->column_to]] = no_piece;
496 color[locn[curr_ply->row_to][curr_ply->column_to]] = neutral;
497 if (curr_ply->taken_piece != no_piece && !curr_ply->enpassant){
498 board[locn[curr_ply->row_to][curr_ply->column_to]]
499 = curr_ply->taken_piece;
500 color[locn[curr_ply->row_to][curr_ply->column_to]]
501 = ((curr_ply->player==white)?black:white);
503 if (curr_ply->castle){
504 if (curr_ply->column_to == 6){
505 /* castling kingside */
506 board[locn[curr_ply->row_to][7]] = rook;
507 color[locn[curr_ply->row_to][7]] = curr_ply->player;
508 board[locn[curr_ply->row_to][5]] = no_piece;
509 color[locn[curr_ply->row_to][5]] = neutral;
510 } else {
511 /* castling queenside */
512 board[locn[curr_ply->row_to][0]] = rook;
513 color[locn[curr_ply->row_to][0]] = curr_ply->player;
514 board[locn[curr_ply->row_to][3]] = no_piece;
515 color[locn[curr_ply->row_to][3]] = neutral;
518 if (curr_ply->enpassant){
519 board[locn[curr_ply->row_from][curr_ply->column_to]] = pawn;
520 color[locn[curr_ply->row_from][curr_ply->column_to]]
521 = ((curr_ply->player==white)?black:white);
523 if (curr_ply->promotion){
524 board[locn[curr_ply->row_from][curr_ply->column_from]] = pawn;
525 color[locn[curr_ply->row_from][curr_ply->column_from]]
526 = curr_ply->player;
529 cb_drawboard();
530 break;
531 case COMMAND_NEXT:
532 /* apply the current move */
533 if (curr_ply->player == neutral){
534 rb->splash ( HZ*2 , "At the end of the game" );
535 break;
537 board[locn[curr_ply->row_to][curr_ply->column_to]]
538 = board[locn[curr_ply->row_from][curr_ply->column_from]];
539 color[locn[curr_ply->row_to][curr_ply->column_to]]
540 = color[locn[curr_ply->row_from][curr_ply->column_from]];
541 board[locn[curr_ply->row_from][curr_ply->column_from]] = no_piece;
542 color[locn[curr_ply->row_from][curr_ply->column_from]] = neutral;
543 if (curr_ply->castle){
544 if (curr_ply->column_to == 6){
545 /* castling kingside */
546 board[locn[curr_ply->row_to][5]] = rook;
547 color[locn[curr_ply->row_to][5]] = curr_ply->player;
548 board[locn[curr_ply->row_to][7]] = no_piece;
549 color[locn[curr_ply->row_to][7]] = neutral;
550 } else {
551 /* castling queenside */
552 board[locn[curr_ply->row_to][3]] = rook;
553 color[locn[curr_ply->row_to][3]] = curr_ply->player;
554 board[locn[curr_ply->row_to][0]] = no_piece;
555 color[locn[curr_ply->row_to][0]] = neutral;
558 if (curr_ply->enpassant){
559 board[locn[curr_ply->row_from][curr_ply->column_to]] = no_piece;
560 color[locn[curr_ply->row_from][curr_ply->column_to]] = neutral;
562 if (curr_ply->promotion){
563 board[locn[curr_ply->row_to][curr_ply->column_to]]
564 = curr_ply->promotion_piece;
565 color[locn[curr_ply->row_to][curr_ply->column_to]]
566 = curr_ply->player;
568 if (curr_ply->next_node != NULL){
569 curr_ply = curr_ply->next_node;
571 cb_drawboard();
572 break;
573 case COMMAND_RESTART:
574 GNUChess_Initialize();
575 cb_drawboard();
576 curr_ply = selected_game->first_ply;
577 case COMMAND_SELECT:
578 exit_game = true;
579 break;
580 case COMMAND_QUIT:
581 exit_viewer = true;
582 break;
584 } while (!exit_game && !exit_viewer);
585 } else {
586 rb->splash ( HZ*2 , "Error parsing game !");
588 } while (!exit_viewer);
591 /* ---- show menu ---- */
592 static int cb_menu(void)
594 int selection;
595 int result = 0;
596 bool menu_quit = false;
598 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"New Game","Resume Game",
599 "Save Game", "Restore Game",
600 #ifdef HAVE_PLAYBACK_CONTROL
601 "Playback Control",
602 #endif
603 "Quit");
605 while(!menu_quit)
607 switch(rb->do_menu(&menu, &selection, NULL, false))
609 case 0:
610 menu_quit = true;
611 result = COMMAND_RESTART;
612 break;
613 case 1:
614 result = COMMAND_RESUME;
615 menu_quit = true;
616 break;
617 case 2:
618 result = COMMAND_SAVE;
619 menu_quit = true;
620 break;
621 case 3:
622 result = COMMAND_RESTORE;
623 menu_quit = true;
624 break;
625 case 4:
626 #ifdef HAVE_PLAYBACK_CONTROL
627 playback_control(NULL);
628 break;
629 case 5:
630 #endif
631 result = COMMAND_QUIT;
632 menu_quit = true;
633 break;
636 return result;
639 /* ---- get a command in game mode ---- */
640 struct cb_command cb_getcommand (void) {
641 static short x = 4 , y = 3 ;
642 short c , r , l;
643 int button, lastbutton = BUTTON_NONE;
644 int marked = false , from_marked = false ;
645 short marked_x = 0 , marked_y = 0 ;
646 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
648 cb_switch ( x , y );
649 /* main loop */
650 while ( true ) {
651 button = rb->button_get(true);
652 switch (button) {
653 #ifdef CB_RC_QUIT
654 case CB_RC_QUIT:
655 result.type = COMMAND_QUIT;
656 return result;
657 #endif
658 case CB_MENU:
659 result.type = cb_menu();
660 return result;
661 case CB_LEVEL:
662 result.type = COMMAND_LEVEL;
663 return result;
664 case CB_PLAY:
665 #ifdef CB_PLAY_PRE
666 if (lastbutton != CB_PLAY_PRE)
667 break;
668 #endif
669 result.type = COMMAND_PLAY;
670 return result;
671 case CB_UP:
672 if ( !from_marked ) cb_switch ( x , y );
673 y++;
674 if ( y == 8 ) {
675 y = 0;
676 x--;
677 if ( x < 0 ) x = 7;
679 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
680 from_marked = true ;
681 } else {
682 from_marked = false ;
683 cb_switch ( x , y );
685 break;
686 case CB_DOWN:
687 if ( !from_marked ) cb_switch ( x , y );
688 y--;
689 if ( y < 0 ) {
690 y = 7;
691 x++;
692 if ( x == 8 ) x = 0;
694 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
695 from_marked = true ;
696 } else {
697 from_marked = false ;
698 cb_switch ( x , y );
700 break;
701 case CB_LEFT:
702 if ( !from_marked ) cb_switch ( x , y );
703 x--;
704 if ( x < 0 ) {
705 x = 7;
706 y++;
707 if ( y == 8 ) y = 0;
709 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
710 from_marked = true ;
711 } else {
712 from_marked = false ;
713 cb_switch ( x , y );
715 break;
716 case CB_RIGHT:
717 if ( !from_marked ) cb_switch ( x , y );
718 x++;
719 if ( x == 8 ) {
720 x = 0;
721 y--;
722 if ( y < 0 ) y = 7;
724 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
725 from_marked = true ;
726 } else {
727 from_marked = false ;
728 cb_switch ( x , y );
730 break;
731 case CB_SELECT:
732 #ifdef CB_SELECT_PRE
733 if (lastbutton != CB_SELECT_PRE)
734 break;
735 #endif
736 if ( !marked ) {
737 xy2cr ( x , y , &c , &r );
738 l = locn[r][c];
739 if ( ( color[l]!=computer ) && ( board[l]!=no_piece ) ) {
740 marked = true;
741 from_marked = true ;
742 marked_x = x;
743 marked_y = y;
745 } else {
746 if ( ( marked_x == x ) && ( marked_y == y ) ) {
747 marked = false;
748 from_marked = false;
749 } else {
750 xy2cr ( marked_x , marked_y , &c , &r );
751 result.mv_s[0] = 'a' + c;
752 result.mv_s[1] = '1' + r;
753 xy2cr ( x , y , &c , &r );
754 result.mv_s[2] = 'a' + c;
755 result.mv_s[3] = '1' + r;
756 result.mv_s[4] = '\00';
757 result.type = COMMAND_MOVE;
758 return result;
761 break;
763 if (button != BUTTON_NONE)
764 lastbutton = button;
769 /* ---- game main loop ---- */
770 void cb_play_game(void) {
771 struct cb_command command;
772 struct pgn_game_node *game;
773 char move_buffer[20];
775 /* init status */
776 bool exit = false;
778 /* load opening book, soon */
780 /* init board */
781 GNUChess_Initialize();
783 /* init PGN history data structures */
784 game = pgn_init_game();
786 /* restore saved position, if saved */
787 cb_restoreposition();
788 /* TODO: save/restore the PGN history of unfinished games */
790 /* draw the board */
791 /* I don't like configscreens, start game inmediatly */
792 cb_drawboard();
794 while (!exit) {
795 if ( mate ) {
796 rb->splash ( HZ*3 , "Checkmate!" );
797 rb->button_get(true);
798 pgn_store_game(game);
799 GNUChess_Initialize();
800 game = pgn_init_game();
801 cb_drawboard();
803 command = cb_getcommand ();
804 switch (command.type) {
805 case COMMAND_MOVE:
806 if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) {
807 rb->splash ( HZ/2 , "Illegal move!" );
808 cb_drawboard();
809 } else {
810 cb_drawboard();
812 /* Add the ply to the PGN history (in algebraic notation) */
813 pgn_append_ply(game, opponent, move_buffer, mate);
815 rb->splash ( 0 , "Thinking..." );
816 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
817 rb->cpu_boost ( true );
818 #endif
819 SelectMove ( computer , 0 , cb_wt_callback, move_buffer);
820 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
821 rb->cpu_boost ( false );
822 #endif
823 /* Add the ply to the PGN history (in algebraic notation) and check
824 * for the result of the game which is only calculated in SelectMove
826 if (move_buffer[0] != '\0'){
827 pgn_append_ply(game, computer, move_buffer, mate);
828 } else {
829 pgn_set_result(game, mate);
832 if ( wt_command == COMMAND_QUIT ) {
833 exit = true;
834 break;
836 cb_drawboard();
838 break;
839 #ifdef COMMAND_RESTART
840 case COMMAND_RESTART:
841 GNUChess_Initialize();
842 game = pgn_init_game();
843 cb_drawboard();
844 break;
845 #endif
846 case COMMAND_RESUME:
847 cb_drawboard();
848 break;
849 case COMMAND_SAVE:
850 cb_saveposition();
851 cb_drawboard();
852 break;
853 case COMMAND_RESTORE:
854 /* watch out, it will reset the game if no previous game was saved! */
856 /* init board */
857 GNUChess_Initialize();
859 /* init PGN history data structures */
860 game = pgn_init_game();
862 /* restore saved position, if saved */
863 cb_restoreposition();
865 cb_drawboard();
866 break;
867 case COMMAND_PLAY:
868 if (opponent == white) {
869 opponent = black;
870 computer = white;
871 } else {
872 opponent = white;
873 computer = black;
875 rb->splash ( 0 , "Thinking..." );
876 ElapsedTime(1);
877 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
878 rb->cpu_boost ( true );
879 #endif
880 SelectMove ( computer , 0 , cb_wt_callback , move_buffer );
881 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
882 rb->cpu_boost ( false );
883 #endif
885 /* Add the ply to the PGN history (in algebraic notation) and check
886 * for the result of the game which is only calculated in SelectMove
888 if (move_buffer[0] != '\0'){
889 pgn_append_ply(game, computer, move_buffer, mate);
890 } else {
891 pgn_set_result(game, mate);
894 if ( wt_command == COMMAND_QUIT ) {
895 exit = true;
896 break;
898 cb_drawboard();
899 break;
900 case COMMAND_LEVEL:
901 cb_levelup ( );
902 cb_drawboard();
903 break;
904 case COMMAND_QUIT:
905 exit = true;
906 break;
910 cb_saveposition();
911 /* TODO: save/restore the PGN history of unfinished games */
912 rb->lcd_setfont(FONT_UI);
916 /*****************************************************************************
917 * plugin entry point.
918 ******************************************************************************/
919 enum plugin_status plugin_start(const void* parameter) {
921 /* plugin init */
923 #if LCD_DEPTH > 1
924 rb->lcd_set_backdrop(NULL);
925 #endif
927 /* end of plugin init */
929 /* if the plugin was invoked as a viewer, parse the file and show the game list
930 * else, start playing a game
932 if (parameter != NULL) {
933 cb_start_viewer((char *)parameter);
934 } else {
935 cb_play_game();
938 return PLUGIN_OK;
941 #endif /* HAVE_LCD_BITMAP */