FS#12076 - DB stats resurrection: If the filename was changed, require
[kugel-rb.git] / apps / plugins / chessbox / chessbox.c
blob6437c8d4fdfb03d0dcb7f4a09abd0b822a46bd93
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 #if (MEMORYSIZE > 8) /* Lowmem doesn't have playback in chessbox */
27 #define HAVE_PLAYBACK_CONTROL
28 #endif
31 #ifdef HAVE_PLAYBACK_CONTROL
32 #include "lib/playback_control.h"
33 #endif
35 #include "gnuchess.h"
36 #include "opening.h"
37 #include "chessbox_pgn.h"
39 /* type definitions */
40 struct cb_command {
41 int type;
42 char mv_s[5];
43 unsigned short mv;
46 /* External bitmaps */
47 extern const fb_data chessbox_pieces[];
52 /* Tile size defined by the assigned bitmap */
53 #include "pluginbitmaps/chessbox_pieces.h"
54 #define TILE_WIDTH BMPWIDTH_chessbox_pieces
55 #define TILE_HEIGHT (BMPHEIGHT_chessbox_pieces/26)
57 /* Calculate Offsets */
58 #define XOFS ((LCD_WIDTH-8*TILE_WIDTH)/2)
59 #define YOFS ((LCD_HEIGHT-8*TILE_HEIGHT)/2)
61 /* save files */
62 #define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/chessbox.save"
64 /* commands enum */
65 #define COMMAND_NOP 0
66 #define COMMAND_MOVE 1
67 #define COMMAND_PLAY 2
68 #define COMMAND_LEVEL 3
69 #define COMMAND_RESTART 4
70 #define COMMAND_QUIT 5
71 #define COMMAND_MENU 6
72 #define COMMAND_SAVE 7
73 #define COMMAND_RESTORE 8
74 #define COMMAND_RESUME 9
75 #define COMMAND_SELECT 10
76 #define COMMAND_NEXT 11
77 #define COMMAND_PREV 12
79 short plugin_mode;
81 /* level+1's string */
82 const char *level_string[] = { "Level 1: 60 moves / 5 min" ,
83 "Level 2: 60 moves / 15 min" ,
84 "Level 3: 60 moves / 30 min" ,
85 "Level 4: 40 moves / 30 min" ,
86 "Level 5: 40 moves / 60 min" ,
87 "Level 6: 40 moves / 120 min" ,
88 "Level 7: 40 moves / 240 min" ,
89 "Level 8: 1 move / 15 min" ,
90 "Level 9: 1 move / 60 min" ,
91 "Level 10: 1 move / 600 min" };
93 /* "While thinking" command */
94 int wt_command = COMMAND_NOP;
96 /* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */
97 void xy2cr ( short x, short y, short *c, short *r ) {
98 if (computer == black ) {
99 *c = x ;
100 *r = y ;
101 } else {
102 *c = 7 - x ;
103 *r = 7 - y ;
107 /* ---- get physical x y for a board column and row (e2 f.e.) ---- */
108 void cr2xy ( short c, short r, short *x, short *y ) {
109 if ( computer == black ) {
110 *x = c ;
111 *y = r ;
112 } else {
113 *x = 7 - c ;
114 *y = 7 - r ;
118 /* ---- Draw a complete board ---- */
119 static void cb_drawboard (void) {
120 short r , c , x , y ;
121 short l , piece , p_color ;
122 int b_color=1;
124 rb->lcd_clear_display();
126 for (r = 0; r < 8; r++) {
127 for (c = 0; c < 8; c++) {
128 l = locn[r][c];
129 piece = board[l] ;
130 p_color = color[l] ;
131 cr2xy ( c , r , &x , &y );
132 if ( piece == no_piece ) {
133 rb->lcd_bitmap_part ( chessbox_pieces , 0 ,
134 TILE_HEIGHT * b_color ,
135 STRIDE( SCREEN_MAIN,
136 BMPWIDTH_chessbox_pieces,
137 BMPHEIGHT_chessbox_pieces) ,
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 STRIDE( SCREEN_MAIN,
150 BMPWIDTH_chessbox_pieces,
151 BMPHEIGHT_chessbox_pieces) ,
152 XOFS + x*TILE_WIDTH ,
153 YOFS + (7 - y)*TILE_HEIGHT ,
154 TILE_WIDTH ,
155 TILE_HEIGHT );
157 b_color = (b_color == 1) ? 0 : 1 ;
159 b_color = (b_color == 1) ? 0 : 1 ;
162 /* draw board limits */
163 #if (LCD_WIDTH > TILE_WIDTH*8) && (LCD_HEIGHT > TILE_HEIGHT*8)
164 rb->lcd_drawrect(XOFS - 1, YOFS - 1, TILE_WIDTH*8 + 2, TILE_HEIGHT*8 + 2);
165 #elif LCD_WIDTH > TILE_WIDTH*8
166 rb->lcd_vline(XOFS - 1, 0, LCD_HEIGHT - 1);
167 rb->lcd_vline(XOFS + 8*TILE_WIDTH, 0, LCD_HEIGHT - 1);
168 #elif LCD_HEIGHT > TILE_HEIGHT*8
169 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS - 1);
170 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS + TILE_HEIGHT*8);
171 #endif
173 rb->lcd_update();
176 /* ---- Switch mark on board ---- */
177 void cb_switch ( short x , short y ) {
178 rb->lcd_set_drawmode ( DRMODE_COMPLEMENT );
179 rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 ,
180 YOFS + ( 7 - y )*TILE_HEIGHT +1 ,
181 TILE_WIDTH-2 , TILE_HEIGHT-2 );
182 rb->lcd_update();
183 rb->lcd_set_drawmode ( DRMODE_SOLID );
186 /* ---- callback for capturing interaction while thinking ---- */
187 void cb_wt_callback ( void ) {
188 int button = BUTTON_NONE;
190 wt_command = COMMAND_NOP;
191 button = rb->button_get(false);
192 switch (button) {
193 #ifdef CB_RC_QUIT
194 case CB_RC_QUIT:
195 wt_command = COMMAND_QUIT;
196 timeout = true;
197 break;
198 #endif
199 case CB_MENU:
200 wt_command = COMMAND_MENU;
201 timeout = true;
202 break;
203 case CB_PLAY:
204 wt_command = COMMAND_PLAY;
205 timeout = true;
206 break;
210 /* ---- set playing parameters depending on level ---- */
211 void cb_setlevel ( int lev ) {
212 Level = (lev > 7) ? 7 : ( (lev < 1) ? 1 : lev ) ;
213 switch (Level) {
214 case 1 :
215 TCmoves = 60;
216 TCminutes = 5;
217 break;
218 case 2 :
219 TCmoves = 60;
220 TCminutes = 15;
221 break;
222 case 3 :
223 TCmoves = 60;
224 TCminutes = 30;
225 break;
226 case 4 :
227 TCmoves = 40;
228 TCminutes = 30;
229 break;
230 case 5 :
231 TCmoves = 40;
232 TCminutes = 60;
233 break;
234 case 6 :
235 TCmoves = 40;
236 TCminutes = 120;
237 break;
238 case 7 :
239 TCmoves = 40;
240 TCminutes = 240;
241 break;
242 case 8 :
243 TCmoves = 1;
244 TCminutes = 15;
245 break;
246 case 9 :
247 TCmoves = 1;
248 TCminutes = 60;
249 break;
250 case 10 :
251 TCmoves = 1;
252 TCminutes = 600;
253 break;
255 TCflag = (TCmoves > 1);
256 SetTimeControl();
259 /* ---- increase playing level ---- */
260 void cb_levelup ( void ) {
261 if ( Level == 7 )
262 cb_setlevel ( 1 );
263 else
264 cb_setlevel ( Level+1 );
265 rb->splash ( HZ/2 , level_string[Level-1] );
268 /* ---- Save current position ---- */
269 void cb_saveposition ( void ) {
270 int fd;
271 short sq,i,c;
272 unsigned short temp;
274 rb->splash ( 0 , "Saving position" );
276 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
278 computer++; rb->write(fd, &(computer), sizeof(computer)); computer--;
279 opponent++; rb->write(fd, &(opponent), sizeof(opponent)); opponent--;
280 rb->write(fd, &(Game50), sizeof(Game50));
282 rb->write(fd, &(castld[white]), sizeof(castld[white]));
283 rb->write(fd, &(castld[black]), sizeof(castld[black]));
284 rb->write(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
285 rb->write(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
287 rb->write(fd, &(withbook), sizeof(withbook));
288 rb->write(fd, &(Level), sizeof(Level));
289 rb->write(fd, &(TCflag), sizeof(TCflag));
290 rb->write(fd, &(OperatorTime), sizeof(OperatorTime));
292 rb->write(fd, &(TimeControl.clock[white]),
293 sizeof(TimeControl.clock[white]) );
294 rb->write(fd, &(TimeControl.clock[black]),
295 sizeof(TimeControl.clock[black]) );
296 rb->write(fd, &(TimeControl.moves[white]),
297 sizeof(TimeControl.moves[white]) );
298 rb->write(fd, &(TimeControl.moves[black]),
299 sizeof(TimeControl.moves[black]) );
300 for (sq = 0; sq < 64; sq++) {
301 if (color[sq] == neutral) c = 0; else c = color[sq]+1;
302 temp = 256*board[sq] + c ;
303 rb->write(fd, &(temp), sizeof(temp));
305 for (i = 0; i <= GameCnt; i++) {
306 if (GameList[i].color == neutral)
307 c = 0;
308 else
309 c = GameList[i].color + 1;
310 rb->write(fd, &(GameList[i].gmove), sizeof(GameList[i].gmove));
311 rb->write(fd, &(GameList[i].score), sizeof(GameList[i].score));
312 rb->write(fd, &(GameList[i].depth), sizeof(GameList[i].depth));
313 rb->write(fd, &(GameList[i].nodes), sizeof(GameList[i].nodes));
314 rb->write(fd, &(GameList[i].time), sizeof(GameList[i].time));
315 rb->write(fd, &(GameList[i].piece), sizeof(GameList[i].piece));
316 rb->write(fd, &(c), sizeof(c));
318 rb->close(fd);
321 /* ---- Restore saved position ---- */
322 void cb_restoreposition ( void ) {
323 int fd;
324 short sq;
325 unsigned short m;
327 if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) {
328 rb->splash ( 0 , "Loading position" );
329 rb->read(fd, &(computer), sizeof(computer));
330 rb->read(fd, &(opponent), sizeof(opponent));
331 rb->read(fd, &(Game50), sizeof(Game50));
333 rb->read(fd, &(castld[white]), sizeof(castld[white]));
334 rb->read(fd, &(castld[black]), sizeof(castld[black]));
335 rb->read(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
336 rb->read(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
338 rb->read(fd, &(withbook), sizeof(withbook));
339 rb->read(fd, &(Level), sizeof(Level));
340 rb->read(fd, &(TCflag), sizeof(TCflag));
341 rb->read(fd, &(OperatorTime), sizeof(OperatorTime));
343 rb->read(fd, &(TimeControl.clock[white]),
344 sizeof(TimeControl.clock[white]));
345 rb->read(fd, &(TimeControl.clock[black]),
346 sizeof(TimeControl.clock[black]));
347 rb->read(fd, &(TimeControl.moves[white]),
348 sizeof(TimeControl.moves[white]));
349 rb->read(fd, &(TimeControl.moves[black]),
350 sizeof(TimeControl.moves[black]));
351 for (sq = 0; sq < 64; sq++) {
352 rb->read(fd, &(m), sizeof(m));
353 board[sq] = (m >> 8); color[sq] = (m & 0xFF);
354 if (color[sq] == 0)
355 color[sq] = neutral;
356 else
357 --color[sq];
359 GameCnt = -1;
360 while (rb->read(fd, &(GameList[++GameCnt].gmove),
361 sizeof(GameList[GameCnt].gmove)) > 0) {
362 rb->read(fd, &(GameList[GameCnt].score),
363 sizeof(GameList[GameCnt].score));
364 rb->read(fd, &(GameList[GameCnt].depth),
365 sizeof(GameList[GameCnt].depth));
366 rb->read(fd, &(GameList[GameCnt].nodes),
367 sizeof(GameList[GameCnt].nodes));
368 rb->read(fd, &(GameList[GameCnt].time),
369 sizeof(GameList[GameCnt].time));
370 rb->read(fd, &(GameList[GameCnt].piece),
371 sizeof(GameList[GameCnt].piece));
372 rb->read(fd, &(GameList[GameCnt].color),
373 sizeof(GameList[GameCnt].color));
374 if (GameList[GameCnt].color == 0)
375 GameList[GameCnt].color = neutral;
376 else
377 --GameList[GameCnt].color;
379 GameCnt--;
380 if (TimeControl.clock[white] > 0)
381 TCflag = true;
382 computer--; opponent--;
384 rb->close(fd);
385 cb_setlevel(Level);
386 InitializeStats();
387 Sdepth = 0;
390 /* ---- show menu in viewer mode---- */
391 static int cb_menu_viewer(void)
393 int selection;
394 int result = 0;
395 bool menu_quit = false;
397 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"Restart Game",
398 "Select Other Game", "Quit");
400 while(!menu_quit)
402 switch(rb->do_menu(&menu, &selection, NULL, false))
404 case 0:
405 menu_quit = true;
406 result = COMMAND_RESTART;
407 break;
408 case 1:
409 result = COMMAND_SELECT;
410 menu_quit = true;
411 break;
412 case 2:
413 result = COMMAND_QUIT;
414 menu_quit = true;
415 break;
418 return result;
421 /* ---- get a command in game mode ---- */
422 struct cb_command cb_get_viewer_command (void) {
423 int button;
424 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
426 /* main loop */
427 while ( true ) {
428 button = rb->button_get(true);
429 switch (button) {
430 #ifdef CB_RC_QUIT
431 case CB_RC_QUIT:
432 result.type = COMMAND_QUIT;
433 return result;
434 #endif
435 case CB_MENU:
436 result.type = cb_menu_viewer();
437 return result;
438 case CB_LEFT:
439 result.type = COMMAND_PREV;
440 return result;
441 case CB_RIGHT:
442 result.type = COMMAND_NEXT;
443 return result;
449 /* ---- viewer main loop ---- */
450 void cb_start_viewer(char* filename){
451 struct pgn_game_node *first_game, *selected_game;
452 struct pgn_ply_node *curr_ply;
453 bool exit_game = false;
454 bool exit_viewer = false;
455 struct cb_command command;
457 first_game = pgn_list_games(filename);
458 if (first_game == NULL){
459 rb->splash ( HZ*2 , "No games found !" );
460 return;
463 do {
464 selected_game = pgn_show_game_list(first_game);
465 if (selected_game == NULL){
466 break;
469 pgn_parse_game(filename, selected_game);
470 if (selected_game->first_ply != NULL) {
472 /* init board */
473 GNUChess_Initialize();
475 /* draw the board */
476 cb_drawboard();
478 curr_ply = selected_game->first_ply;
479 exit_game = false;
481 do {
482 command = cb_get_viewer_command ();
483 switch (command.type) {
484 case COMMAND_PREV:
485 /* unapply the previous ply */
486 if (curr_ply->prev_node != NULL){
487 curr_ply = curr_ply->prev_node;
488 } else {
489 rb->splash ( HZ*2 , "At the begining of the game" );
490 break;
492 board[locn[curr_ply->row_from][curr_ply->column_from]]
493 = board[locn[curr_ply->row_to][curr_ply->column_to]];
494 color[locn[curr_ply->row_from][curr_ply->column_from]]
495 = color[locn[curr_ply->row_to][curr_ply->column_to]];
496 board[locn[curr_ply->row_to][curr_ply->column_to]] = no_piece;
497 color[locn[curr_ply->row_to][curr_ply->column_to]] = neutral;
498 if (curr_ply->taken_piece != no_piece && !curr_ply->enpassant){
499 board[locn[curr_ply->row_to][curr_ply->column_to]]
500 = curr_ply->taken_piece;
501 color[locn[curr_ply->row_to][curr_ply->column_to]]
502 = ((curr_ply->player==white)?black:white);
504 if (curr_ply->castle){
505 if (curr_ply->column_to == 6){
506 /* castling kingside */
507 board[locn[curr_ply->row_to][7]] = rook;
508 color[locn[curr_ply->row_to][7]] = curr_ply->player;
509 board[locn[curr_ply->row_to][5]] = no_piece;
510 color[locn[curr_ply->row_to][5]] = neutral;
511 } else {
512 /* castling queenside */
513 board[locn[curr_ply->row_to][0]] = rook;
514 color[locn[curr_ply->row_to][0]] = curr_ply->player;
515 board[locn[curr_ply->row_to][3]] = no_piece;
516 color[locn[curr_ply->row_to][3]] = neutral;
519 if (curr_ply->enpassant){
520 board[locn[curr_ply->row_from][curr_ply->column_to]] = pawn;
521 color[locn[curr_ply->row_from][curr_ply->column_to]]
522 = ((curr_ply->player==white)?black:white);
524 if (curr_ply->promotion){
525 board[locn[curr_ply->row_from][curr_ply->column_from]] = pawn;
526 color[locn[curr_ply->row_from][curr_ply->column_from]]
527 = curr_ply->player;
530 cb_drawboard();
531 break;
532 case COMMAND_NEXT:
533 /* apply the current move */
534 if (curr_ply->player == neutral){
535 rb->splash ( HZ*2 , "At the end of the game" );
536 break;
538 board[locn[curr_ply->row_to][curr_ply->column_to]]
539 = board[locn[curr_ply->row_from][curr_ply->column_from]];
540 color[locn[curr_ply->row_to][curr_ply->column_to]]
541 = color[locn[curr_ply->row_from][curr_ply->column_from]];
542 board[locn[curr_ply->row_from][curr_ply->column_from]] = no_piece;
543 color[locn[curr_ply->row_from][curr_ply->column_from]] = neutral;
544 if (curr_ply->castle){
545 if (curr_ply->column_to == 6){
546 /* castling kingside */
547 board[locn[curr_ply->row_to][5]] = rook;
548 color[locn[curr_ply->row_to][5]] = curr_ply->player;
549 board[locn[curr_ply->row_to][7]] = no_piece;
550 color[locn[curr_ply->row_to][7]] = neutral;
551 } else {
552 /* castling queenside */
553 board[locn[curr_ply->row_to][3]] = rook;
554 color[locn[curr_ply->row_to][3]] = curr_ply->player;
555 board[locn[curr_ply->row_to][0]] = no_piece;
556 color[locn[curr_ply->row_to][0]] = neutral;
559 if (curr_ply->enpassant){
560 board[locn[curr_ply->row_from][curr_ply->column_to]] = no_piece;
561 color[locn[curr_ply->row_from][curr_ply->column_to]] = neutral;
563 if (curr_ply->promotion){
564 board[locn[curr_ply->row_to][curr_ply->column_to]]
565 = curr_ply->promotion_piece;
566 color[locn[curr_ply->row_to][curr_ply->column_to]]
567 = curr_ply->player;
569 if (curr_ply->next_node != NULL){
570 curr_ply = curr_ply->next_node;
572 cb_drawboard();
573 break;
574 case COMMAND_RESTART:
575 GNUChess_Initialize();
576 cb_drawboard();
577 curr_ply = selected_game->first_ply;
578 case COMMAND_SELECT:
579 exit_game = true;
580 break;
581 case COMMAND_QUIT:
582 exit_viewer = true;
583 break;
585 } while (!exit_game && !exit_viewer);
586 } else {
587 rb->splash ( HZ*2 , "Error parsing game !");
589 } while (!exit_viewer);
592 /* ---- show menu ---- */
593 static int cb_menu(void)
595 int selection;
596 int result = 0;
597 bool menu_quit = false;
599 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"New Game","Resume Game",
600 "Save Game", "Restore Game",
601 #ifdef HAVE_PLAYBACK_CONTROL
602 "Playback Control",
603 #endif
604 "Quit");
606 while(!menu_quit)
608 switch(rb->do_menu(&menu, &selection, NULL, false))
610 case 0:
611 menu_quit = true;
612 result = COMMAND_RESTART;
613 break;
614 case 1:
615 result = COMMAND_RESUME;
616 menu_quit = true;
617 break;
618 case 2:
619 result = COMMAND_SAVE;
620 menu_quit = true;
621 break;
622 case 3:
623 result = COMMAND_RESTORE;
624 menu_quit = true;
625 break;
626 case 4:
627 #ifdef HAVE_PLAYBACK_CONTROL
628 playback_control(NULL);
629 break;
630 case 5:
631 #endif
632 result = COMMAND_QUIT;
633 menu_quit = true;
634 break;
637 return result;
640 /* ---- get a command in game mode ---- */
641 struct cb_command cb_getcommand (void) {
642 static short x = 4 , y = 3 ;
643 short c , r , l;
644 int button;
645 #if defined(CB_PLAY_PRE) || defined(CB_SELECT_PRE)
646 int lastbutton = BUTTON_NONE;
647 #endif
648 int marked = false , from_marked = false ;
649 short marked_x = 0 , marked_y = 0 ;
650 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
652 cb_switch ( x , y );
653 /* main loop */
654 while ( true ) {
655 button = rb->button_get(true);
656 switch (button) {
657 #ifdef CB_RC_QUIT
658 case CB_RC_QUIT:
659 result.type = COMMAND_QUIT;
660 return result;
661 #endif
662 case CB_MENU:
663 result.type = cb_menu();
664 return result;
665 case CB_LEVEL:
666 result.type = COMMAND_LEVEL;
667 return result;
668 case CB_PLAY:
669 #ifdef CB_PLAY_PRE
670 if (lastbutton != CB_PLAY_PRE)
671 break;
672 #endif
673 result.type = COMMAND_PLAY;
674 return result;
675 case CB_UP:
676 if ( !from_marked ) cb_switch ( x , y );
677 y++;
678 if ( y == 8 ) {
679 y = 0;
680 x--;
681 if ( x < 0 ) x = 7;
683 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
684 from_marked = true ;
685 } else {
686 from_marked = false ;
687 cb_switch ( x , y );
689 break;
690 case CB_DOWN:
691 if ( !from_marked ) cb_switch ( x , y );
692 y--;
693 if ( y < 0 ) {
694 y = 7;
695 x++;
696 if ( x == 8 ) x = 0;
698 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
699 from_marked = true ;
700 } else {
701 from_marked = false ;
702 cb_switch ( x , y );
704 break;
705 case CB_LEFT:
706 if ( !from_marked ) cb_switch ( x , y );
707 x--;
708 if ( x < 0 ) {
709 x = 7;
710 y++;
711 if ( y == 8 ) y = 0;
713 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
714 from_marked = true ;
715 } else {
716 from_marked = false ;
717 cb_switch ( x , y );
719 break;
720 case CB_RIGHT:
721 if ( !from_marked ) cb_switch ( x , y );
722 x++;
723 if ( x == 8 ) {
724 x = 0;
725 y--;
726 if ( y < 0 ) y = 7;
728 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
729 from_marked = true ;
730 } else {
731 from_marked = false ;
732 cb_switch ( x , y );
734 break;
735 case CB_SELECT:
736 #ifdef CB_SELECT_PRE
737 if (lastbutton != CB_SELECT_PRE)
738 break;
739 #endif
740 if ( !marked ) {
741 xy2cr ( x , y , &c , &r );
742 l = locn[r][c];
743 if ( ( color[l]!=computer ) && ( board[l]!=no_piece ) ) {
744 marked = true;
745 from_marked = true ;
746 marked_x = x;
747 marked_y = y;
749 } else {
750 if ( ( marked_x == x ) && ( marked_y == y ) ) {
751 marked = false;
752 from_marked = false;
753 } else {
754 xy2cr ( marked_x , marked_y , &c , &r );
755 result.mv_s[0] = 'a' + c;
756 result.mv_s[1] = '1' + r;
757 xy2cr ( x , y , &c , &r );
758 result.mv_s[2] = 'a' + c;
759 result.mv_s[3] = '1' + r;
760 result.mv_s[4] = '\00';
761 result.type = COMMAND_MOVE;
762 return result;
765 break;
767 #if defined(CB_PLAY_PRE) || defined(CB_SELECT_PRE)
768 if (button != BUTTON_NONE)
769 lastbutton = button;
770 #endif
775 /* ---- game main loop ---- */
776 void cb_play_game(void) {
777 struct cb_command command;
778 struct pgn_game_node *game;
779 char move_buffer[20];
781 /* init status */
782 bool exit = false;
784 /* load opening book, soon */
786 /* init board */
787 GNUChess_Initialize();
789 /* init PGN history data structures */
790 game = pgn_init_game();
792 /* restore saved position, if saved */
793 cb_restoreposition();
794 /* TODO: save/restore the PGN history of unfinished games */
796 /* draw the board */
797 /* I don't like configscreens, start game inmediatly */
798 cb_drawboard();
800 while (!exit) {
801 if ( mate ) {
802 rb->splash ( HZ*3 , "Checkmate!" );
803 rb->button_get(true);
804 pgn_store_game(game);
805 GNUChess_Initialize();
806 game = pgn_init_game();
807 cb_drawboard();
809 command = cb_getcommand ();
810 switch (command.type) {
811 case COMMAND_MOVE:
812 if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) {
813 rb->splash ( HZ/2 , "Illegal move!" );
814 cb_drawboard();
815 } else {
816 cb_drawboard();
818 /* Add the ply to the PGN history (in algebraic notation) */
819 pgn_append_ply(game, opponent, move_buffer, mate);
821 rb->splash ( 0 , "Thinking..." );
822 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
823 rb->cpu_boost ( true );
824 #endif
825 SelectMove ( computer , 0 , cb_wt_callback, move_buffer);
826 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
827 rb->cpu_boost ( false );
828 #endif
829 /* Add the ply to the PGN history (in algebraic notation) and check
830 * for the result of the game which is only calculated in SelectMove
832 if (move_buffer[0] != '\0'){
833 pgn_append_ply(game, computer, move_buffer, mate);
834 } else {
835 pgn_set_result(game, mate);
838 if ( wt_command == COMMAND_QUIT ) {
839 exit = true;
840 break;
842 cb_drawboard();
844 break;
845 #ifdef COMMAND_RESTART
846 case COMMAND_RESTART:
847 GNUChess_Initialize();
848 game = pgn_init_game();
849 cb_drawboard();
850 break;
851 #endif
852 case COMMAND_RESUME:
853 cb_drawboard();
854 break;
855 case COMMAND_SAVE:
856 cb_saveposition();
857 cb_drawboard();
858 break;
859 case COMMAND_RESTORE:
860 /* watch out, it will reset the game if no previous game was saved! */
862 /* init board */
863 GNUChess_Initialize();
865 /* init PGN history data structures */
866 game = pgn_init_game();
868 /* restore saved position, if saved */
869 cb_restoreposition();
871 cb_drawboard();
872 break;
873 case COMMAND_PLAY:
874 if (opponent == white) {
875 opponent = black;
876 computer = white;
877 } else {
878 opponent = white;
879 computer = black;
881 rb->splash ( 0 , "Thinking..." );
882 ElapsedTime(1);
883 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
884 rb->cpu_boost ( true );
885 #endif
886 SelectMove ( computer , 0 , cb_wt_callback , move_buffer );
887 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
888 rb->cpu_boost ( false );
889 #endif
891 /* Add the ply to the PGN history (in algebraic notation) and check
892 * for the result of the game which is only calculated in SelectMove
894 if (move_buffer[0] != '\0'){
895 pgn_append_ply(game, computer, move_buffer, mate);
896 } else {
897 pgn_set_result(game, mate);
900 if ( wt_command == COMMAND_QUIT ) {
901 exit = true;
902 break;
904 cb_drawboard();
905 break;
906 case COMMAND_LEVEL:
907 cb_levelup ( );
908 cb_drawboard();
909 break;
910 case COMMAND_QUIT:
911 exit = true;
912 break;
916 cb_saveposition();
917 /* TODO: save/restore the PGN history of unfinished games */
918 rb->lcd_setfont(FONT_UI);
922 /*****************************************************************************
923 * plugin entry point.
924 ******************************************************************************/
925 enum plugin_status plugin_start(const void* parameter) {
927 /* plugin init */
929 #if LCD_DEPTH > 1
930 rb->lcd_set_backdrop(NULL);
931 #endif
933 /* end of plugin init */
935 /* if the plugin was invoked as a viewer, parse the file and show the game list
936 * else, start playing a game
938 if (parameter != NULL) {
939 cb_start_viewer((char *)parameter);
940 } else {
941 cb_play_game();
944 return PLUGIN_OK;