rockbox/apps/plugins/chessbox/chessbox.c

1112 lines
37 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Miguel A. Ar<EFBFBD>valo
* Color graphics from eboard
* GNUChess v2 chess engine Copyright (c) 1988 John Stanback
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP
#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[];
PLUGIN_HEADER
/* button definitions */
#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
(CONFIG_KEYPAD == IPOD_1G2G_PAD)
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_MENU
#define CB_DOWN BUTTON_PLAY
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY (BUTTON_SELECT | BUTTON_PLAY)
#define CB_LEVEL (BUTTON_SELECT | BUTTON_RIGHT)
#define CB_MENU (BUTTON_SELECT | BUTTON_MENU)
#define CB_SCROLL_UP (BUTTON_SCROLL_FWD|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_SCROLL_BACK|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_PLAY
#define CB_LEVEL BUTTON_REC
#define CB_MENU BUTTON_POWER
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_ON
#define CB_LEVEL BUTTON_MODE
#define CB_MENU BUTTON_OFF
#define CB_RC_QUIT BUTTON_RC_STOP
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_PLAY
#define CB_LEVEL BUTTON_EQ
#define CB_MENU BUTTON_MODE
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == RECORDER_PAD
#define CB_SELECT BUTTON_PLAY
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_ON
#define CB_LEVEL BUTTON_F1
#define CB_MENU BUTTON_OFF
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_ON
#define CB_LEVEL BUTTON_F1
#define CB_MENU BUTTON_OFF
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == ONDIO_PAD
#define CB_SELECT_PRE BUTTON_MENU
#define CB_SELECT (BUTTON_MENU|BUTTON_REL)
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY_PRE BUTTON_MENU
#define CB_PLAY (BUTTON_MENU|BUTTON_REPEAT)
#define CB_LEVEL (BUTTON_MENU|BUTTON_OFF)
#define CB_MENU BUTTON_OFF
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_POWER
#define CB_LEVEL BUTTON_MENU
#define CB_MENU BUTTON_A
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
#define CB_SELECT BUTTON_REW
#define CB_UP BUTTON_SCROLL_UP
#define CB_DOWN BUTTON_SCROLL_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY BUTTON_PLAY
#define CB_LEVEL BUTTON_FF
#define CB_MENU BUTTON_POWER
#define CB_SCROLL_UP (BUTTON_SCROLL_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_SCROLL_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#elif CONFIG_KEYPAD == SANSA_E200_PAD
#define CB_SELECT BUTTON_SELECT
#define CB_UP BUTTON_UP
#define CB_DOWN BUTTON_DOWN
#define CB_LEFT BUTTON_LEFT
#define CB_RIGHT BUTTON_RIGHT
#define CB_PLAY (BUTTON_SELECT | BUTTON_RIGHT)
#define CB_LEVEL BUTTON_REC
#define CB_MENU BUTTON_POWER
#define CB_SCROLL_UP (BUTTON_SCROLL_UP|BUTTON_REPEAT)
#define CB_SCROLL_DOWN (BUTTON_SCROLL_DOWN|BUTTON_REPEAT)
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
#else
#error CHESSBOX: Unsupported keypad
#endif
/* use 30x30 tiles */
#if (LCD_HEIGHT >= 240) && (LCD_WIDTH >= 240)
#define TILE_WIDTH 30
#define TILE_HEIGHT 30
/* use 22x22 tiles */
#elif (LCD_HEIGHT >= 176) && (LCD_WIDTH >= 176)
#define TILE_WIDTH 22
#define TILE_HEIGHT 22
/* use 16x16 tiles */
#elif (LCD_HEIGHT >= 128) && (LCD_WIDTH >= 128)
#define TILE_WIDTH 16
#define TILE_HEIGHT 16
/* use 13x13 tiles */
#elif (LCD_HEIGHT >= 104) && (LCD_WIDTH >= 104)
#define TILE_WIDTH 13
#define TILE_HEIGHT 13
/* use 10x8 tiles , only for the archoses */
#elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
#define TILE_WIDTH 10
#define TILE_HEIGHT 8
/* use 8x8 tiles */
#elif (LCD_HEIGHT >= 64) && (LCD_WIDTH >= 64)
#define TILE_WIDTH 8
#define TILE_HEIGHT 8
#else
#error CHESSBOX: Unsupported LCD
#endif
/* 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_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[] = { "Level 1: 60 moves / 5 min" ,
"Level 2: 60 moves / 15 min" ,
"Level 3: 60 moves / 30 min" ,
"Level 4: 40 moves / 30 min" ,
"Level 5: 40 moves / 60 min" ,
"Level 6: 40 moves / 120 min" ,
"Level 7: 40 moves / 240 min" ,
"Level 8: 1 move / 15 min" ,
"Level 9: 1 move / 60 min" ,
"Level 10: 1 move / 600 min" };
/* "While thinking" command */
int wt_command = COMMAND_NOP;
/* GCC wants this to be present for some targets */
void* memcpy(void* dst, const void* src, size_t size)
{
return rb->memcpy(dst, src, size);
}
/* ---- Get the board column and row (e2 f.e.) for a physical x y ---- */
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.) ---- */
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 ,
TILE_WIDTH ,
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 ,
TILE_WIDTH ,
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();
}
/* ---- Switch mark on board ---- */
void cb_switch ( short x , short 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 ---- */
void cb_wt_callback ( void ) {
int button = BUTTON_NONE;
wt_command = COMMAND_NOP;
button = rb->button_get(false);
switch (button) {
#ifdef CB_RC_QUIT
case CB_RC_QUIT:
wt_command = COMMAND_QUIT;
timeout = true;
break;
#endif
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 ---- */
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 ---- */
void cb_levelup ( void ) {
if ( Level == 7 )
cb_setlevel ( 1 );
else
cb_setlevel ( Level+1 );
rb->splash ( 50 , level_string[Level-1] );
};
/* ---- Save current position ---- */
void cb_saveposition ( void ) {
int fd;
short sq,i,c;
unsigned short temp;
rb->splash ( 0 , "Saving position" );
fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
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 ---- */
void cb_restoreposition ( void ) {
int fd;
int c;
short sq;
unsigned short m;
if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) {
rb->splash ( 0 , "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 = -1; c = '?';
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,"Restart Game",
"Select Other Game", "Quit");
while(!menu_quit)
{
switch(rb->do_menu(&menu, &selection))
{
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 ---- */
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) {
#ifdef CB_RC_QUIT
case CB_RC_QUIT:
result.type = COMMAND_QUIT;
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 ---- */
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(rb, filename);
if (first_game == NULL){
rb->splash ( 200 , "No games found !" );
return;
}
do {
selected_game = pgn_show_game_list(rb, first_game);
if (selected_game == NULL){
break;
}
pgn_parse_game(rb, 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 ( 200 , "At the begining of the game" );
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 ( 200 , "At the end of the game" );
break;
}
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){
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;
case COMMAND_SELECT:
exit_game = true;
break;
case COMMAND_QUIT:
exit_viewer = true;
break;
}
} while (!exit_game && !exit_viewer);
} else {
rb->splash ( 200 , "Error parsing game !");
}
} 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,"New Game","Resume Game",
"Save Game", "Restore Game", "Quit");
while(!menu_quit)
{
switch(rb->do_menu(&menu, &selection))
{
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:
result = COMMAND_QUIT;
menu_quit = true;
break;
}
}
return result;
}
/* ---- get a command in game mode ---- */
struct cb_command cb_getcommand (void) {
static short x = 4 , y = 3 ;
short c , r , l;
int button, lastbutton = BUTTON_NONE;
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) {
#ifdef CB_RC_QUIT
case CB_RC_QUIT:
result.type = COMMAND_QUIT;
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;
#endif
result.type = COMMAND_PLAY;
return result;
case CB_UP:
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 ;
} else {
from_marked = false ;
cb_switch ( x , y );
}
break;
case CB_DOWN:
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 ;
} else {
from_marked = false ;
cb_switch ( x , y );
}
break;
case CB_LEFT:
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 ;
} else {
from_marked = false ;
cb_switch ( x , y );
}
break;
case CB_RIGHT:
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 ;
} 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;
}
} else {
if ( ( marked_x == x ) && ( marked_y == y ) ) {
marked = false;
from_marked = 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 (button != BUTTON_NONE)
lastbutton = button;
}
}
/* ---- game main loop ---- */
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(rb);
/* 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->splash ( 500 , "Checkmate!" );
rb->button_get(true);
pgn_store_game(rb, game);
GNUChess_Initialize();
game = pgn_init_game(rb);
cb_drawboard();
}
command = cb_getcommand ();
switch (command.type) {
case COMMAND_MOVE:
if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) {
rb->splash ( 50 , "Illegal move!" );
cb_drawboard();
} else {
cb_drawboard();
/* Add the ply to the PGN history (in algebraic notation) */
pgn_append_ply(rb, game, opponent, move_buffer, mate);
rb->splash ( 0 , "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(rb, game, computer, move_buffer, mate);
} else {
pgn_set_result(rb, game, mate);
}
if ( wt_command == COMMAND_QUIT ) {
exit = true;
break;
}
cb_drawboard();
}
break;
#ifdef COMMAND_RESTART
case COMMAND_RESTART:
GNUChess_Initialize();
game = pgn_init_game(rb);
cb_drawboard();
break;
#endif
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(rb);
/* 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 , "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(rb, game, computer, move_buffer, mate);
} else {
pgn_set_result(rb, 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(struct plugin_api* api, void* parameter) {
/* plugin init */
rb = api;
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
/* 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();
}
return PLUGIN_OK;
}
#endif /* HAVE_LCD_BITMAP */