| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2006 Miguel A. Arévalo |
| * Color graphics from eboard |
| * GNUChess v2 chess engine Copyright (c) 1988 John Stanback |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include "plugin.h" |
| |
| #if (MEMORYSIZE > 8) /* Lowmem doesn't have playback in chessbox */ |
| #define HAVE_PLAYBACK_CONTROL |
| #endif |
| /*#define CHESSBOX_SAVE_FILE_DBG PLUGIN_GAMES_DATA_DIR "/chessbox_dbg.save"*/ |
| #ifdef HAVE_PLAYBACK_CONTROL |
| #include "lib/playback_control.h" |
| #endif |
| |
| #include "gnuchess.h" |
| #include "opening.h" |
| #include "chessbox_pgn.h" |
| |
| /* type definitions */ |
| struct cb_command { |
| int type; |
| char mv_s[5]; |
| unsigned short mv; |
| }; |
| |
| /* External bitmaps */ |
| extern const fb_data chessbox_pieces[]; |
| |
| |
| |
| |
| /* Tile size defined by the assigned bitmap */ |
| #include "pluginbitmaps/chessbox_pieces.h" |
| #define TILE_WIDTH BMPWIDTH_chessbox_pieces |
| #define TILE_HEIGHT (BMPHEIGHT_chessbox_pieces/26) |
| |
| /* Calculate Offsets */ |
| #define XOFS ((LCD_WIDTH-8*TILE_WIDTH)/2) |
| #define YOFS ((LCD_HEIGHT-8*TILE_HEIGHT)/2) |
| |
| /* save files */ |
| #define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/chessbox.save" |
| |
| /* commands enum */ |
| #define COMMAND_NOP 0 |
| #define COMMAND_MOVE 1 |
| #define COMMAND_PLAY 2 |
| #define COMMAND_LEVEL 3 |
| #define COMMAND_RESTART 4 |
| #define COMMAND_QUIT 5 |
| #define COMMAND_MENU 6 |
| #define COMMAND_SAVE 7 |
| #define COMMAND_RESTORE 8 |
| #define COMMAND_RESUME 9 |
| #define COMMAND_SELECT 10 |
| #define COMMAND_NEXT 11 |
| #define COMMAND_PREV 12 |
| |
| short plugin_mode; |
| |
| /* level+1's string */ |
| const char *level_string[] = { ID2P(LANG_CHESSBOX_LEVEL_1) , |
| ID2P(LANG_CHESSBOX_LEVEL_2) , |
| ID2P(LANG_CHESSBOX_LEVEL_3) , |
| ID2P(LANG_CHESSBOX_LEVEL_4) , |
| ID2P(LANG_CHESSBOX_LEVEL_5) , |
| ID2P(LANG_CHESSBOX_LEVEL_6) , |
| ID2P(LANG_CHESSBOX_LEVEL_7) , |
| ID2P(LANG_CHESSBOX_LEVEL_8) , |
| ID2P(LANG_CHESSBOX_LEVEL_9) , |
| ID2P(LANG_CHESSBOX_LEVEL_10) }; |
| |
| /* "While thinking" command */ |
| int wt_command = COMMAND_NOP; |
| |
| /* System event id */ |
| static long cb_sysevent = 0; |
| |
| /* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */ |
| static void xy2cr ( short x, short y, short *c, short *r ) { |
| if (computer == black ) { |
| *c = x ; |
| *r = y ; |
| } else { |
| *c = 7 - x ; |
| *r = 7 - y ; |
| } |
| } |
| |
| /* ---- get physical x y for a board column and row (e2 f.e.) ---- */ |
| static void cr2xy ( short c, short r, short *x, short *y ) { |
| if ( computer == black ) { |
| *x = c ; |
| *y = r ; |
| } else { |
| *x = 7 - c ; |
| *y = 7 - r ; |
| } |
| } |
| |
| /* ---- Draw a complete board ---- */ |
| static void cb_drawboard (void) { |
| short r , c , x , y ; |
| short l , piece , p_color ; |
| int b_color=1; |
| |
| rb->lcd_clear_display(); |
| |
| for (r = 0; r < 8; r++) { |
| for (c = 0; c < 8; c++) { |
| l = locn[r][c]; |
| piece = board[l] ; |
| p_color = color[l] ; |
| cr2xy ( c , r , &x , &y ); |
| if ( piece == no_piece ) { |
| rb->lcd_bitmap_part ( chessbox_pieces , 0 , |
| TILE_HEIGHT * b_color , |
| STRIDE( SCREEN_MAIN, |
| BMPWIDTH_chessbox_pieces, |
| BMPHEIGHT_chessbox_pieces) , |
| XOFS + x*TILE_WIDTH , |
| YOFS + ( 7 - y )*TILE_HEIGHT , |
| TILE_WIDTH , |
| TILE_HEIGHT ); |
| } else { |
| rb->lcd_bitmap_part ( chessbox_pieces , |
| 0 , |
| 2 * TILE_HEIGHT + |
| 4 * TILE_HEIGHT * ( piece - 1 ) + |
| 2 * TILE_HEIGHT * p_color + |
| TILE_HEIGHT * b_color , |
| STRIDE( SCREEN_MAIN, |
| BMPWIDTH_chessbox_pieces, |
| BMPHEIGHT_chessbox_pieces) , |
| XOFS + x*TILE_WIDTH , |
| YOFS + (7 - y)*TILE_HEIGHT , |
| TILE_WIDTH , |
| TILE_HEIGHT ); |
| } |
| b_color = (b_color == 1) ? 0 : 1 ; |
| } |
| b_color = (b_color == 1) ? 0 : 1 ; |
| } |
| |
| /* draw board limits */ |
| #if (LCD_WIDTH > TILE_WIDTH*8) && (LCD_HEIGHT > TILE_HEIGHT*8) |
| rb->lcd_drawrect(XOFS - 1, YOFS - 1, TILE_WIDTH*8 + 2, TILE_HEIGHT*8 + 2); |
| #elif LCD_WIDTH > TILE_WIDTH*8 |
| rb->lcd_vline(XOFS - 1, 0, LCD_HEIGHT - 1); |
| rb->lcd_vline(XOFS + 8*TILE_WIDTH, 0, LCD_HEIGHT - 1); |
| #elif LCD_HEIGHT > TILE_HEIGHT*8 |
| rb->lcd_hline(0, LCD_WIDTH - 1, YOFS - 1); |
| rb->lcd_hline(0, LCD_WIDTH - 1, YOFS + TILE_HEIGHT*8); |
| #endif |
| |
| rb->lcd_update(); |
| } |
| |
| static short oldx, oldy = 0; |
| void cb_talk(short x, short y) |
| { |
| if (x != oldx || y != oldy) { |
| short c, r; |
| short l, piece, p_color; |
| |
| rb->talk_shutup(); |
| cr2xy(x, y, &c, &r); |
| l = locn[r][c]; |
| piece = board[l]; |
| p_color = color[l]; |
| if (piece != no_piece) { |
| rb->talk_id (VOICE_WHITE + p_color, true); |
| if (piece >= pawn && piece <= king) { |
| rb->talk_id (VOICE_PAWN + piece - 1, true); |
| } |
| } |
| rb->talk_id (VOICE_CHAR_A + c, true); |
| rb->talk_id (VOICE_ONE + r, true); |
| oldx = x; |
| oldy = y; |
| } |
| } |
| |
| /* ---- Switch mark on board ---- */ |
| static void cb_switch ( short x , short y ) { |
| if (rb->global_settings->talk_menu) |
| cb_talk(x, y); |
| rb->lcd_set_drawmode ( DRMODE_COMPLEMENT ); |
| rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 , |
| YOFS + ( 7 - y )*TILE_HEIGHT +1 , |
| TILE_WIDTH-2 , TILE_HEIGHT-2 ); |
| rb->lcd_update(); |
| rb->lcd_set_drawmode ( DRMODE_SOLID ); |
| } |
| |
| /* ---- callback for capturing interaction while thinking ---- */ |
| static void cb_wt_callback ( void ) { |
| int button = BUTTON_NONE; |
| |
| wt_command = COMMAND_NOP; |
| button = rb->button_get(false); |
| switch (button) { |
| case SYS_POWEROFF: |
| cb_sysevent = button; |
| #ifdef CB_RC_QUIT |
| case CB_RC_QUIT: |
| #endif |
| wt_command = COMMAND_QUIT; |
| timeout = true; |
| break; |
| case CB_MENU: |
| wt_command = COMMAND_MENU; |
| timeout = true; |
| break; |
| case CB_PLAY: |
| wt_command = COMMAND_PLAY; |
| timeout = true; |
| break; |
| } |
| } |
| |
| /* ---- set playing parameters depending on level ---- */ |
| static void cb_setlevel ( int lev ) { |
| Level = (lev > 7) ? 7 : ( (lev < 1) ? 1 : lev ) ; |
| switch (Level) { |
| case 1 : |
| TCmoves = 60; |
| TCminutes = 5; |
| break; |
| case 2 : |
| TCmoves = 60; |
| TCminutes = 15; |
| break; |
| case 3 : |
| TCmoves = 60; |
| TCminutes = 30; |
| break; |
| case 4 : |
| TCmoves = 40; |
| TCminutes = 30; |
| break; |
| case 5 : |
| TCmoves = 40; |
| TCminutes = 60; |
| break; |
| case 6 : |
| TCmoves = 40; |
| TCminutes = 120; |
| break; |
| case 7 : |
| TCmoves = 40; |
| TCminutes = 240; |
| break; |
| case 8 : |
| TCmoves = 1; |
| TCminutes = 15; |
| break; |
| case 9 : |
| TCmoves = 1; |
| TCminutes = 60; |
| break; |
| case 10 : |
| TCmoves = 1; |
| TCminutes = 600; |
| break; |
| } |
| TCflag = (TCmoves > 1); |
| SetTimeControl(); |
| } |
| |
| /* ---- increase playing level ---- */ |
| static void cb_levelup ( void ) { |
| if ( Level == 7 ) |
| cb_setlevel ( 1 ); |
| else |
| cb_setlevel ( Level+1 ); |
| rb->splash ( HZ/2 , level_string[Level-1] ); |
| }; |
| |
| #ifdef CHESSBOX_SAVE_FILE_DBG |
| /* Save a debug file with names, variables, and sizes */ |
| static void cb_saveposition_dbg ( void ) |
| { |
| int fd; |
| short sq,i,c; |
| unsigned short temp; |
| char buf[32]="\0"; |
| int ch_ct = 0; |
| |
| rb->splash ( 0 , "Saving debug" ); |
| fd = rb->open(CHESSBOX_SAVE_FILE_DBG, O_WRONLY|O_CREAT, 0666); |
| ch_ct = rb->snprintf(buf,31,"computer = %d, %d bytes\n",computer+1, |
| sizeof(computer)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"opponent = %d, %d bytes\n",opponent+1, |
| sizeof(opponent)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"Game50 = %d, %d bytes\n",Game50, |
| sizeof(Game50)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"CastldWht = %d, %d bytes\n",castld[white], |
| sizeof(castld[white])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"CastldBlk = %d, %d bytes\n",castld[black], |
| sizeof(castld[black])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"KngMovedWht = %d, %d bytes\n",kingmoved[white], |
| sizeof(kingmoved[white])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"KngMovedBlk = %d, %d bytes\n",kingmoved[black], |
| sizeof(kingmoved[black])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"WithBook = %d, %d bytes\n",withbook, |
| sizeof(withbook)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"Lvl = %ld, %d bytes\n",Level, |
| sizeof(Level)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"TCflag = %d, %d bytes\n",TCflag, |
| sizeof(TCflag)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"OpTime = %d, %d bytes\n",OperatorTime, |
| sizeof(OperatorTime)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"TmCtlClkWht = %ld, %d bytes\n", |
| TimeControl.clock[white], sizeof(TimeControl.clock[white])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"TmCtlClkBlk = %ld, %d bytes\n", |
| TimeControl.clock[black], sizeof(TimeControl.clock[black])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"TmCtlMovesWht = %d, %d bytes\n", |
| TimeControl.moves[white], sizeof(TimeControl.moves[white])); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"TmCtlMovesBlk = %d, %d bytes\n", |
| TimeControl.moves[black], sizeof(TimeControl.moves[black])); |
| rb->write(fd, buf, ch_ct); |
| for (sq = 0; sq < 64; sq++) { |
| if (color[sq] == neutral) c = 0; else c = color[sq]+1; |
| temp = 256*board[sq] + c ; |
| ch_ct = rb->snprintf(buf,31,"sq %02d = %d, %d bytes\n",sq, temp, |
| sizeof(temp)); |
| rb->write(fd, buf, ch_ct); |
| } |
| for (i = 0; i <= GameCnt; i++) { |
| ch_ct = rb->snprintf(buf,31,"GameCt %d, %d bytes\n",i, |
| sizeof(GameCnt)); |
| rb->write(fd, buf, ch_ct); |
| if (GameList[i].color == neutral) |
| { |
| c = 0; |
| ch_ct = rb->snprintf(buf,31,"color = %d, %d bytes\n",c, |
| sizeof(c)); |
| rb->write(fd, buf, ch_ct); |
| } |
| else |
| c = GameList[i].color + 1; |
| ch_ct = rb->snprintf(buf,31,"gmove = %d, %d bytes\n",GameList[i].gmove, |
| sizeof(GameList[i].gmove)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"score = %d, %d bytes\n",GameList[i].score, |
| sizeof(GameList[i].score)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"depth = %d, %d bytes\n",GameList[i].depth, |
| sizeof(GameList[i].depth)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"nodes = %ld, %d bytes\n",GameList[i].nodes, |
| sizeof(GameList[i].nodes)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"time = %d, %d bytes\n",GameList[i].time, |
| sizeof(GameList[i].time)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"piece = %d, %d bytes\n",GameList[i].piece, |
| sizeof(GameList[i].piece)); |
| rb->write(fd, buf, ch_ct); |
| ch_ct = rb->snprintf(buf,31,"color = %d, %d bytes\n",c,sizeof(c)); |
| rb->write(fd, buf, ch_ct); |
| } |
| rb->close(fd); |
| |
| } |
| #endif |
| |
| /* ---- Save current position ---- */ |
| static void cb_saveposition ( void ) { |
| int fd; |
| short sq,i,c; |
| unsigned short temp; |
| #ifdef CHESSBOX_SAVE_FILE_DBG |
| cb_saveposition_dbg(); |
| #endif |
| rb->splash ( 0 , ID2P(LANG_CHESSBOX_SAVING_POSITION) ); |
| |
| fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666); |
| |
| computer++; rb->write(fd, &(computer), sizeof(computer)); computer--; |
| opponent++; rb->write(fd, &(opponent), sizeof(opponent)); opponent--; |
| rb->write(fd, &(Game50), sizeof(Game50)); |
| |
| rb->write(fd, &(castld[white]), sizeof(castld[white])); |
| rb->write(fd, &(castld[black]), sizeof(castld[black])); |
| rb->write(fd, &(kingmoved[white]), sizeof(kingmoved[white])); |
| rb->write(fd, &(kingmoved[black]), sizeof(kingmoved[black])); |
| |
| rb->write(fd, &(withbook), sizeof(withbook)); |
| rb->write(fd, &(Level), sizeof(Level)); |
| rb->write(fd, &(TCflag), sizeof(TCflag)); |
| rb->write(fd, &(OperatorTime), sizeof(OperatorTime)); |
| |
| rb->write(fd, &(TimeControl.clock[white]), |
| sizeof(TimeControl.clock[white]) ); |
| rb->write(fd, &(TimeControl.clock[black]), |
| sizeof(TimeControl.clock[black]) ); |
| rb->write(fd, &(TimeControl.moves[white]), |
| sizeof(TimeControl.moves[white]) ); |
| rb->write(fd, &(TimeControl.moves[black]), |
| sizeof(TimeControl.moves[black]) ); |
| for (sq = 0; sq < 64; sq++) { |
| if (color[sq] == neutral) c = 0; else c = color[sq]+1; |
| temp = 256*board[sq] + c ; |
| rb->write(fd, &(temp), sizeof(temp)); |
| } |
| for (i = 0; i <= GameCnt; i++) { |
| if (GameList[i].color == neutral) |
| c = 0; |
| else |
| c = GameList[i].color + 1; |
| rb->write(fd, &(GameList[i].gmove), sizeof(GameList[i].gmove)); |
| rb->write(fd, &(GameList[i].score), sizeof(GameList[i].score)); |
| rb->write(fd, &(GameList[i].depth), sizeof(GameList[i].depth)); |
| rb->write(fd, &(GameList[i].nodes), sizeof(GameList[i].nodes)); |
| rb->write(fd, &(GameList[i].time), sizeof(GameList[i].time)); |
| rb->write(fd, &(GameList[i].piece), sizeof(GameList[i].piece)); |
| rb->write(fd, &(c), sizeof(c)); |
| } |
| rb->close(fd); |
| } |
| |
| /* ---- Restore saved position ---- */ |
| static void cb_restoreposition ( void ) { |
| int fd; |
| short sq; |
| unsigned short m; |
| |
| if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) { |
| rb->splash ( 0 , ID2P(LANG_CHESSBOX_LOADING_POSITION) ); |
| rb->read(fd, &(computer), sizeof(computer)); |
| rb->read(fd, &(opponent), sizeof(opponent)); |
| rb->read(fd, &(Game50), sizeof(Game50)); |
| |
| rb->read(fd, &(castld[white]), sizeof(castld[white])); |
| rb->read(fd, &(castld[black]), sizeof(castld[black])); |
| rb->read(fd, &(kingmoved[white]), sizeof(kingmoved[white])); |
| rb->read(fd, &(kingmoved[black]), sizeof(kingmoved[black])); |
| |
| rb->read(fd, &(withbook), sizeof(withbook)); |
| rb->read(fd, &(Level), sizeof(Level)); |
| rb->read(fd, &(TCflag), sizeof(TCflag)); |
| rb->read(fd, &(OperatorTime), sizeof(OperatorTime)); |
| |
| rb->read(fd, &(TimeControl.clock[white]), |
| sizeof(TimeControl.clock[white])); |
| rb->read(fd, &(TimeControl.clock[black]), |
| sizeof(TimeControl.clock[black])); |
| rb->read(fd, &(TimeControl.moves[white]), |
| sizeof(TimeControl.moves[white])); |
| rb->read(fd, &(TimeControl.moves[black]), |
| sizeof(TimeControl.moves[black])); |
| for (sq = 0; sq < 64; sq++) { |
| rb->read(fd, &(m), sizeof(m)); |
| board[sq] = (m >> 8); color[sq] = (m & 0xFF); |
| if (color[sq] == 0) |
| color[sq] = neutral; |
| else |
| --color[sq]; |
| } |
| GameCnt = MAX_GAME_CNT - 1; /*uchar rollsover to 0 after 255*/ |
| while (rb->read(fd, &(GameList[++GameCnt].gmove), |
| sizeof(GameList[GameCnt].gmove)) > 0) { |
| rb->read(fd, &(GameList[GameCnt].score), |
| sizeof(GameList[GameCnt].score)); |
| rb->read(fd, &(GameList[GameCnt].depth), |
| sizeof(GameList[GameCnt].depth)); |
| rb->read(fd, &(GameList[GameCnt].nodes), |
| sizeof(GameList[GameCnt].nodes)); |
| rb->read(fd, &(GameList[GameCnt].time), |
| sizeof(GameList[GameCnt].time)); |
| rb->read(fd, &(GameList[GameCnt].piece), |
| sizeof(GameList[GameCnt].piece)); |
| rb->read(fd, &(GameList[GameCnt].color), |
| sizeof(GameList[GameCnt].color)); |
| if (GameList[GameCnt].color == 0) |
| GameList[GameCnt].color = neutral; |
| else |
| --GameList[GameCnt].color; |
| } |
| GameCnt--; |
| if (TimeControl.clock[white] > 0) |
| TCflag = true; |
| computer--; opponent--; |
| } |
| rb->close(fd); |
| cb_setlevel(Level); |
| InitializeStats(); |
| Sdepth = 0; |
| } |
| |
| /* ---- show menu in viewer mode---- */ |
| static int cb_menu_viewer(void) |
| { |
| int selection; |
| int result = 0; |
| bool menu_quit = false; |
| |
| MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL, |
| ID2P(LANG_CHESSBOX_MENU_RESTART_GAME), |
| ID2P(LANG_CHESSBOX_MENU_SELECT_OTHER_GAME), |
| ID2P(LANG_MENU_QUIT)); |
| |
| while(!menu_quit) |
| { |
| switch(rb->do_menu(&menu, &selection, NULL, false)) |
| { |
| case 0: |
| menu_quit = true; |
| result = COMMAND_RESTART; |
| break; |
| case 1: |
| result = COMMAND_SELECT; |
| menu_quit = true; |
| break; |
| case 2: |
| result = COMMAND_QUIT; |
| menu_quit = true; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| /* ---- get a command in game mode ---- */ |
| static struct cb_command cb_get_viewer_command (void) { |
| int button; |
| struct cb_command result = { 0, {0,0,0,0,0}, 0 }; |
| |
| /* main loop */ |
| while ( true ) { |
| button = rb->button_get(true); |
| switch (button) { |
| case SYS_POWEROFF: |
| cb_sysevent = button; |
| #ifdef CB_RC_QUIT |
| case CB_RC_QUIT: |
| #endif |
| result.type = COMMAND_QUIT; |
| return result; |
| #ifdef CB_RESTART |
| case CB_RESTART: |
| result.type = COMMAND_RESTART; |
| return result; |
| #endif |
| case CB_MENU: |
| result.type = cb_menu_viewer(); |
| return result; |
| case CB_LEFT: |
| result.type = COMMAND_PREV; |
| return result; |
| case CB_RIGHT: |
| result.type = COMMAND_NEXT; |
| return result; |
| } |
| } |
| |
| } |
| |
| /* ---- viewer main loop ---- */ |
| static void cb_start_viewer(char* filename){ |
| struct pgn_game_node *first_game, *selected_game; |
| struct pgn_ply_node *curr_ply; |
| bool exit_game = false; |
| bool exit_viewer = false; |
| struct cb_command command; |
| |
| first_game = pgn_list_games(filename); |
| if (first_game == NULL){ |
| rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_NO_GAMES) ); |
| return; |
| } |
| |
| do { |
| selected_game = pgn_show_game_list(first_game); |
| if (selected_game == NULL){ |
| break; |
| } |
| |
| pgn_parse_game(filename, selected_game); |
| if (selected_game->first_ply != NULL) { |
| |
| /* init board */ |
| GNUChess_Initialize(); |
| |
| /* draw the board */ |
| cb_drawboard(); |
| |
| curr_ply = selected_game->first_ply; |
| exit_game = false; |
| |
| do { |
| command = cb_get_viewer_command (); |
| switch (command.type) { |
| case COMMAND_PREV: |
| /* unapply the previous ply */ |
| if (curr_ply->prev_node != NULL){ |
| curr_ply = curr_ply->prev_node; |
| } else { |
| rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_GAME_BEGINNING) ); |
| break; |
| } |
| board[locn[curr_ply->row_from][curr_ply->column_from]] |
| = board[locn[curr_ply->row_to][curr_ply->column_to]]; |
| color[locn[curr_ply->row_from][curr_ply->column_from]] |
| = color[locn[curr_ply->row_to][curr_ply->column_to]]; |
| board[locn[curr_ply->row_to][curr_ply->column_to]] = no_piece; |
| color[locn[curr_ply->row_to][curr_ply->column_to]] = neutral; |
| if (curr_ply->taken_piece != no_piece && !curr_ply->enpassant){ |
| board[locn[curr_ply->row_to][curr_ply->column_to]] |
| = curr_ply->taken_piece; |
| color[locn[curr_ply->row_to][curr_ply->column_to]] |
| = ((curr_ply->player==white)?black:white); |
| } |
| if (curr_ply->castle){ |
| if (curr_ply->column_to == 6){ |
| /* castling kingside */ |
| board[locn[curr_ply->row_to][7]] = rook; |
| color[locn[curr_ply->row_to][7]] = curr_ply->player; |
| board[locn[curr_ply->row_to][5]] = no_piece; |
| color[locn[curr_ply->row_to][5]] = neutral; |
| } else { |
| /* castling queenside */ |
| board[locn[curr_ply->row_to][0]] = rook; |
| color[locn[curr_ply->row_to][0]] = curr_ply->player; |
| board[locn[curr_ply->row_to][3]] = no_piece; |
| color[locn[curr_ply->row_to][3]] = neutral; |
| } |
| } |
| if (curr_ply->enpassant){ |
| board[locn[curr_ply->row_from][curr_ply->column_to]] = pawn; |
| color[locn[curr_ply->row_from][curr_ply->column_to]] |
| = ((curr_ply->player==white)?black:white); |
| } |
| if (curr_ply->promotion){ |
| board[locn[curr_ply->row_from][curr_ply->column_from]] = pawn; |
| color[locn[curr_ply->row_from][curr_ply->column_from]] |
| = curr_ply->player; |
| } |
| |
| cb_drawboard(); |
| break; |
| case COMMAND_NEXT: |
| /* apply the current move */ |
| if (curr_ply->player == neutral){ |
| rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_GAME_END) ); |
| break; |
| } |
| if (rb->global_settings->talk_menu) { |
| rb->talk_id (VOICE_WHITE + curr_ply->player, false); |
| if (curr_ply->castle){ |
| rb->talk_id (VOICE_CHESSBOX_CASTLE, true); |
| if (curr_ply->column_to == 6){ |
| rb->talk_id (VOICE_CHESSBOX_KINGSIDE, true); |
| } else { |
| rb->talk_id (VOICE_CHESSBOX_QUEENSIDE, true); |
| } |
| } else { |
| rb->talk_id (VOICE_PAWN + |
| board[locn[curr_ply->row_from] |
| [curr_ply->column_from]] |
| - 1, true); |
| rb->talk_id (VOICE_CHAR_A + curr_ply->column_from, |
| true); |
| rb->talk_id (VOICE_ONE + curr_ply->row_from, true); |
| if (board[locn[curr_ply->row_to] |
| [curr_ply->column_to]] != no_piece) { |
| rb->talk_id (VOICE_CHESSBOX_CAPTURES, true); |
| rb->talk_id (VOICE_PAWN + |
| board[locn[curr_ply->row_to] |
| [curr_ply->column_to]] |
| - 1, true); |
| } |
| rb->talk_id (VOICE_CHAR_A + curr_ply->column_to, |
| true); |
| rb->talk_id (VOICE_ONE + curr_ply->row_to, true); |
| } |
| } |
| board[locn[curr_ply->row_to][curr_ply->column_to]] |
| = board[locn[curr_ply->row_from][curr_ply->column_from]]; |
| color[locn[curr_ply->row_to][curr_ply->column_to]] |
| = color[locn[curr_ply->row_from][curr_ply->column_from]]; |
| board[locn[curr_ply->row_from][curr_ply->column_from]] = no_piece; |
| color[locn[curr_ply->row_from][curr_ply->column_from]] = neutral; |
| if (curr_ply->castle){ |
| if (curr_ply->column_to == 6){ |
| /* castling kingside */ |
| board[locn[curr_ply->row_to][5]] = rook; |
| color[locn[curr_ply->row_to][5]] = curr_ply->player; |
| board[locn[curr_ply->row_to][7]] = no_piece; |
| color[locn[curr_ply->row_to][7]] = neutral; |
| } else { |
| /* castling queenside */ |
| board[locn[curr_ply->row_to][3]] = rook; |
| color[locn[curr_ply->row_to][3]] = curr_ply->player; |
| board[locn[curr_ply->row_to][0]] = no_piece; |
| color[locn[curr_ply->row_to][0]] = neutral; |
| } |
| } |
| if (curr_ply->enpassant){ |
| board[locn[curr_ply->row_from][curr_ply->column_to]] = no_piece; |
| color[locn[curr_ply->row_from][curr_ply->column_to]] = neutral; |
| } |
| if (curr_ply->promotion){ |
| if (rb->global_settings->talk_menu) |
| rb->talk_id (VOICE_PAWN + |
| curr_ply->promotion_piece - 1, |
| true); |
| board[locn[curr_ply->row_to][curr_ply->column_to]] |
| = curr_ply->promotion_piece; |
| color[locn[curr_ply->row_to][curr_ply->column_to]] |
| = curr_ply->player; |
| } |
| if (curr_ply->next_node != NULL){ |
| curr_ply = curr_ply->next_node; |
| } |
| cb_drawboard(); |
| break; |
| case COMMAND_RESTART: |
| GNUChess_Initialize(); |
| cb_drawboard(); |
| curr_ply = selected_game->first_ply; |
| break; |
| case COMMAND_SELECT: |
| exit_game = true; |
| break; |
| case COMMAND_QUIT: |
| exit_viewer = true; |
| break; |
| } |
| } while (!exit_game && !exit_viewer); |
| } else { |
| rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_PGN_PARSE_ERROR)); |
| } |
| } while (!exit_viewer); |
| } |
| |
| /* ---- show menu ---- */ |
| static int cb_menu(void) |
| { |
| int selection; |
| int result = 0; |
| bool menu_quit = false; |
| |
| MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL, |
| ID2P(LANG_CHESSBOX_MENU_NEW_GAME), |
| ID2P(LANG_CHESSBOX_MENU_RESUME_GAME), |
| ID2P(LANG_CHESSBOX_MENU_SAVE_GAME), |
| ID2P(LANG_CHESSBOX_MENU_RESTORE_GAME), |
| #ifdef HAVE_PLAYBACK_CONTROL |
| ID2P(LANG_PLAYBACK_CONTROL), |
| #endif |
| ID2P(LANG_MENU_QUIT)); |
| |
| while(!menu_quit) |
| { |
| switch(rb->do_menu(&menu, &selection, NULL, false)) |
| { |
| case 0: |
| menu_quit = true; |
| result = COMMAND_RESTART; |
| break; |
| case 1: |
| result = COMMAND_RESUME; |
| menu_quit = true; |
| break; |
| case 2: |
| result = COMMAND_SAVE; |
| menu_quit = true; |
| break; |
| case 3: |
| result = COMMAND_RESTORE; |
| menu_quit = true; |
| break; |
| case 4: |
| #ifdef HAVE_PLAYBACK_CONTROL |
| playback_control(NULL); |
| break; |
| case 5: |
| #endif |
| result = COMMAND_QUIT; |
| menu_quit = true; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| /* ---- get a command in game mode ---- */ |
| static struct cb_command cb_getcommand (void) { |
| static short x = 4 , y = 3 ; |
| short c , r , l; |
| int button; |
| #if defined(CB_PLAY_PRE) || defined(CB_SELECT_PRE) |
| int lastbutton = BUTTON_NONE; |
| #endif |
| int marked = false , from_marked = false ; |
| short marked_x = 0 , marked_y = 0 ; |
| struct cb_command result = { 0, {0,0,0,0,0}, 0 }; |
| |
| cb_switch ( x , y ); |
| /* main loop */ |
| while ( true ) { |
| button = rb->button_get(true); |
| switch (button) { |
| case SYS_POWEROFF: |
| cb_sysevent = button; |
| #ifdef CB_RC_QUIT |
| case CB_RC_QUIT: |
| #endif |
| result.type = COMMAND_QUIT; |
| return result; |
| #ifdef CB_RESTART |
| case CB_RESTART: |
| result.type = COMMAND_RESTART; |
| return result; |
| #endif |
| case CB_MENU: |
| result.type = cb_menu(); |
| return result; |
| case CB_LEVEL: |
| result.type = COMMAND_LEVEL; |
| return result; |
| case CB_PLAY: |
| #ifdef CB_PLAY_PRE |
| if (lastbutton != CB_PLAY_PRE) |
| break; |
| /* fallthrough */ |
| #endif |
| #ifdef CB_PLAY_ALT |
| case CB_PLAY_ALT: |
| #endif |
| result.type = COMMAND_PLAY; |
| return result; |
| case CB_UP: |
| #ifdef CB_SCROLL_UP |
| case CB_SCROLL_UP: |
| #endif |
| if ( !from_marked ) cb_switch ( x , y ); |
| y++; |
| if ( y == 8 ) { |
| y = 0; |
| x--; |
| if ( x < 0 ) x = 7; |
| } |
| if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { |
| from_marked = true ; |
| if (rb->global_settings->talk_menu) { |
| cb_talk(x, y); |
| rb->talk_id(VOICE_MARKED, true); |
| } |
| } else { |
| from_marked = false ; |
| cb_switch ( x , y ); |
| } |
| break; |
| case CB_DOWN: |
| #ifdef CB_SCROLL_DOWN |
| case CB_SCROLL_DOWN: |
| #endif |
| if ( !from_marked ) cb_switch ( x , y ); |
| y--; |
| if ( y < 0 ) { |
| y = 7; |
| x++; |
| if ( x == 8 ) x = 0; |
| } |
| if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { |
| from_marked = true ; |
| if (rb->global_settings->talk_menu) { |
| cb_talk(x, y); |
| rb->talk_id(VOICE_MARKED, true); |
| } |
| } else { |
| from_marked = false ; |
| cb_switch ( x , y ); |
| } |
| break; |
| case CB_LEFT: |
| #ifdef CB_SCROLL_LEFT |
| case CB_SCROLL_LEFT: |
| #endif |
| if ( !from_marked ) cb_switch ( x , y ); |
| x--; |
| if ( x < 0 ) { |
| x = 7; |
| y++; |
| if ( y == 8 ) y = 0; |
| } |
| if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { |
| from_marked = true ; |
| if (rb->global_settings->talk_menu) { |
| cb_talk(x, y); |
| rb->talk_id(VOICE_MARKED, true); |
| } |
| } else { |
| from_marked = false ; |
| cb_switch ( x , y ); |
| } |
| break; |
| case CB_RIGHT: |
| #ifdef CB_SCROLL_RIGHT |
| case CB_SCROLL_RIGHT: |
| #endif |
| if ( !from_marked ) cb_switch ( x , y ); |
| x++; |
| if ( x == 8 ) { |
| x = 0; |
| y--; |
| if ( y < 0 ) y = 7; |
| } |
| if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { |
| from_marked = true ; |
| if (rb->global_settings->talk_menu) { |
| cb_talk(x, y); |
| rb->talk_id(VOICE_MARKED, true); |
| } |
| } else { |
| from_marked = false ; |
| cb_switch ( x , y ); |
| } |
| break; |
| case CB_SELECT: |
| #ifdef CB_SELECT_PRE |
| if (lastbutton != CB_SELECT_PRE) |
| break; |
| #endif |
| if ( !marked ) { |
| xy2cr ( x , y , &c , &r ); |
| l = locn[r][c]; |
| if ( ( color[l]!=computer ) && ( board[l]!=no_piece ) ) { |
| marked = true; |
| from_marked = true ; |
| marked_x = x; |
| marked_y = y; |
| if (rb->global_settings->talk_menu) |
| rb->talk_id(VOICE_MARKED, false); |
| } |
| } else { |
| if ( ( marked_x == x ) && ( marked_y == y ) ) { |
| marked = false; |
| from_marked = false; |
| if (rb->global_settings->talk_menu) |
| rb->talk_id(VOICE_UNMARKED, false); |
| } else { |
| xy2cr ( marked_x , marked_y , &c , &r ); |
| result.mv_s[0] = 'a' + c; |
| result.mv_s[1] = '1' + r; |
| xy2cr ( x , y , &c , &r ); |
| result.mv_s[2] = 'a' + c; |
| result.mv_s[3] = '1' + r; |
| result.mv_s[4] = '\00'; |
| result.type = COMMAND_MOVE; |
| return result; |
| } |
| } |
| break; |
| } |
| #if defined(CB_PLAY_PRE) || defined(CB_SELECT_PRE) |
| if (button != BUTTON_NONE) |
| lastbutton = button; |
| #endif |
| } |
| |
| } |
| |
| /* Talk a move */ |
| static void talk_move(char *move_buffer) |
| { |
| if (rb->global_settings->talk_menu) { |
| rb->talk_id (VOICE_PAWN + |
| board[locn[move_buffer[3]-'1'][move_buffer[2]-'a']] - 1, |
| false); |
| rb->talk_id(VOICE_CHAR_A + move_buffer[0] - 'a', true); |
| rb->talk_id(VOICE_ONE + move_buffer[1] - '1', true); |
| rb->talk_id(VOICE_CHAR_A + move_buffer[2] - 'a', true); |
| rb->talk_id(VOICE_ONE + move_buffer[3] - '1', true); |
| if (move_buffer[4] == '+' && !mate) { |
| rb->talk_id(VOICE_CHESSBOX_CHECK, true); |
| } |
| } |
| } |
| |
| /* ---- game main loop ---- */ |
| static void cb_play_game(void) { |
| struct cb_command command; |
| struct pgn_game_node *game; |
| char move_buffer[20]; |
| |
| /* init status */ |
| bool exit = false; |
| |
| /* load opening book, soon */ |
| |
| /* init board */ |
| GNUChess_Initialize(); |
| |
| /* init PGN history data structures */ |
| game = pgn_init_game(); |
| |
| /* restore saved position, if saved */ |
| cb_restoreposition(); |
| /* TODO: save/restore the PGN history of unfinished games */ |
| |
| /* draw the board */ |
| /* I don't like configscreens, start game inmediatly */ |
| cb_drawboard(); |
| |
| while (!exit) { |
| if ( mate ) { |
| rb->talk_force_enqueue_next(); |
| rb->splash ( HZ*3 , ID2P(LANG_CHESSBOX_CHECKMATE) ); |
| rb->button_get(true); |
| pgn_store_game(game); |
| GNUChess_Initialize(); |
| game = pgn_init_game(); |
| cb_drawboard(); |
| } |
| command = cb_getcommand (); |
| switch (command.type) { |
| case COMMAND_MOVE: |
| if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) { |
| rb->splash ( HZ/2 , ID2P(LANG_CHESSBOX_ILLEGAL_MOVE) ); |
| cb_drawboard(); |
| } else { |
| cb_drawboard(); |
| |
| /* Add the ply to the PGN history (in algebraic notation) */ |
| pgn_append_ply(game, opponent, move_buffer, mate); |
| |
| talk_move(move_buffer); |
| rb->splash ( 0 , ID2P(LANG_CHESSBOX_THINKING) ); |
| #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
| rb->cpu_boost ( true ); |
| #endif |
| SelectMove ( computer , 0 , cb_wt_callback, move_buffer); |
| #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
| rb->cpu_boost ( false ); |
| #endif |
| /* Add the ply to the PGN history (in algebraic notation) and check |
| * for the result of the game which is only calculated in SelectMove |
| */ |
| if (move_buffer[0] != '\0'){ |
| pgn_append_ply(game, computer, move_buffer, mate); |
| talk_move(move_buffer); |
| } else { |
| pgn_set_result(game, mate); |
| } |
| |
| if ( wt_command == COMMAND_QUIT ) { |
| exit = true; |
| break; |
| } |
| cb_drawboard(); |
| } |
| break; |
| case COMMAND_RESTART: |
| GNUChess_Initialize(); |
| game = pgn_init_game(); |
| cb_drawboard(); |
| break; |
| case COMMAND_RESUME: |
| cb_drawboard(); |
| break; |
| case COMMAND_SAVE: |
| cb_saveposition(); |
| cb_drawboard(); |
| break; |
| case COMMAND_RESTORE: |
| /* watch out, it will reset the game if no previous game was saved! */ |
| |
| /* init board */ |
| GNUChess_Initialize(); |
| |
| /* init PGN history data structures */ |
| game = pgn_init_game(); |
| |
| /* restore saved position, if saved */ |
| cb_restoreposition(); |
| |
| cb_drawboard(); |
| break; |
| case COMMAND_PLAY: |
| if (opponent == white) { |
| opponent = black; |
| computer = white; |
| } else { |
| opponent = white; |
| computer = black; |
| } |
| rb->splash ( 0 , ID2P(LANG_CHESSBOX_THINKING) ); |
| ElapsedTime(1); |
| #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
| rb->cpu_boost ( true ); |
| #endif |
| SelectMove ( computer , 0 , cb_wt_callback , move_buffer ); |
| #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
| rb->cpu_boost ( false ); |
| #endif |
| |
| /* Add the ply to the PGN history (in algebraic notation) and check |
| * for the result of the game which is only calculated in SelectMove |
| */ |
| if (move_buffer[0] != '\0'){ |
| pgn_append_ply(game, computer, move_buffer, mate); |
| talk_move(move_buffer); |
| } else { |
| pgn_set_result(game, mate); |
| } |
| |
| if ( wt_command == COMMAND_QUIT ) { |
| exit = true; |
| break; |
| } |
| cb_drawboard(); |
| break; |
| case COMMAND_LEVEL: |
| cb_levelup ( ); |
| cb_drawboard(); |
| break; |
| case COMMAND_QUIT: |
| exit = true; |
| break; |
| } |
| } |
| |
| cb_saveposition(); |
| /* TODO: save/restore the PGN history of unfinished games */ |
| rb->lcd_setfont(FONT_UI); |
| |
| } |
| |
| /***************************************************************************** |
| * plugin entry point. |
| ******************************************************************************/ |
| enum plugin_status plugin_start(const void* parameter) { |
| |
| /* plugin init */ |
| |
| #if LCD_DEPTH > 1 |
| rb->lcd_set_backdrop(NULL); |
| #endif |
| cb_sysevent = 0; |
| |
| /* end of plugin init */ |
| |
| /* if the plugin was invoked as a viewer, parse the file and show the game list |
| * else, start playing a game |
| */ |
| if (parameter != NULL) { |
| cb_start_viewer((char *)parameter); |
| } else { |
| cb_play_game(); |
| } |
| |
| if (cb_sysevent) |
| rb->default_event_handler(cb_sysevent); |
| |
| return PLUGIN_OK; |
| } |