New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / chessbox / chessbox.c
blobf8db7d9b7fabb932cdecb7ac6540faa6e4bde9f6
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 #include "gnuchess.h"
29 #include "opening.h"
30 #include "chessbox_pgn.h"
32 /* type definitions */
33 struct cb_command {
34 int type;
35 char mv_s[5];
36 unsigned short mv;
39 /* External bitmaps */
40 extern const fb_data chessbox_pieces[];
43 PLUGIN_HEADER
45 /* Tile size defined by the assigned bitmap */
46 #include "pluginbitmaps/chessbox_pieces.h"
47 #define TILE_WIDTH BMPWIDTH_chessbox_pieces
48 #define TILE_HEIGHT (BMPHEIGHT_chessbox_pieces/26)
50 /* Calculate Offsets */
51 #define XOFS ((LCD_WIDTH-8*TILE_WIDTH)/2)
52 #define YOFS ((LCD_HEIGHT-8*TILE_HEIGHT)/2)
54 /* save files */
55 #define SAVE_FILE PLUGIN_GAMES_DIR "/chessbox.save"
57 /* commands enum */
58 #define COMMAND_NOP 0
59 #define COMMAND_MOVE 1
60 #define COMMAND_PLAY 2
61 #define COMMAND_LEVEL 3
62 #define COMMAND_RESTART 4
63 #define COMMAND_QUIT 5
64 #define COMMAND_MENU 6
65 #define COMMAND_SAVE 7
66 #define COMMAND_RESTORE 8
67 #define COMMAND_RESUME 9
68 #define COMMAND_SELECT 10
69 #define COMMAND_NEXT 11
70 #define COMMAND_PREV 12
72 short plugin_mode;
74 /* level+1's string */
75 const char *level_string[] = { "Level 1: 60 moves / 5 min" ,
76 "Level 2: 60 moves / 15 min" ,
77 "Level 3: 60 moves / 30 min" ,
78 "Level 4: 40 moves / 30 min" ,
79 "Level 5: 40 moves / 60 min" ,
80 "Level 6: 40 moves / 120 min" ,
81 "Level 7: 40 moves / 240 min" ,
82 "Level 8: 1 move / 15 min" ,
83 "Level 9: 1 move / 60 min" ,
84 "Level 10: 1 move / 600 min" };
86 /* "While thinking" command */
87 int wt_command = COMMAND_NOP;
89 /* GCC wants this to be present for some targets */
90 void* memcpy(void* dst, const void* src, size_t size)
92 return rb->memcpy(dst, src, size);
95 /* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */
96 void xy2cr ( short x, short y, short *c, short *r ) {
97 if (computer == black ) {
98 *c = x ;
99 *r = y ;
100 } else {
101 *c = 7 - x ;
102 *r = 7 - y ;
106 /* ---- get physical x y for a board column and row (e2 f.e.) ---- */
107 void cr2xy ( short c, short r, short *x, short *y ) {
108 if ( computer == black ) {
109 *x = c ;
110 *y = r ;
111 } else {
112 *x = 7 - c ;
113 *y = 7 - r ;
117 /* ---- Draw a complete board ---- */
118 static void cb_drawboard (void) {
119 short r , c , x , y ;
120 short l , piece , p_color ;
121 int b_color=1;
123 rb->lcd_clear_display();
125 for (r = 0; r < 8; r++) {
126 for (c = 0; c < 8; c++) {
127 l = locn[r][c];
128 piece = board[l] ;
129 p_color = color[l] ;
130 cr2xy ( c , r , &x , &y );
131 if ( piece == no_piece ) {
132 rb->lcd_bitmap_part ( chessbox_pieces , 0 ,
133 TILE_HEIGHT * b_color ,
134 TILE_WIDTH ,
135 XOFS + x*TILE_WIDTH ,
136 YOFS + ( 7 - y )*TILE_HEIGHT ,
137 TILE_WIDTH ,
138 TILE_HEIGHT );
139 } else {
140 rb->lcd_bitmap_part ( chessbox_pieces ,
142 2 * TILE_HEIGHT +
143 4 * TILE_HEIGHT * ( piece - 1 ) +
144 2 * TILE_HEIGHT * p_color +
145 TILE_HEIGHT * b_color ,
146 TILE_WIDTH ,
147 XOFS + x*TILE_WIDTH ,
148 YOFS + (7 - y)*TILE_HEIGHT ,
149 TILE_WIDTH ,
150 TILE_HEIGHT );
152 b_color = (b_color == 1) ? 0 : 1 ;
154 b_color = (b_color == 1) ? 0 : 1 ;
157 /* draw board limits */
158 #if (LCD_WIDTH > TILE_WIDTH*8) && (LCD_HEIGHT > TILE_HEIGHT*8)
159 rb->lcd_drawrect(XOFS - 1, YOFS - 1, TILE_WIDTH*8 + 2, TILE_HEIGHT*8 + 2);
160 #elif LCD_WIDTH > TILE_WIDTH*8
161 rb->lcd_vline(XOFS - 1, 0, LCD_HEIGHT - 1);
162 rb->lcd_vline(XOFS + 8*TILE_WIDTH, 0, LCD_HEIGHT - 1);
163 #elif LCD_HEIGHT > TILE_HEIGHT*8
164 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS - 1);
165 rb->lcd_hline(0, LCD_WIDTH - 1, YOFS + TILE_HEIGHT*8);
166 #endif
168 rb->lcd_update();
171 /* ---- Switch mark on board ---- */
172 void cb_switch ( short x , short y ) {
173 rb->lcd_set_drawmode ( DRMODE_COMPLEMENT );
174 rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 ,
175 YOFS + ( 7 - y )*TILE_HEIGHT +1 ,
176 TILE_WIDTH-2 , TILE_HEIGHT-2 );
177 rb->lcd_update();
178 rb->lcd_set_drawmode ( DRMODE_SOLID );
181 /* ---- callback for capturing interaction while thinking ---- */
182 void cb_wt_callback ( void ) {
183 int button = BUTTON_NONE;
185 wt_command = COMMAND_NOP;
186 button = rb->button_get(false);
187 switch (button) {
188 #ifdef CB_RC_QUIT
189 case CB_RC_QUIT:
190 wt_command = COMMAND_QUIT;
191 timeout = true;
192 break;
193 #endif
194 case CB_MENU:
195 wt_command = COMMAND_MENU;
196 timeout = true;
197 break;
198 case CB_PLAY:
199 wt_command = COMMAND_PLAY;
200 timeout = true;
201 break;
205 /* ---- set playing parameters depending on level ---- */
206 void cb_setlevel ( int lev ) {
207 Level = (lev > 7) ? 7 : ( (lev < 1) ? 1 : lev ) ;
208 switch (Level) {
209 case 1 :
210 TCmoves = 60;
211 TCminutes = 5;
212 break;
213 case 2 :
214 TCmoves = 60;
215 TCminutes = 15;
216 break;
217 case 3 :
218 TCmoves = 60;
219 TCminutes = 30;
220 break;
221 case 4 :
222 TCmoves = 40;
223 TCminutes = 30;
224 break;
225 case 5 :
226 TCmoves = 40;
227 TCminutes = 60;
228 break;
229 case 6 :
230 TCmoves = 40;
231 TCminutes = 120;
232 break;
233 case 7 :
234 TCmoves = 40;
235 TCminutes = 240;
236 break;
237 case 8 :
238 TCmoves = 1;
239 TCminutes = 15;
240 break;
241 case 9 :
242 TCmoves = 1;
243 TCminutes = 60;
244 break;
245 case 10 :
246 TCmoves = 1;
247 TCminutes = 600;
248 break;
250 TCflag = (TCmoves > 1);
251 SetTimeControl();
254 /* ---- increase playing level ---- */
255 void cb_levelup ( void ) {
256 if ( Level == 7 )
257 cb_setlevel ( 1 );
258 else
259 cb_setlevel ( Level+1 );
260 rb->splash ( HZ/2 , level_string[Level-1] );
263 /* ---- Save current position ---- */
264 void cb_saveposition ( void ) {
265 int fd;
266 short sq,i,c;
267 unsigned short temp;
269 rb->splash ( 0 , "Saving position" );
271 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
273 computer++; rb->write(fd, &(computer), sizeof(computer)); computer--;
274 opponent++; rb->write(fd, &(opponent), sizeof(opponent)); opponent--;
275 rb->write(fd, &(Game50), sizeof(Game50));
277 rb->write(fd, &(castld[white]), sizeof(castld[white]));
278 rb->write(fd, &(castld[black]), sizeof(castld[black]));
279 rb->write(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
280 rb->write(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
282 rb->write(fd, &(withbook), sizeof(withbook));
283 rb->write(fd, &(Level), sizeof(Level));
284 rb->write(fd, &(TCflag), sizeof(TCflag));
285 rb->write(fd, &(OperatorTime), sizeof(OperatorTime));
287 rb->write(fd, &(TimeControl.clock[white]),
288 sizeof(TimeControl.clock[white]) );
289 rb->write(fd, &(TimeControl.clock[black]),
290 sizeof(TimeControl.clock[black]) );
291 rb->write(fd, &(TimeControl.moves[white]),
292 sizeof(TimeControl.moves[white]) );
293 rb->write(fd, &(TimeControl.moves[black]),
294 sizeof(TimeControl.moves[black]) );
295 for (sq = 0; sq < 64; sq++) {
296 if (color[sq] == neutral) c = 0; else c = color[sq]+1;
297 temp = 256*board[sq] + c ;
298 rb->write(fd, &(temp), sizeof(temp));
300 for (i = 0; i <= GameCnt; i++) {
301 if (GameList[i].color == neutral)
302 c = 0;
303 else
304 c = GameList[i].color + 1;
305 rb->write(fd, &(GameList[i].gmove), sizeof(GameList[i].gmove));
306 rb->write(fd, &(GameList[i].score), sizeof(GameList[i].score));
307 rb->write(fd, &(GameList[i].depth), sizeof(GameList[i].depth));
308 rb->write(fd, &(GameList[i].nodes), sizeof(GameList[i].nodes));
309 rb->write(fd, &(GameList[i].time), sizeof(GameList[i].time));
310 rb->write(fd, &(GameList[i].piece), sizeof(GameList[i].piece));
311 rb->write(fd, &(c), sizeof(c));
313 rb->close(fd);
316 /* ---- Restore saved position ---- */
317 void cb_restoreposition ( void ) {
318 int fd;
319 int c;
320 short sq;
321 unsigned short m;
323 if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) {
324 rb->splash ( 0 , "Loading position" );
325 rb->read(fd, &(computer), sizeof(computer));
326 rb->read(fd, &(opponent), sizeof(opponent));
327 rb->read(fd, &(Game50), sizeof(Game50));
329 rb->read(fd, &(castld[white]), sizeof(castld[white]));
330 rb->read(fd, &(castld[black]), sizeof(castld[black]));
331 rb->read(fd, &(kingmoved[white]), sizeof(kingmoved[white]));
332 rb->read(fd, &(kingmoved[black]), sizeof(kingmoved[black]));
334 rb->read(fd, &(withbook), sizeof(withbook));
335 rb->read(fd, &(Level), sizeof(Level));
336 rb->read(fd, &(TCflag), sizeof(TCflag));
337 rb->read(fd, &(OperatorTime), sizeof(OperatorTime));
339 rb->read(fd, &(TimeControl.clock[white]),
340 sizeof(TimeControl.clock[white]));
341 rb->read(fd, &(TimeControl.clock[black]),
342 sizeof(TimeControl.clock[black]));
343 rb->read(fd, &(TimeControl.moves[white]),
344 sizeof(TimeControl.moves[white]));
345 rb->read(fd, &(TimeControl.moves[black]),
346 sizeof(TimeControl.moves[black]));
347 for (sq = 0; sq < 64; sq++) {
348 rb->read(fd, &(m), sizeof(m));
349 board[sq] = (m >> 8); color[sq] = (m & 0xFF);
350 if (color[sq] == 0)
351 color[sq] = neutral;
352 else
353 --color[sq];
355 GameCnt = -1; c = '?';
356 while (rb->read(fd, &(GameList[++GameCnt].gmove),
357 sizeof(GameList[GameCnt].gmove)) > 0) {
358 rb->read(fd, &(GameList[GameCnt].score),
359 sizeof(GameList[GameCnt].score));
360 rb->read(fd, &(GameList[GameCnt].depth),
361 sizeof(GameList[GameCnt].depth));
362 rb->read(fd, &(GameList[GameCnt].nodes),
363 sizeof(GameList[GameCnt].nodes));
364 rb->read(fd, &(GameList[GameCnt].time),
365 sizeof(GameList[GameCnt].time));
366 rb->read(fd, &(GameList[GameCnt].piece),
367 sizeof(GameList[GameCnt].piece));
368 rb->read(fd, &(GameList[GameCnt].color),
369 sizeof(GameList[GameCnt].color));
370 if (GameList[GameCnt].color == 0)
371 GameList[GameCnt].color = neutral;
372 else
373 --GameList[GameCnt].color;
375 GameCnt--;
376 if (TimeControl.clock[white] > 0)
377 TCflag = true;
378 computer--; opponent--;
380 rb->close(fd);
381 cb_setlevel(Level);
382 InitializeStats();
383 Sdepth = 0;
386 /* ---- show menu in viewer mode---- */
387 static int cb_menu_viewer(void)
389 int selection;
390 int result = 0;
391 bool menu_quit = false;
393 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"Restart Game",
394 "Select Other Game", "Quit");
396 while(!menu_quit)
398 switch(rb->do_menu(&menu, &selection, NULL, false))
400 case 0:
401 menu_quit = true;
402 result = COMMAND_RESTART;
403 break;
404 case 1:
405 result = COMMAND_SELECT;
406 menu_quit = true;
407 break;
408 case 2:
409 result = COMMAND_QUIT;
410 menu_quit = true;
411 break;
414 return result;
417 /* ---- get a command in game mode ---- */
418 struct cb_command cb_get_viewer_command (void) {
419 int button;
420 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
422 /* main loop */
423 while ( true ) {
424 button = rb->button_get(true);
425 switch (button) {
426 #ifdef CB_RC_QUIT
427 case CB_RC_QUIT:
428 result.type = COMMAND_QUIT;
429 return result;
430 #endif
431 case CB_MENU:
432 result.type = cb_menu_viewer();
433 return result;
434 case CB_LEFT:
435 result.type = COMMAND_PREV;
436 return result;
437 case CB_RIGHT:
438 result.type = COMMAND_NEXT;
439 return result;
445 /* ---- viewer main loop ---- */
446 void cb_start_viewer(char* filename){
447 struct pgn_game_node *first_game, *selected_game;
448 struct pgn_ply_node *curr_ply;
449 bool exit_game = false;
450 bool exit_viewer = false;
451 struct cb_command command;
453 first_game = pgn_list_games(rb, filename);
454 if (first_game == NULL){
455 rb->splash ( HZ*2 , "No games found !" );
456 return;
459 do {
460 selected_game = pgn_show_game_list(rb, first_game);
461 if (selected_game == NULL){
462 break;
465 pgn_parse_game(rb, filename, selected_game);
466 if (selected_game->first_ply != NULL) {
468 /* init board */
469 GNUChess_Initialize();
471 /* draw the board */
472 cb_drawboard();
474 curr_ply = selected_game->first_ply;
475 exit_game = false;
477 do {
478 command = cb_get_viewer_command ();
479 switch (command.type) {
480 case COMMAND_PREV:
481 /* unapply the previous ply */
482 if (curr_ply->prev_node != NULL){
483 curr_ply = curr_ply->prev_node;
484 } else {
485 rb->splash ( HZ*2 , "At the begining of the game" );
486 break;
488 board[locn[curr_ply->row_from][curr_ply->column_from]]
489 = board[locn[curr_ply->row_to][curr_ply->column_to]];
490 color[locn[curr_ply->row_from][curr_ply->column_from]]
491 = color[locn[curr_ply->row_to][curr_ply->column_to]];
492 board[locn[curr_ply->row_to][curr_ply->column_to]] = no_piece;
493 color[locn[curr_ply->row_to][curr_ply->column_to]] = neutral;
494 if (curr_ply->taken_piece != no_piece && !curr_ply->enpassant){
495 board[locn[curr_ply->row_to][curr_ply->column_to]]
496 = curr_ply->taken_piece;
497 color[locn[curr_ply->row_to][curr_ply->column_to]]
498 = ((curr_ply->player==white)?black:white);
500 if (curr_ply->castle){
501 if (curr_ply->column_to == 6){
502 /* castling kingside */
503 board[locn[curr_ply->row_to][7]] = rook;
504 color[locn[curr_ply->row_to][7]] = curr_ply->player;
505 board[locn[curr_ply->row_to][5]] = no_piece;
506 color[locn[curr_ply->row_to][5]] = neutral;
507 } else {
508 /* castling queenside */
509 board[locn[curr_ply->row_to][0]] = rook;
510 color[locn[curr_ply->row_to][0]] = curr_ply->player;
511 board[locn[curr_ply->row_to][3]] = no_piece;
512 color[locn[curr_ply->row_to][3]] = neutral;
515 if (curr_ply->enpassant){
516 board[locn[curr_ply->row_from][curr_ply->column_to]] = pawn;
517 color[locn[curr_ply->row_from][curr_ply->column_to]]
518 = ((curr_ply->player==white)?black:white);
520 if (curr_ply->promotion){
521 board[locn[curr_ply->row_from][curr_ply->column_from]] = pawn;
522 color[locn[curr_ply->row_from][curr_ply->column_from]]
523 = curr_ply->player;
526 cb_drawboard();
527 break;
528 case COMMAND_NEXT:
529 /* apply the current move */
530 if (curr_ply->player == neutral){
531 rb->splash ( HZ*2 , "At the end of the game" );
532 break;
534 board[locn[curr_ply->row_to][curr_ply->column_to]]
535 = board[locn[curr_ply->row_from][curr_ply->column_from]];
536 color[locn[curr_ply->row_to][curr_ply->column_to]]
537 = color[locn[curr_ply->row_from][curr_ply->column_from]];
538 board[locn[curr_ply->row_from][curr_ply->column_from]] = no_piece;
539 color[locn[curr_ply->row_from][curr_ply->column_from]] = neutral;
540 if (curr_ply->castle){
541 if (curr_ply->column_to == 6){
542 /* castling kingside */
543 board[locn[curr_ply->row_to][5]] = rook;
544 color[locn[curr_ply->row_to][5]] = curr_ply->player;
545 board[locn[curr_ply->row_to][7]] = no_piece;
546 color[locn[curr_ply->row_to][7]] = neutral;
547 } else {
548 /* castling queenside */
549 board[locn[curr_ply->row_to][3]] = rook;
550 color[locn[curr_ply->row_to][3]] = curr_ply->player;
551 board[locn[curr_ply->row_to][0]] = no_piece;
552 color[locn[curr_ply->row_to][0]] = neutral;
555 if (curr_ply->enpassant){
556 board[locn[curr_ply->row_from][curr_ply->column_to]] = no_piece;
557 color[locn[curr_ply->row_from][curr_ply->column_to]] = neutral;
559 if (curr_ply->promotion){
560 board[locn[curr_ply->row_to][curr_ply->column_to]]
561 = curr_ply->promotion_piece;
562 color[locn[curr_ply->row_to][curr_ply->column_to]]
563 = curr_ply->player;
565 if (curr_ply->next_node != NULL){
566 curr_ply = curr_ply->next_node;
568 cb_drawboard();
569 break;
570 case COMMAND_RESTART:
571 GNUChess_Initialize();
572 cb_drawboard();
573 curr_ply = selected_game->first_ply;
574 case COMMAND_SELECT:
575 exit_game = true;
576 break;
577 case COMMAND_QUIT:
578 exit_viewer = true;
579 break;
581 } while (!exit_game && !exit_viewer);
582 } else {
583 rb->splash ( HZ*2 , "Error parsing game !");
585 } while (!exit_viewer);
588 /* ---- show menu ---- */
589 static int cb_menu(void)
591 int selection;
592 int result = 0;
593 bool menu_quit = false;
595 MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"New Game","Resume Game",
596 "Save Game", "Restore Game", "Quit");
598 while(!menu_quit)
600 switch(rb->do_menu(&menu, &selection, NULL, false))
602 case 0:
603 menu_quit = true;
604 result = COMMAND_RESTART;
605 break;
606 case 1:
607 result = COMMAND_RESUME;
608 menu_quit = true;
609 break;
610 case 2:
611 result = COMMAND_SAVE;
612 menu_quit = true;
613 break;
614 case 3:
615 result = COMMAND_RESTORE;
616 menu_quit = true;
617 break;
618 case 4:
619 result = COMMAND_QUIT;
620 menu_quit = true;
621 break;
624 return result;
627 /* ---- get a command in game mode ---- */
628 struct cb_command cb_getcommand (void) {
629 static short x = 4 , y = 3 ;
630 short c , r , l;
631 int button, lastbutton = BUTTON_NONE;
632 int marked = false , from_marked = false ;
633 short marked_x = 0 , marked_y = 0 ;
634 struct cb_command result = { 0, {0,0,0,0,0}, 0 };
636 cb_switch ( x , y );
637 /* main loop */
638 while ( true ) {
639 button = rb->button_get(true);
640 switch (button) {
641 #ifdef CB_RC_QUIT
642 case CB_RC_QUIT:
643 result.type = COMMAND_QUIT;
644 return result;
645 #endif
646 case CB_MENU:
647 result.type = cb_menu();
648 return result;
649 case CB_LEVEL:
650 result.type = COMMAND_LEVEL;
651 return result;
652 case CB_PLAY:
653 #ifdef CB_PLAY_PRE
654 if (lastbutton != CB_PLAY_PRE)
655 break;
656 #endif
657 result.type = COMMAND_PLAY;
658 return result;
659 case CB_UP:
660 if ( !from_marked ) cb_switch ( x , y );
661 y++;
662 if ( y == 8 ) {
663 y = 0;
664 x--;
665 if ( x < 0 ) x = 7;
667 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
668 from_marked = true ;
669 } else {
670 from_marked = false ;
671 cb_switch ( x , y );
673 break;
674 case CB_DOWN:
675 if ( !from_marked ) cb_switch ( x , y );
676 y--;
677 if ( y < 0 ) {
678 y = 7;
679 x++;
680 if ( x == 8 ) x = 0;
682 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
683 from_marked = true ;
684 } else {
685 from_marked = false ;
686 cb_switch ( x , y );
688 break;
689 case CB_LEFT:
690 if ( !from_marked ) cb_switch ( x , y );
691 x--;
692 if ( x < 0 ) {
693 x = 7;
694 y++;
695 if ( y == 8 ) y = 0;
697 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
698 from_marked = true ;
699 } else {
700 from_marked = false ;
701 cb_switch ( x , y );
703 break;
704 case CB_RIGHT:
705 if ( !from_marked ) cb_switch ( x , y );
706 x++;
707 if ( x == 8 ) {
708 x = 0;
709 y--;
710 if ( y < 0 ) y = 7;
712 if ( marked && ( marked_x == x ) && ( marked_y == y ) ) {
713 from_marked = true ;
714 } else {
715 from_marked = false ;
716 cb_switch ( x , y );
718 break;
719 case CB_SELECT:
720 #ifdef CB_SELECT_PRE
721 if (lastbutton != CB_SELECT_PRE)
722 break;
723 #endif
724 if ( !marked ) {
725 xy2cr ( x , y , &c , &r );
726 l = locn[r][c];
727 if ( ( color[l]!=computer ) && ( board[l]!=no_piece ) ) {
728 marked = true;
729 from_marked = true ;
730 marked_x = x;
731 marked_y = y;
733 } else {
734 if ( ( marked_x == x ) && ( marked_y == y ) ) {
735 marked = false;
736 from_marked = false;
737 } else {
738 xy2cr ( marked_x , marked_y , &c , &r );
739 result.mv_s[0] = 'a' + c;
740 result.mv_s[1] = '1' + r;
741 xy2cr ( x , y , &c , &r );
742 result.mv_s[2] = 'a' + c;
743 result.mv_s[3] = '1' + r;
744 result.mv_s[4] = '\00';
745 result.type = COMMAND_MOVE;
746 return result;
749 break;
751 if (button != BUTTON_NONE)
752 lastbutton = button;
757 /* ---- game main loop ---- */
758 void cb_play_game(void) {
759 struct cb_command command;
760 struct pgn_game_node *game;
761 char move_buffer[20];
763 /* init status */
764 bool exit = false;
766 /* load opening book, soon */
768 /* init board */
769 GNUChess_Initialize();
771 /* init PGN history data structures */
772 game = pgn_init_game(rb);
774 /* restore saved position, if saved */
775 cb_restoreposition();
776 /* TODO: save/restore the PGN history of unfinished games */
778 /* draw the board */
779 /* I don't like configscreens, start game inmediatly */
780 cb_drawboard();
782 while (!exit) {
783 if ( mate ) {
784 rb->splash ( HZ*3 , "Checkmate!" );
785 rb->button_get(true);
786 pgn_store_game(rb, game);
787 GNUChess_Initialize();
788 game = pgn_init_game(rb);
789 cb_drawboard();
791 command = cb_getcommand ();
792 switch (command.type) {
793 case COMMAND_MOVE:
794 if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) {
795 rb->splash ( HZ/2 , "Illegal move!" );
796 cb_drawboard();
797 } else {
798 cb_drawboard();
800 /* Add the ply to the PGN history (in algebraic notation) */
801 pgn_append_ply(rb, game, opponent, move_buffer, mate);
803 rb->splash ( 0 , "Thinking..." );
804 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
805 rb->cpu_boost ( true );
806 #endif
807 SelectMove ( computer , 0 , cb_wt_callback, move_buffer);
808 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
809 rb->cpu_boost ( false );
810 #endif
811 /* Add the ply to the PGN history (in algebraic notation) and check
812 * for the result of the game which is only calculated in SelectMove
814 if (move_buffer[0] != '\0'){
815 pgn_append_ply(rb, game, computer, move_buffer, mate);
816 } else {
817 pgn_set_result(rb, game, mate);
820 if ( wt_command == COMMAND_QUIT ) {
821 exit = true;
822 break;
824 cb_drawboard();
826 break;
827 #ifdef COMMAND_RESTART
828 case COMMAND_RESTART:
829 GNUChess_Initialize();
830 game = pgn_init_game(rb);
831 cb_drawboard();
832 break;
833 #endif
834 case COMMAND_RESUME:
835 cb_drawboard();
836 break;
837 case COMMAND_SAVE:
838 cb_saveposition();
839 cb_drawboard();
840 break;
841 case COMMAND_RESTORE:
842 /* watch out, it will reset the game if no previous game was saved! */
844 /* init board */
845 GNUChess_Initialize();
847 /* init PGN history data structures */
848 game = pgn_init_game(rb);
850 /* restore saved position, if saved */
851 cb_restoreposition();
853 cb_drawboard();
854 break;
855 case COMMAND_PLAY:
856 if (opponent == white) {
857 opponent = black;
858 computer = white;
859 } else {
860 opponent = white;
861 computer = black;
863 rb->splash ( 0 , "Thinking..." );
864 ElapsedTime(1);
865 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
866 rb->cpu_boost ( true );
867 #endif
868 SelectMove ( computer , 0 , cb_wt_callback , move_buffer );
869 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
870 rb->cpu_boost ( false );
871 #endif
873 /* Add the ply to the PGN history (in algebraic notation) and check
874 * for the result of the game which is only calculated in SelectMove
876 if (move_buffer[0] != '\0'){
877 pgn_append_ply(rb, game, computer, move_buffer, mate);
878 } else {
879 pgn_set_result(rb, game, mate);
882 if ( wt_command == COMMAND_QUIT ) {
883 exit = true;
884 break;
886 cb_drawboard();
887 break;
888 case COMMAND_LEVEL:
889 cb_levelup ( );
890 cb_drawboard();
891 break;
892 case COMMAND_QUIT:
893 exit = true;
894 break;
898 cb_saveposition();
899 /* TODO: save/restore the PGN history of unfinished games */
900 rb->lcd_setfont(FONT_UI);
904 /*****************************************************************************
905 * plugin entry point.
906 ******************************************************************************/
907 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) {
909 /* plugin init */
911 rb = api;
912 #if LCD_DEPTH > 1
913 rb->lcd_set_backdrop(NULL);
914 #endif
916 /* end of plugin init */
918 /* if the plugin was invoked as a viewer, parse the file and show the game list
919 * else, start playing a game
921 if (parameter != NULL) {
922 cb_start_viewer((char *)parameter);
923 } else {
924 cb_play_game();
927 return PLUGIN_OK;
930 #endif /* HAVE_LCD_BITMAP */