diff --git a/libraries/u8glib/chessengine.c b/libraries/u8glib/chessengine.c deleted file mode 100644 --- a/libraries/u8glib/chessengine.c +++ /dev/null @@ -1,2392 +0,0 @@ -/* - chessengine.c - - "Little Rook Chess" (lrc) - - Port to u8g library - - chess for embedded 8-Bit controllers - - Copyright (c) 2012, olikraus@gmail.com - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list - of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or other - materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Note: - UNIX_MAIN --> unix console executable - - Current Rule Limitation - - no minor promotion, only "Queening" of the pawn - - threefold repetition is not detected (same board situation appears three times) - Note: Could be implemented, but requires tracking of the complete game - - Fifty-move rule is not checked (no pawn move, no capture within last 50 moves) - - Words - Ply a half move - - General Links - http://chessprogramming.wikispaces.com/ - - Arduino specific - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1260055596 - - Prefixes - chess_ Generic Chess Application Interface - ce_ Chess engine, used internally, these function should not be called directly - cu_ Chess utility function - stack_ Internal function for stack handling - - Issues - 10.01.2011 - - castling to the right does not move the rook - --> done - - castling to the left: King can only move two squares - --> done - - 11.01.2011 - Next Steps: - - replace stack_NextCurrentPos with cu_NextPos, cleanup code according to the loop variable - --> done - - Castling: Need to check for fields under attack - --> done - - - Check for WIN / LOOSE situation, perhaps call ce_Eval() once on the top-level board setup - just after the real move - - cleanup cu_Move - --> almost done - - add some heuristics to the eval procedure - - add right side menu - --> done - - clean up chess_ManualMove - --> done - - finish menu (consider is_game_end, undo move) - - end condition: if KING is under attack and if KING can not move to a field which is under attack... - then the game is lost. What will be returned by the Eval procedure? is it -INF? - --> finished - - - reduce the use of variable color, all should be reduced to board_orientation and ply&1 - - - chess_GetNextMarked shoud make use of cu_NextPos - --> done - - chess_ManualMove: again cleanup, solve draw issue (KING is not in check and no legal moves are available) - --> done - 22.01.2011 - - simplify eval_t ce_Eval(void) - - position eval does not work, still moves side pawn :-( - maybe because all pieces are considered - --> done - -*/ - -#include "u8g.h" - -//#ifndef __unix__ -//#else -//#include -//#define U8G_NOINLINE -//#endif - -/* -SAN identifies each piece by a single upper case letter. The standard English -values: pawn = "P", knight = "N", bishop = "B", rook = "R", queen = "Q", and -king = "K". -*/ - -/* numbers for the various pieces */ -#define PIECE_NONE 0 -#define PIECE_PAWN 1 -#define PIECE_KNIGHT 2 -#define PIECE_BISHOP 3 -#define PIECE_ROOK 4 -#define PIECE_QUEEN 5 -#define PIECE_KING 6 - -/* color definitions */ -#define COLOR_WHITE 0 -#define COLOR_BLACK 1 - -/* a mask, which includes COLOR and PIECE number */ -#define COLOR_PIECE_MASK 0x01f - -#define CP_MARK_MASK 0x20 - -#define ILLEGAL_POSITION 255 - -/* This is the build in upper limit of the search stack */ -/* This value defines the amount of memory allocated for the search stack */ -/* The search depth of this chess engine can never exceed this value */ -#define STACK_MAX_SIZE 5 - -/* chess half move stack: twice the number of undo's, a user can do */ -#define CHM_USER_SIZE 6 - -/* the CHM_LIST_SIZE must be larger than the maximum search depth */ -/* the overall size of ste half move stack */ -#define CHM_LIST_SIZE (STACK_MAX_SIZE+CHM_USER_SIZE+2) - -typedef int16_t eval_t; /* a variable type to store results from the evaluation */ -//#define EVAL_T_LOST -32768 -#define EVAL_T_MIN -32767 -#define EVAL_T_MAX 32767 -//#define EVAL_T_WIN 32767 - -/* for maintainance of our own stack: this is the definition of one element on the stack */ -struct _stack_element_struct -{ - /* the current source position which is investigated */ - uint8_t current_pos; - uint8_t current_cp; - uint8_t current_color; /* COLOR_WHITE or COLOR_BLACK: must be predefines */ - - /* the move which belongs to that value, both values are game positions */ - uint8_t best_from_pos; - uint8_t best_to_pos; - /* the best value, which has been dicovered so far */ - eval_t best_eval; -}; -typedef struct _stack_element_struct stack_element_t; -typedef struct _stack_element_struct *stack_element_p; - -/* chess half move history */ -struct _chm_struct -{ - uint8_t main_cp; /* the main piece, which is moved */ - uint8_t main_src; /* the source position of the main piece */ - uint8_t main_dest; /* the destination of the main piece */ - - uint8_t other_cp; /* another piece: the captured one, the ROOK in case of castling or PIECE_NONE */ - uint8_t other_src; /* the delete position of other_cp. Often identical to main_dest except for e.p. and castling */ - uint8_t other_dest; /* only used for castling: ROOK destination pos */ - - /* the position of the last pawn, which did a double move forward */ - /* this is required to check en passant conditions */ - /* this array can be indexed by the color of the current player */ - /* this is the condition BEFORE the move was done */ - uint8_t pawn_dbl_move[2]; - - /* flags for the movement of rook and king; required for castling */ - /* a 1 means: castling is (still) possible */ - /* a 0 means: castling not possible */ - /* bit 0 left side white */ - /* bit 1 right side white */ - /* bit 2 left side black */ - /* bit 3 right side black */ - /* this is the condition BEFORE the move was done */ - uint8_t castling_possible; -}; - -typedef struct _chm_struct chm_t; -typedef struct _chm_struct *chm_p; - -/* little rook chess, main structure */ -struct _lrc_struct -{ - /* half-move (ply) counter: Counts the number of half-moves so far. Starts with 0 */ - /* the lowest bit is used to derive the color of the current player */ - /* will be set to zero in chess_SetupBoard() */ - uint8_t ply_count; - - /* the half move stack position counter, counts the number of elements in chm_list */ - uint8_t chm_pos; - - /* each element contains a colored piece, empty fields have value 0 */ - /* the field with index 0 is black (lower left) */ - uint8_t board[64]; - /* the position of the last pawn, which did a double move forward */ - /* this is required to check en passant conditions */ - /* this array can be indexed by the color of the current player */ - uint8_t pawn_dbl_move[2]; - - /* flags for the movement of rook and king; required for castling */ - /* a 1 means: castling is (still) possible */ - /* a 0 means: castling not possible */ - /* bit 0 left side white */ - /* bit 1 right side white */ - /* bit 2 left side black */ - /* bit 3 right side black */ - uint8_t castling_possible; - - /* board orientation */ - /* 0: white is below COLOR_WHITE */ - /* 1: black is below COLOR_BLACK */ - /* bascially, this can be used as a color */ - uint8_t orientation; - - /* exchange colors of the pieces */ - /* 0: white has an empty body, use this for bright background color */ - /* 1: black has an empty body, use this for dark backround color */ - uint8_t strike_out_color; - - /* 0, when the game is ongoing */ - /* 1, when the game is stopped (lost or draw) */ - uint8_t is_game_end; - /* the color of the side which lost the game */ - /* this value is only valid, when is_game_end is not 0 */ - /* values 0 and 1 represent WHITE and BLACK, 2 means a draw */ - uint8_t lost_side_color; - - - - /* checks are executed in ce_LoopRecur */ - /* these checks will put some marks on the board */ - /* this will be used by the interface to find out */ - /* legal moves */ - uint8_t check_src_pos; - uint8_t check_mode; /* CHECK_MODE_NONE, CHECK_MODE_MOVEABLE, CHECK_MODE_TARGET_MOVE */ - - - /* count of the attacking pieces, indexed by color */ - uint8_t find_piece_cnt[2]; - - /* sum of the attacking pieces, indexed by color */ - uint8_t find_piece_weight[2]; - - /* points to the current element of the search stack */ - /* this stack is NEVER empty. The value 0 points to the first element of the stack */ - /* actually "curr_depth" represent half-moves (plies) */ - uint8_t curr_depth; - uint8_t max_depth; - stack_element_p curr_element; - - /* allocated memory for the search stack */ - stack_element_t stack_memory[STACK_MAX_SIZE]; - - /* the half move stack, used for move undo and depth search, size is stored in chm_pos */ - chm_t chm_list[CHM_LIST_SIZE]; -}; -typedef struct _lrc_struct lrc_t; - -#define CHECK_MODE_NONE 0 -#define CHECK_MODE_MOVEABLE 1 -#define CHECK_MODE_TARGET_MOVE 2 - - - -/*==============================================================*/ -/* global variables */ -/*==============================================================*/ - -u8g_t *lrc_u8g; - -lrc_t lrc_obj; - - -/*==============================================================*/ -/* forward declarations */ -/*==============================================================*/ - -/* - apply no inline to some of the functions: - avr-gcc very often inlines functions, however not inline saves a lot of program memory! - On the other hand there are some really short procedures which should be inlined (like cp_GetColor) - These procedures are marked static to prevent the generation of the expanded procedure, which - also saves space. -*/ - -uint8_t stack_Push(uint8_t color) U8G_NOINLINE; -void stack_Pop(void) U8G_NOINLINE; -void stack_InitCurrElement(void) U8G_NOINLINE; -void stack_Init(uint8_t max) U8G_NOINLINE; -void stack_SetMove(eval_t val, uint8_t to_pos) U8G_NOINLINE; -uint8_t cu_NextPos(uint8_t pos) U8G_NOINLINE; -static uint8_t cu_gpos2bpos(uint8_t gpos); -static uint8_t cp_Construct(uint8_t color, uint8_t piece); -static uint8_t cp_GetPiece(uint8_t cp); -static uint8_t cp_GetColor(uint8_t cp); -uint8_t cp_GetFromBoard(uint8_t pos) U8G_NOINLINE; -void cp_SetOnBoard(uint8_t pos, uint8_t cp) U8G_NOINLINE; - -void cu_ClearBoard(void) U8G_NOINLINE; -void chess_SetupBoard(void) U8G_NOINLINE; -eval_t ce_Eval(void); - -void cu_ClearMoveHistory(void) U8G_NOINLINE; -void cu_ReduceHistoryByFullMove(void) U8G_NOINLINE; -void cu_UndoHalfMove(void) U8G_NOINLINE; -chm_p cu_PushHalfMove(void) U8G_NOINLINE; - - -void ce_CalculatePositionWeight(uint8_t pos); -uint8_t ce_GetPositionAttackWeight(uint8_t pos, uint8_t color); - -void chess_Thinking(void); -void ce_LoopPieces(void); - - -/*==============================================================*/ -/* search stack */ -/*==============================================================*/ - -/* get current element from stack */ -stack_element_p stack_GetCurrElement(void) -{ - return lrc_obj.curr_element; -} - -uint8_t stack_Push(uint8_t color) -{ - if ( lrc_obj.curr_depth == lrc_obj.max_depth ) - return 0; - lrc_obj.curr_depth++; - lrc_obj.curr_element = lrc_obj.stack_memory+lrc_obj.curr_depth; - - /* change view for the evaluation */ - color ^= 1; - stack_GetCurrElement()->current_color = color; - - return 1; -} - -void stack_Pop(void) -{ - lrc_obj.curr_depth--; - lrc_obj.curr_element = lrc_obj.stack_memory+lrc_obj.curr_depth; -} - -/* reset the current element on the stack */ -void stack_InitCurrElement(void) -{ - stack_element_p e = stack_GetCurrElement(); - e->best_eval = EVAL_T_MIN; - e->best_from_pos = ILLEGAL_POSITION; - e->best_to_pos = ILLEGAL_POSITION; -} - -/* resets the search stack (and the check mode) */ -void stack_Init(uint8_t max) -{ - lrc_obj.curr_depth = 0; - lrc_obj.curr_element = lrc_obj.stack_memory; - lrc_obj.max_depth = max; - lrc_obj.check_mode = CHECK_MODE_NONE; - stack_InitCurrElement(); - stack_GetCurrElement()->current_color = lrc_obj.ply_count; - stack_GetCurrElement()->current_color &= 1; -} - -/* assign evaluation value and store the move, if this is the best move */ -/* assumes, that current_pos contains the source position */ -void stack_SetMove(eval_t val, uint8_t to_pos) -{ - stack_element_p e = stack_GetCurrElement(); - if ( e->best_eval < val ) - { - e->best_eval = val; - e->best_from_pos = e->current_pos; - e->best_to_pos = to_pos; - } -} - -/* - calculate next position on a 0x88 board - loop is constructed in this way: - i = 0; - do - { - ... - i = cu_NextPos(i); - } while( i != 0 ); - - next pos might be started with an illegal position like 255 -*/ -uint8_t cu_NextPos(uint8_t pos) -{ - /* calculate next gpos */ - pos++; - if ( ( pos & 0x08 ) != 0 ) - { - pos+= 0x10; - pos&= 0xf0; - } - if ( ( pos & 0x80 ) != 0 ) - pos = 0; - return pos; -} - -uint8_t cu_PrevPos(uint8_t pos) -{ - /* calculate prev gpos */ - pos--; - if ( ( pos & 0x80 ) != 0 ) - pos = 0x077; - else if ( ( pos & 0x08 ) != 0 ) - { - pos &= 0xf0; - pos |= 0x07; - } - return pos; -} - - -/*==============================================================*/ -/* position transltion */ -/*==============================================================*/ -/* - there are two positions - 1. game position (gpos): BCD encoded x-y values - 2. board position (bpos): a number between 0 and 63, only used to access the board. -*/ -/* - gpos: game position value - returns: board position - note: does not do any checks -*/ -static uint8_t cu_gpos2bpos(uint8_t gpos) -{ - uint8_t bpos = gpos; - bpos &= 0xf0; - bpos >>= 1; - gpos &= 0x0f; - bpos |= gpos; - return bpos; -} - -#define gpos_IsIllegal(gpos) ((gpos) & 0x088) - - -/*==============================================================*/ -/* colored piece handling */ -/*==============================================================*/ - -#define cp_IsMarked(cp) ((cp) & CP_MARK_MASK) - - -/* - piece: one of PIECE_xxx - color: COLOR_WHITE or COLOR_BLACK - - returns: A colored piece -*/ -static uint8_t cp_Construct(uint8_t color, uint8_t piece) -{ - color <<= 4; - color |= piece; - return color; -} - -/* inline is better than a macro */ -static uint8_t cp_GetPiece(uint8_t cp) -{ - cp &= 0x0f; - return cp; -} - -/* - we could use a macro: - #define cp_GetColor(cp) (((cp) >> 4)&1) - however, inlined functions are sometimes much better -*/ -static uint8_t cp_GetColor(uint8_t cp) -{ - cp >>= 4; - cp &= 1; - return cp; -} - -/* - pos: game position - returns the colored piece at the given position -*/ -uint8_t cp_GetFromBoard(uint8_t pos) -{ - return lrc_obj.board[cu_gpos2bpos(pos)]; -} - -/* - pos: game position - cp: colored piece -*/ -void cp_SetOnBoard(uint8_t pos, uint8_t cp) -{ - /*printf("cp_SetOnBoard gpos:%02x cp:%02x\n", pos, cp);*/ - lrc_obj.board[cu_gpos2bpos(pos)] = cp; -} - -/*==============================================================*/ -/* global board access */ -/*==============================================================*/ - -void cu_ClearBoard(void) -{ - uint8_t i; - /* clear the board */ - for( i = 0; i < 64; i++ ) - lrc_obj.board[i] = PIECE_NONE; - - lrc_obj.ply_count = 0; - lrc_obj.orientation = COLOR_WHITE; - - lrc_obj.pawn_dbl_move[0] = ILLEGAL_POSITION; - lrc_obj.pawn_dbl_move[1] = ILLEGAL_POSITION; - - lrc_obj.castling_possible = 0x0f; - - lrc_obj.is_game_end = 0; - lrc_obj.lost_side_color = 0; - - /* clear half move history */ - cu_ClearMoveHistory(); - -} - -/* - test setup - white wins in one move -*/ -void chess_SetupBoardTest01(void) -{ - cu_ClearBoard(); - lrc_obj.board[7+7*8] = cp_Construct(COLOR_BLACK, PIECE_KING); - lrc_obj.board[7+5*8] = cp_Construct(COLOR_WHITE, PIECE_PAWN); - lrc_obj.board[3] = cp_Construct(COLOR_WHITE, PIECE_KING); - lrc_obj.board[0+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK); - lrc_obj.board[6] = cp_Construct(COLOR_WHITE, PIECE_QUEEN); -} - -/* setup the global board */ -void chess_SetupBoard(void) -{ - uint8_t i; - register uint8_t bp, wp; - - /* clear the board */ - cu_ClearBoard(); - - /* precronstruct pawns */ - wp = cp_Construct(COLOR_WHITE, PIECE_PAWN); - bp = cp_Construct(COLOR_BLACK, PIECE_PAWN); - - /* setup pawn */ - for( i = 0; i < 8; i++ ) - { - lrc_obj.board[i+8] = wp; - lrc_obj.board[i+6*8] = bp; - } - - /* assign remaining pieces */ - - lrc_obj.board[0] = cp_Construct(COLOR_WHITE, PIECE_ROOK); - lrc_obj.board[1] = cp_Construct(COLOR_WHITE, PIECE_KNIGHT); - lrc_obj.board[2] = cp_Construct(COLOR_WHITE, PIECE_BISHOP); - lrc_obj.board[3] = cp_Construct(COLOR_WHITE, PIECE_QUEEN); - lrc_obj.board[4] = cp_Construct(COLOR_WHITE, PIECE_KING); - lrc_obj.board[5] = cp_Construct(COLOR_WHITE, PIECE_BISHOP); - lrc_obj.board[6] = cp_Construct(COLOR_WHITE, PIECE_KNIGHT); - lrc_obj.board[7] = cp_Construct(COLOR_WHITE, PIECE_ROOK); - - lrc_obj.board[0+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK); - lrc_obj.board[1+7*8] = cp_Construct(COLOR_BLACK, PIECE_KNIGHT); - lrc_obj.board[2+7*8] = cp_Construct(COLOR_BLACK, PIECE_BISHOP); - lrc_obj.board[3+7*8] = cp_Construct(COLOR_BLACK, PIECE_QUEEN); - lrc_obj.board[4+7*8] = cp_Construct(COLOR_BLACK, PIECE_KING); - lrc_obj.board[5+7*8] = cp_Construct(COLOR_BLACK, PIECE_BISHOP); - lrc_obj.board[6+7*8] = cp_Construct(COLOR_BLACK, PIECE_KNIGHT); - lrc_obj.board[7+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK); - - //chess_SetupBoardTest01(); - -} - - - -/*==============================================================*/ -/* checks */ -/*==============================================================*/ - -/* - checks if the position is somehow illegal -*/ -uint8_t cu_IsIllegalPosition(uint8_t pos, uint8_t my_color) -{ - uint8_t board_cp; - /* check, if the position is offboard */ - if ( gpos_IsIllegal(pos) != 0 ) - return 1; - /* get the piece from the board */ - board_cp = cp_GetFromBoard(pos); - /* check if hit our own pieces */ - if ( board_cp != 0 ) - if ( cp_GetColor(board_cp) == my_color ) - return 1; - /* all ok, we could go to this position */ - return 0; -} - -/*==============================================================*/ -/* evaluation procedure */ -/*==============================================================*/ - -/* - basic idea is to return a value between EVAL_T_MIN and EVAL_T_MAX -*/ - -/* - the weight table uses the PIECE number as index: - #define PIECE_NONE 0 - #define PIECE_PAWN 1 - #define PIECE_KNIGHT 2 - #define PIECE_BISHOP 3 - #define PIECE_ROOK 4 - #define PIECE_QUEEN 5 - #define PIECE_KING 6 - the king itself is not counted -*/ -uint8_t ce_piece_weight[] = { 0, 1, 3, 3, 5, 9, 0 }; -uint8_t ce_pos_weight[] = { 0, 1, 1, 2, 2, 1, 1, 0}; -/* - evaluate the current situation on the global board -*/ -eval_t ce_Eval(void) -{ - uint8_t cp; - uint8_t is_my_king_present = 0; - uint8_t is_opposit_king_present = 0; - eval_t material_my_color = 0; - eval_t material_opposit_color = 0; - eval_t position_my_color = 0; - eval_t position_opposit_color = 0; - eval_t result; - uint8_t pos; - - pos = 0; - do - { - /* get colored piece from the board */ - cp = cp_GetFromBoard(pos); - - if ( cp_GetPiece(cp) != PIECE_NONE ) - { - if ( stack_GetCurrElement()->current_color == cp_GetColor(cp) ) - { - /* this is our color */ - /* check if we found our king */ - if ( cp_GetPiece(cp) == PIECE_KING ) - is_my_king_present = 1; - material_my_color += ce_piece_weight[cp_GetPiece(cp)]; - if ( cp_GetPiece(cp) == PIECE_PAWN || cp_GetPiece(cp) == PIECE_KNIGHT ) - { - position_my_color += ce_pos_weight[pos&7]*ce_pos_weight[(pos>>4)&7]; - } - } - else - { - /* this is the opposit color */ - if ( cp_GetPiece(cp) == PIECE_KING ) - is_opposit_king_present = 1; - material_opposit_color += ce_piece_weight[cp_GetPiece(cp)]; - if ( cp_GetPiece(cp) == PIECE_PAWN || cp_GetPiece(cp) == PIECE_KNIGHT ) - { - position_opposit_color += ce_pos_weight[pos&7]*ce_pos_weight[(pos>>4)&7]; - } - } - } - pos = cu_NextPos(pos); - } while( pos != 0 ); - - - /* decide if we lost or won the game */ - if ( is_my_king_present == 0 ) - return EVAL_T_MIN; /*_LOST*/ - if ( is_opposit_king_present == 0 ) - return EVAL_T_MAX; /*_WIN*/ - - /* here is the evaluation function */ - - result = material_my_color - material_opposit_color; - result <<= 3; - result += position_my_color - position_opposit_color; - return result; -} - -/*==============================================================*/ -/* move backup and restore */ -/*==============================================================*/ - - -/* this procedure must be called to keep the size as low as possible */ -/* if the chm_list is large enough, it could hold the complete history */ -/* but for an embedded controler... it is deleted for every engine search */ -void cu_ClearMoveHistory(void) -{ - lrc_obj.chm_pos = 0; -} - -void cu_ReduceHistoryByFullMove(void) -{ - uint8_t i; - while( lrc_obj.chm_pos > CHM_USER_SIZE ) - { - i = 0; - for(;;) - { - if ( i+2 >= lrc_obj.chm_pos ) - break; - lrc_obj.chm_list[i] = lrc_obj.chm_list[i+2]; - i++; - } - lrc_obj.chm_pos -= 2; - } -} - -void cu_UndoHalfMove(void) -{ - chm_p chm; - - if ( lrc_obj.chm_pos == 0 ) - return; - - lrc_obj.chm_pos--; - - chm = lrc_obj.chm_list+lrc_obj.chm_pos; - - lrc_obj.pawn_dbl_move[0] = chm->pawn_dbl_move[0]; - lrc_obj.pawn_dbl_move[1] = chm->pawn_dbl_move[1]; - lrc_obj.castling_possible = chm->castling_possible; - - cp_SetOnBoard(chm->main_src, chm->main_cp); - cp_SetOnBoard(chm->main_dest, PIECE_NONE); - - if ( chm->other_src != ILLEGAL_POSITION ) - cp_SetOnBoard(chm->other_src, chm->other_cp); - if ( chm->other_dest != ILLEGAL_POSITION ) - cp_SetOnBoard(chm->other_dest, PIECE_NONE); - -} - -/* - assumes, that the following members of the returned chm structure are filled - uint8_t main_cp; the main piece, which is moved - uint8_t main_src; the source position of the main piece - uint8_t main_dest; the destination of the main piece - - uint8_t other_cp; another piece: the captured one, the ROOK in case of castling or PIECE_NONE - uint8_t other_src; the delete position of other_cp. Often identical to main_dest except for e.p. and castling - uint8_t other_dest; only used for castling: ROOK destination pos - -*/ -chm_p cu_PushHalfMove(void) -{ - chm_p chm; - - chm = lrc_obj.chm_list+lrc_obj.chm_pos; - if ( lrc_obj.chm_pos < CHM_LIST_SIZE-1) - lrc_obj.chm_pos++; - - chm->pawn_dbl_move[0] = lrc_obj.pawn_dbl_move[0]; - chm->pawn_dbl_move[1] = lrc_obj.pawn_dbl_move[1]; - chm->castling_possible = lrc_obj.castling_possible; - return chm; -} - - -char chess_piece_to_char[] = "NBRQK"; - -/* - simple moves on empty field: Ka1-b2 - capture moves: Ka1xb2 - castling: 0-0 or 0-0-0 -*/ - -static void cu_add_pos(char *s, uint8_t pos) U8G_NOINLINE; - -static void cu_add_pos(char *s, uint8_t pos) -{ - *s = pos; - *s >>= 4; - *s += 'a'; - s++; - *s = pos; - *s &= 15; - *s += '1'; -} - -const char *cu_GetHalfMoveStr(uint8_t idx) -{ - chm_p chm; - static char buf[7]; /*Ka1-b2*/ - char *p = buf; - chm = lrc_obj.chm_list+idx; - - if ( cp_GetPiece(chm->main_cp) != PIECE_NONE ) - { - if ( cp_GetPiece(chm->main_cp) > PIECE_PAWN ) - { - *p++ = chess_piece_to_char[cp_GetPiece(chm->main_cp)-2]; - } - cu_add_pos(p, chm->main_src); - p+=2; - if ( cp_GetPiece(chm->other_cp) == PIECE_NONE ) - *p++ = '-'; - else - *p++ = 'x'; - cu_add_pos(p, chm->main_dest); - p+=2; - } - *p = '\0'; - return buf; -} - - - - - -/*==============================================================*/ -/* move */ -/*==============================================================*/ - -/* - Move a piece from source position to a destination on the board - This function - - does not perform any checking - - however it processes "en passant" and casteling - - backup the move and allow 1x undo - - 2011-02-05: - - fill pawn_dbl_move[] for double pawn moves - --> done - - Implement casteling - --> done - - en passant - --> done - - pawn conversion/promotion - --> done - - half-move backup - --> done - - cleanup everything, minimize variables - --> done -*/ - -void cu_Move(uint8_t src, uint8_t dest) -{ - /* start backup structure */ - chm_p chm = cu_PushHalfMove(); - - /* these are the values from the board at the positions, provided as arguments to this function */ - uint8_t cp_src, cp_dest; - - /* Maybe a second position is cleared and one additional location is set */ - uint8_t clr_pos2; - uint8_t set_pos2; - uint8_t set_cp2; - - /* get values from board */ - cp_src = cp_GetFromBoard(src); - cp_dest = cp_GetFromBoard(dest); - - /* fill backup structure */ - - chm->main_cp = cp_src; - chm->main_src = src; - chm->main_dest = dest; - - chm->other_cp = cp_dest; /* prepace capture backup */ - chm->other_src = dest; - chm->other_dest = ILLEGAL_POSITION; - - /* setup results as far as possible with some suitable values */ - - clr_pos2 = ILLEGAL_POSITION; /* for en passant and castling, two positions might be cleared */ - set_pos2 = ILLEGAL_POSITION; /* only used for castling */ - set_cp2 = PIECE_NONE; /* ROOK for castling */ - - /* check for PAWN */ - if ( cp_GetPiece(cp_src) == PIECE_PAWN ) - { - - /* double step: is the distance 2 rows */ - if ( (src - dest == 32) || ( dest - src == 32 ) ) - { - /* remember the destination position */ - lrc_obj.pawn_dbl_move[cp_GetColor(cp_src)] = dest; - } - - /* check if the PAWN is able to promote */ - else if ( (dest>>4) == 0 || (dest>>4) == 7 ) - { - /* do simple "queening" */ - cp_src &= ~PIECE_PAWN; - cp_src |= PIECE_QUEEN; - } - - /* is it en passant capture? */ - /* check for side move */ - else if ( ((src + dest) & 1) != 0 ) - { - /* check, if target field is empty */ - if ( cp_GetPiece(cp_dest) == PIECE_NONE ) - { - /* this is en passant */ - /* no further checking required, because legal moves are assumed here */ - /* however... the captured pawn position must be valid */ - clr_pos2 = lrc_obj.pawn_dbl_move[cp_GetColor(cp_src) ^ 1]; - chm->other_src = clr_pos2; - chm->other_cp = cp_GetFromBoard(clr_pos2); - } - } - } - - /* check for the KING */ - else if ( cp_GetPiece(cp_src) == PIECE_KING ) - { - /* disallow castling, if the KING has moved */ - if ( cp_GetColor(cp_src) == COLOR_WHITE ) - { - /* if white KING has moved, disallow castling for white */ - lrc_obj.castling_possible &= 0x0c; - } - else - { - /* if black KING has moved, disallow castling for black */ - lrc_obj.castling_possible &= 0x03; - } - - /* has it been castling to the left? */ - if ( src - dest == 2 ) - { - /* let the ROOK move to pos2 */ - set_pos2 = src-1; - set_cp2 = cp_GetFromBoard(src-4); - - /* the ROOK must be cleared from the original position */ - clr_pos2 = src-4; - - chm->other_cp = set_cp2; - chm->other_src = clr_pos2; - chm->other_dest = set_pos2; - } - - /* has it been castling to the right? */ - else if ( dest - src == 2 ) - { - /* let the ROOK move to pos2 */ - set_pos2 = src+1; - set_cp2 = cp_GetFromBoard(src+3); - - /* the ROOK must be cleared from the original position */ - clr_pos2 = src+3; - - chm->other_cp = set_cp2; - chm->other_src = clr_pos2; - chm->other_dest = set_pos2; - - } - - } - - /* check for the ROOK */ - else if ( cp_GetPiece(cp_src) == PIECE_ROOK ) - { - /* disallow white left castling */ - if ( src == 0x00 ) - lrc_obj.castling_possible &= ~0x01; - /* disallow white right castling */ - if ( src == 0x07 ) - lrc_obj.castling_possible &= ~0x02; - /* disallow black left castling */ - if ( src == 0x70 ) - lrc_obj.castling_possible &= ~0x04; - /* disallow black right castling */ - if ( src == 0x77 ) - lrc_obj.castling_possible &= ~0x08; - } - - - /* apply new board situation */ - - cp_SetOnBoard(dest, cp_src); - - if ( set_pos2 != ILLEGAL_POSITION ) - cp_SetOnBoard(set_pos2, set_cp2); - - cp_SetOnBoard(src, PIECE_NONE); - - if ( clr_pos2 != ILLEGAL_POSITION ) - cp_SetOnBoard(clr_pos2, PIECE_NONE); - - -} - -/* - this subprocedure decides for evaluation of the current board situation or further (deeper) investigation - Argument pos is the new target position if the current piece - -*/ -uint8_t ce_LoopRecur(uint8_t pos) -{ - eval_t eval; - - /* 1. check if target position is occupied by the same player (my_color) */ - /* of if pos is somehow illegal or not valid */ - if ( cu_IsIllegalPosition(pos, stack_GetCurrElement()->current_color) != 0 ) - return 0; - - /* 2. move piece to the specified position, capture opponent piece if required */ - cu_Move(stack_GetCurrElement()->current_pos, pos); - - - /* 3. */ - /* if depth reached: evaluate */ - /* else: go down next level */ - /* no eval if there had been any valid half-moves, so the default value (MIN) will be returned. */ - if ( stack_Push(stack_GetCurrElement()->current_color) == 0 ) - { - eval = ce_Eval(); - } - else - { - /* init the element, which has been pushed */ - stack_InitCurrElement(); - /* start over with ntext level */ - ce_LoopPieces(); - /* get the best move from opponents view, so invert the result */ - eval = -stack_GetCurrElement()->best_eval; - stack_Pop(); - } - - /* 4. store result */ - stack_SetMove(eval, pos); - - /* 5. undo the move */ - cu_UndoHalfMove(); - - /* 6. check special modes */ - /* the purpose of these checks is to mark special pieces and positions on the board */ - /* these marks can be checked by the user interface to highlight special positions */ - if ( lrc_obj.check_mode != 0 ) - { - stack_element_p e = stack_GetCurrElement(); - if ( lrc_obj.check_mode == CHECK_MODE_MOVEABLE ) - { - cp_SetOnBoard(e->current_pos, e->current_cp | CP_MARK_MASK ); - } - else if ( lrc_obj.check_mode == CHECK_MODE_TARGET_MOVE ) - { - if ( e->current_pos == lrc_obj.check_src_pos ) - { - cp_SetOnBoard(pos, cp_GetFromBoard(pos) | CP_MARK_MASK ); - } - } - } - return 1; -} - -/*==============================================================*/ -/* move pieces which can move one or more steps into a direction */ -/*==============================================================*/ - -/* - subprocedure to generate various target positions for some pieces - special cases are handled in the piece specific sub-procedure - - Arguments: - d: a list of potential directions - is_multi_step: if the piece can only do one step (zero for KING and KNIGHT) -*/ -static const uint8_t ce_dir_offset_rook[] PROGMEM = { 1, 16, -16, -1, 0 }; -static const uint8_t ce_dir_offset_bishop[] PROGMEM = { 15, 17, -17, -15, 0 }; -static const uint8_t ce_dir_offset_queen[] PROGMEM = { 1, 16, -16, -1, 15, 17, -17, -15, 0 }; -static const uint8_t ce_dir_offset_knight[] PROGMEM = {14, -14, 18, -18, 31, -31, 33, -33, 0}; - -void ce_LoopDirsSingleMultiStep(const uint8_t *d, uint8_t is_multi_step) -{ - uint8_t loop_pos; - - /* with all directions */ - for(;;) - { - if ( u8g_pgm_read(d) == 0 ) - break; - - /* start again from the initial position */ - loop_pos = stack_GetCurrElement()->current_pos; - - /* check direction */ - do - { - /* check next position into one direction */ - loop_pos += u8g_pgm_read(d); - - /* - go further to ce_LoopRecur() - 0 will be returned if the target position is illegal or a piece of the own color - this is used to stop walking into one direction - */ - if ( ce_LoopRecur(loop_pos) == 0 ) - break; - - /* stop if we had hit another piece */ - if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) != PIECE_NONE ) - break; - } while( is_multi_step ); - d++; - } -} - -void ce_LoopRook(void) -{ - ce_LoopDirsSingleMultiStep(ce_dir_offset_rook, 1); -} - -void ce_LoopBishop(void) -{ - ce_LoopDirsSingleMultiStep(ce_dir_offset_bishop, 1); -} - -void ce_LoopQueen(void) -{ - ce_LoopDirsSingleMultiStep(ce_dir_offset_queen, 1); -} - -void ce_LoopKnight(void) -{ - ce_LoopDirsSingleMultiStep(ce_dir_offset_knight, 0); -} - - - -/*==============================================================*/ -/* move king */ -/*==============================================================*/ - -uint8_t cu_IsKingCastling(uint8_t mask, int8_t direction, uint8_t cnt) U8G_NOINLINE; - -/* - checks, if the king can do castling - - Arguments: - mask: the bit-mask for the global "castling possible" flag - direction: left castling: -1, right castling 1 - cnt: number of fields to be checked: 3 or 2 -*/ -uint8_t cu_IsKingCastling(uint8_t mask, int8_t direction, uint8_t cnt) -{ - uint8_t pos; - uint8_t opponent_color; - - /* check if the current board state allows castling */ - if ( (lrc_obj.castling_possible & mask) == 0 ) - return 0; /* castling not allowed */ - - /* get the position of the KING, could be white or black king */ - pos = stack_GetCurrElement()->current_pos; - - /* calculate the color of the opponent */ - opponent_color = 1; - opponent_color -= stack_GetCurrElement()->current_color; - - /* if the KING itself is given check... */ - if ( ce_GetPositionAttackWeight(pos, opponent_color) > 0 ) - return 0; - - - /* check if fields in the desired direction are emtpy */ - for(;;) - { - /* go to the next field */ - pos += direction; - /* check for a piece */ - if ( cp_GetPiece(cp_GetFromBoard(pos)) != PIECE_NONE ) - return 0; /* castling not allowed */ - - /* if some of the fields are under attack */ - if ( ce_GetPositionAttackWeight(pos, opponent_color) > 0 ) - return 0; - - cnt--; - if ( cnt == 0 ) - break; - } - return 1; /* castling allowed */ -} - -void ce_LoopKing(void) -{ - /* - there is an interessting timing problem in this procedure - it must be checked for castling first and as second step the normal - KING movement. If we would first check for normal moves, than - any marks might be overwritten by the ROOK in the case of castling. - */ - - /* castling (this must be done before checking normal moves (see above) */ - if ( stack_GetCurrElement()->current_color == COLOR_WHITE ) - { - /* white left castling */ - if ( cu_IsKingCastling(1, -1, 3) != 0 ) - { - /* check for attacked fields */ - ce_LoopRecur(stack_GetCurrElement()->current_pos-2); - } - /* white right castling */ - if ( cu_IsKingCastling(2, 1, 2) != 0 ) - { - /* check for attacked fields */ - ce_LoopRecur(stack_GetCurrElement()->current_pos+2); - } - } - else - { - /* black left castling */ - if ( cu_IsKingCastling(4, -1, 3) != 0 ) - { - /* check for attacked fields */ - ce_LoopRecur(stack_GetCurrElement()->current_pos-2); - } - /* black right castling */ - if ( cu_IsKingCastling(8, 1, 2) != 0 ) - { - /* check for attacked fields */ - ce_LoopRecur(stack_GetCurrElement()->current_pos+2); - } - } - - /* reuse queen directions */ - ce_LoopDirsSingleMultiStep(ce_dir_offset_queen, 0); -} - - -/*==============================================================*/ -/* move pawn */ -/*==============================================================*/ - -/* - doppelschritt: nur von der grundlinie aus, beide (!) felder vor dem bauern müssen frei sein - en passant: nur unmittelbar nachdem ein doppelschritt ausgeführt wurde. -*/ -void ce_LoopPawnSideCapture(uint8_t loop_pos) -{ - if ( gpos_IsIllegal(loop_pos) == 0 ) - { - /* get the piece from the board */ - /* if the field is NOT empty */ - if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) != PIECE_NONE ) - { - /* normal capture */ - ce_LoopRecur(loop_pos); - /* TODO: check for pawn conversion/promotion */ - } - else - { - /* check conditions for en passant capture */ - if ( stack_GetCurrElement()->current_color == COLOR_WHITE ) - { - if ( lrc_obj.pawn_dbl_move[COLOR_BLACK]+16 == loop_pos ) - { - ce_LoopRecur(loop_pos); - /* note: pawn conversion/promotion can not occur */ - } - } - else - { - if ( lrc_obj.pawn_dbl_move[COLOR_WHITE] == loop_pos+16 ) - { - ce_LoopRecur(loop_pos); - /* note: pawn conversion/promotion can not occur */ - } - } - } - } -} - -void ce_LoopPawn(void) -{ - uint8_t initial_pos = stack_GetCurrElement()->current_pos; - uint8_t my_color = stack_GetCurrElement()->current_color; - - uint8_t loop_pos; - uint8_t line; - - /* one step forward */ - - loop_pos = initial_pos; - line = initial_pos; - line >>= 4; - if ( my_color == COLOR_WHITE ) - loop_pos += 16; - else - loop_pos -= 16; - if ( gpos_IsIllegal(loop_pos) == 0 ) - { - /* if the field is empty */ - if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) == PIECE_NONE ) - { - /* TODO: check for and loop through piece conversion/promotion */ - ce_LoopRecur(loop_pos); - - /* second step forward */ - - /* if pawn is on his starting line */ - if ( (my_color == COLOR_WHITE && line == 1) || (my_color == COLOR_BLACK && line == 6 ) ) - { - /* the place before the pawn is not occupied, so we can do double moves, see above */ - - if ( my_color == COLOR_WHITE ) - loop_pos += 16; - else - loop_pos -= 16; - if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) == PIECE_NONE ) - { - /* this is a special case, other promotions of the pawn can not occur */ - ce_LoopRecur(loop_pos); - } - } - } - } - - /* capture */ - - loop_pos = initial_pos; - if ( my_color == COLOR_WHITE ) - loop_pos += 15; - else - loop_pos -= 15; - ce_LoopPawnSideCapture(loop_pos); - - - loop_pos = initial_pos; - if ( my_color == COLOR_WHITE ) - loop_pos += 17; - else - loop_pos -= 17; - ce_LoopPawnSideCapture(loop_pos); -} - -/*==============================================================*/ -/* attacked */ -/*==============================================================*/ - -/* - from a starting position, search for a piece, that might jump to that postion. - return: - the two global variables - lrc_obj.find_piece_weight[0]; - lrc_obj.find_piece_weight[1]; - will be increased by the weight of the attacked pieces of that color. - it is usually required to reset these global variables to zero, before using - this function. -*/ - -void ce_FindPieceByStep(uint8_t start_pos, uint8_t piece, const uint8_t *d, uint8_t is_multi_step) -{ - uint8_t loop_pos, cp; - - /* with all directions */ - for(;;) - { - if ( u8g_pgm_read(d) == 0 ) - break; - - /* start again from the initial position */ - loop_pos = start_pos; - - /* check direction */ - do - { - /* check next position into one direction */ - loop_pos += u8g_pgm_read(d); - - /* check if the board boundary has been crossed */ - if ( (loop_pos & 0x088) != 0 ) - break; - - /* get the colored piece from the board */ - cp = cp_GetFromBoard(loop_pos); - - /* stop if we had hit another piece */ - if ( cp_GetPiece(cp) != PIECE_NONE ) - { - /* if it is the piece we are looking for, then add the weight */ - if ( cp_GetPiece(cp) == piece ) - { - lrc_obj.find_piece_weight[cp_GetColor(cp)] += ce_piece_weight[piece]; - lrc_obj.find_piece_cnt[cp_GetColor(cp)]++; - } - /* in any case, break out of the inner loop */ - break; - } - } while( is_multi_step ); - d++; - } -} - -void ce_FindPawnPiece(uint8_t dest_pos, uint8_t color) -{ - uint8_t cp; - /* check if the board boundary has been crossed */ - if ( (dest_pos & 0x088) == 0 ) - { - /* get the colored piece from the board */ - cp = cp_GetFromBoard(dest_pos); - /* only if there is a pawn of the matching color */ - if ( cp_GetPiece(cp) == PIECE_PAWN ) - { - if ( cp_GetColor(cp) == color ) - { - /* the weight of the PAWN */ - lrc_obj.find_piece_weight[color] += 1; - lrc_obj.find_piece_cnt[color]++; - } - } - } -} - - -/* - find out, which pieces do attack a specified field - used to - - check if the KING can do castling - - check if the KING must move - - may be used in the eval procedure ... once... - - the result is stored in the global array - uint8_t lrc_obj.find_piece_weight[2]; - which is indexed with the color. - lrc_obj.find_piece_weight[COLOR_WHITE] is the sum of all white pieces - which can directly move to this field. - - example: - if the black KING is at "pos" and lrc_obj.find_piece_weight[COLOR_WHITE] is not zero - (after executing ce_CalculatePositionWeight(pos)) then the KING must be protected or moveed, because - the KING was given check. -*/ - -void ce_CalculatePositionWeight(uint8_t pos) -{ - - lrc_obj.find_piece_weight[0] = 0; - lrc_obj.find_piece_weight[1] = 0; - lrc_obj.find_piece_cnt[0] = 0; - lrc_obj.find_piece_cnt[1] = 0; - - if ( (pos & 0x088) != 0 ) - return; - - ce_FindPieceByStep(pos, PIECE_ROOK, ce_dir_offset_rook, 1); - ce_FindPieceByStep(pos, PIECE_BISHOP, ce_dir_offset_bishop, 1); - ce_FindPieceByStep(pos, PIECE_QUEEN, ce_dir_offset_queen, 1); - ce_FindPieceByStep(pos, PIECE_KNIGHT, ce_dir_offset_knight, 0); - ce_FindPieceByStep(pos, PIECE_KING, ce_dir_offset_queen, 0); - - ce_FindPawnPiece(pos+17, COLOR_BLACK); - ce_FindPawnPiece(pos+15, COLOR_BLACK); - ce_FindPawnPiece(pos-17, COLOR_WHITE); - ce_FindPawnPiece(pos-15, COLOR_WHITE); -} - -/* - calculate the summed weight of pieces with specified color which can move to a specified position - - argument: - pos: the position which should be analysed - color: the color of those pieces which should be analysed - e.g. if a black piece is at 'pos' and 'color' is white then this procedure returns the white atting count -*/ -uint8_t ce_GetPositionAttackWeight(uint8_t pos, uint8_t color) -{ - ce_CalculatePositionWeight(pos); - return lrc_obj.find_piece_weight[color]; -} - -uint8_t ce_GetPositionAttackCount(uint8_t pos, uint8_t color) -{ - ce_CalculatePositionWeight(pos); - return lrc_obj.find_piece_cnt[color]; -} - - -/*==============================================================*/ -/* depth search starts here: loop over all pieces of the current color on the board */ -/*==============================================================*/ - -void ce_LoopPieces(void) -{ - stack_element_p e = stack_GetCurrElement(); - /* start with lower left position (A1) */ - e->current_pos = 0; - do - { - e->current_cp = cp_GetFromBoard(e->current_pos); - /* check if the position on the board is empty */ - if ( e->current_cp != 0 ) - { - /* only generate moves for the current color */ - if ( e->current_color == cp_GetColor(e->current_cp) ) - { - chess_Thinking(); - - /* find out which piece is used */ - switch(cp_GetPiece(e->current_cp)) - { - case PIECE_NONE: - break; - case PIECE_PAWN: - ce_LoopPawn(); - break; - case PIECE_KNIGHT: - ce_LoopKnight(); - break; - case PIECE_BISHOP: - ce_LoopBishop(); - break; - case PIECE_ROOK: - ce_LoopRook(); - break; - case PIECE_QUEEN: - ce_LoopQueen(); - break; - case PIECE_KING: - ce_LoopKing(); - break; - } - } - } - e->current_pos = cu_NextPos(e->current_pos); - } while( e->current_pos != 0 ); -} - -/*==============================================================*/ -/* user interface */ -/*==============================================================*/ - -/* -eval_t chess_EvalCurrBoard(uint8_t color) -{ - stack_Init(0); - stack_GetCurrElement()->current_color = color; - ce_LoopPieces(); - return stack_GetCurrElement()->best_eval; -} -*/ - -/* clear any marks on the board */ -void chess_ClearMarks(void) -{ - uint8_t i; - for( i = 0; i < 64; i++ ) - lrc_obj.board[i] &= ~CP_MARK_MASK; -} - -/* - Mark all pieces which can do moves. This is done by setting flags on the global board -*/ -void chess_MarkMovable(void) -{ - stack_Init(0); - //stack_GetCurrElement()->current_color = color; - lrc_obj.check_mode = CHECK_MODE_MOVEABLE; - ce_LoopPieces(); -} - -/* - Checks, if the piece can move from src_pos to dest_pos - - src_pos: The game position of a piece on the chess board -*/ -void chess_MarkTargetMoves(uint8_t src_pos) -{ - stack_Init(0); - stack_GetCurrElement()->current_color = cp_GetColor(cp_GetFromBoard(src_pos)); - lrc_obj.check_src_pos = src_pos; - lrc_obj.check_mode = CHECK_MODE_TARGET_MOVE; - ce_LoopPieces(); -} - -/* - first call should start with 255 - this procedure will return 255 if - - there are no marks at all - - it has looped over all marks once -*/ -uint8_t chess_GetNextMarked(uint8_t arg, uint8_t is_prev) -{ - uint8_t i; - uint8_t pos = arg; - for(i = 0; i < 64; i++) - { - if ( is_prev != 0 ) - pos = cu_PrevPos(pos); - else - pos = cu_NextPos(pos); - if ( arg != 255 && pos == 0 ) - return 255; - if ( cp_IsMarked(cp_GetFromBoard(pos)) ) - return pos; - } - return 255; -} - - -/* make a manual move: this is a little bit more than cu_Move() */ -void chess_ManualMove(uint8_t src, uint8_t dest) -{ - uint8_t cp; - - /* printf("chess_ManualMove %02x -> %02x\n", src, dest); */ - - /* if all other things fail, this is the place where the game is to be decided: */ - /* ... if the KING is captured */ - cp = cp_GetFromBoard(dest); - if ( cp_GetPiece(cp) == PIECE_KING ) - { - lrc_obj.is_game_end = 1; - lrc_obj.lost_side_color = cp_GetColor(cp); - } - - /* clear ply history here, to avoid memory overflow */ - /* may be the last X moves can be kept here */ - cu_ReduceHistoryByFullMove(); - /* perform the move on the board */ - cu_Move(src, dest); - - /* update en passant double move positions: en passant position is removed after two half moves */ - lrc_obj.pawn_dbl_move[lrc_obj.ply_count&1] = ILLEGAL_POSITION; - - /* update the global half move counter */ - lrc_obj.ply_count++; - - - /* make a small check about the end of the game */ - /* use at least depth 1, because we must know if the king can still move */ - /* this is: King moves at level 0 and will be captured at level 1 */ - /* so we check if the king can move and will not be captured at search level 1 */ - - stack_Init(1); - ce_LoopPieces(); - - /* printf("chess_ManualMove/analysis best_from_pos %02x -> best_to_pos %02x\n", stack_GetCurrElement()->best_from_pos, stack_GetCurrElement()->best_to_pos); */ - - /* analyse the eval result */ - - /* check if the other player has any moves left */ - if ( stack_GetCurrElement()->best_from_pos == ILLEGAL_POSITION ) - { - uint8_t color; - /* conditions: */ - /* 1. no King, should never happen, opposite color has won */ - /* this is already checked above at the beginning if this procedure */ - /* 2. King is under attack, opposite color has won */ - /* 3. King is not under attack, game is a draw */ - - uint8_t i = 0; - color = lrc_obj.ply_count; - color &= 1; - do - { - cp = cp_GetFromBoard(i); - /* look for the King */ - if ( cp_GetPiece(cp) == PIECE_KING ) - { - if ( cp_GetColor(cp) == color ) - { - /* check if KING is attacked */ - if ( ce_GetPositionAttackCount(i, color^1) != 0 ) - { - /* KING is under attack (check) and can not move: Game is lost */ - lrc_obj.is_game_end = 1; - lrc_obj.lost_side_color = color; - } - else - { - /* KING is NOT under attack (check) but can not move: Game is a draw */ - lrc_obj.is_game_end = 1; - lrc_obj.lost_side_color = 2; - } - /* break out of the loop */ - break; - } - } - i = cu_NextPos(i); - } while( i != 0 ); - } -} - -/* let the computer do a move */ -void chess_ComputerMove(uint8_t depth) -{ - stack_Init(depth); - - //stack_GetCurrElement()->current_color = lrc_obj.ply_count; - //stack_GetCurrElement()->current_color &= 1; - - cu_ReduceHistoryByFullMove(); - ce_LoopPieces(); - - chess_ManualMove(stack_GetCurrElement()->best_from_pos, stack_GetCurrElement()->best_to_pos); -} - - -/*==============================================================*/ -/* unix code */ -/*==============================================================*/ - -#ifdef UNIX_MAIN - -#include -#include - -char *piece_str[] = { - /* 0x00 */ - " ", - "wP", - "wN", - "wB", - - /* 0x04 */ - "wR", - "wQ", - "wK", - "w?", - - /* 0x08 */ - "w?", - "w?", - "w?", - "w?", - - /* 0x0c */ - "w?", - "w?", - "w?", - "w?", - - /* 0x10 */ - "b ", - "bP", - "bN", - "bB", - "bR", - "bQ", - "bK", - "b?", - - "b?", - "b?", - "b?", - "b?", - "b?", - "b?", - "b?", - "b?" -}; - -void chess_Thinking(void) -{ - uint8_t i; - uint8_t cp = cp_GetPiece(stack_GetCurrElement()->current_cp); - - printf("Thinking: ", piece_str[cp], stack_GetCurrElement()->current_pos); - - for( i = 0; i <= lrc_obj.curr_depth; i++ ) - printf("%s ", piece_str[(lrc_obj.stack_memory+i)->current_cp]); - - printf(" \r"); -} - -void board_Show(void) -{ - uint8_t i, j, cp; - char buf[10]; - for ( i = 0; i < 8; i++ ) - { - printf("%1d ", 7-i); - for ( j = 0; j < 8; j++ ) - { - /* get piece from global board */ - cp = lrc_obj.board[(7-i)*8+j]; - strcpy(buf, piece_str[cp&COLOR_PIECE_MASK]); - - if ( (cp & CP_MARK_MASK) != 0 ) - { - buf[0] = '#'; - } - - /* mask out any bits except color and piece index */ - cp &= COLOR_PIECE_MASK; - printf("%s %02x ", buf, cp); - - } - printf("\n"); - } -} - -int main(void) -{ - uint8_t depth = 3; - chess_SetupBoard(); - board_Show(); - puts(""); - - - /* - chess_ClearMarks(); - chess_MarkMovable(COLOR_WHITE); - board_Show(); - */ - - chess_ManualMove(0x006, 0x066); - - printf("lrc_obj.is_game_end: %d\n" , lrc_obj.is_game_end); - printf("lrc_obj.lost_side_color: %d\n" , lrc_obj.lost_side_color); - - chess_ComputerMove(2); - - printf("lrc_obj.is_game_end: %d\n" , lrc_obj.is_game_end); - printf("lrc_obj.lost_side_color: %d\n" , lrc_obj.lost_side_color); - - board_Show(); - -} - - - -#else - -/*==============================================================*/ -/* display menu */ -/*==============================================================*/ - -//#define MNU_FONT font_5x7 -#define MNU_FONT u8g_font_5x8r -//#define MNU_FONT font_6x9 -#define MNU_ENTRY_HEIGHT 9 - -char *mnu_title = "Little Rook Chess"; -char *mnu_list[] = { "New Game (White)", "New Game (Black)", "Undo Move", "Return" }; -uint8_t mnu_pos = 0; -uint8_t mnu_max = 4; - -void mnu_DrawHome(uint8_t is_highlight) -{ - uint8_t x = lrc_u8g->width - 35; - uint8_t y = (lrc_u8g->height-1); - uint8_t t; - - u8g_SetFont(lrc_u8g, u8g_font_5x7r); - u8g_SetDefaultForegroundColor(lrc_u8g); - t = u8g_DrawStrP(lrc_u8g, x, y -1, U8G_PSTR("Options")); - - if ( is_highlight ) - u8g_DrawFrame(lrc_u8g, x-1, y - MNU_ENTRY_HEIGHT +1, t, MNU_ENTRY_HEIGHT); -} - -void mnu_DrawEntry(uint8_t y, char *str, uint8_t is_clr_background, uint8_t is_highlight) -{ - uint8_t t, x; - u8g_SetFont(lrc_u8g, MNU_FONT); - t = u8g_GetStrWidth(lrc_u8g, str); - x = u8g_GetWidth(lrc_u8g); - x -= t; - x >>= 1; - - if ( is_clr_background ) - { - u8g_SetDefaultBackgroundColor(lrc_u8g); - u8g_DrawBox(lrc_u8g, x-3, (lrc_u8g->height-1) - (y+MNU_ENTRY_HEIGHT-1+2), t+5, MNU_ENTRY_HEIGHT+4); - } - - u8g_SetDefaultForegroundColor(lrc_u8g); - u8g_DrawStr(lrc_u8g, x, (lrc_u8g->height-1) - y, str); - - if ( is_highlight ) - { - u8g_DrawFrame(lrc_u8g, x-1, (lrc_u8g->height-1) - y -MNU_ENTRY_HEIGHT +1, t, MNU_ENTRY_HEIGHT); - } -} - -void mnu_Draw(void) -{ - uint8_t i; - uint8_t t,y; - /* calculate hight of the complete menu */ - y = mnu_max; - y++; /* consider also some space for the title */ - y++; /* consider also some space for the title */ - y *= MNU_ENTRY_HEIGHT; - - /* calculate how much space will be left */ - t = u8g_GetHeight(lrc_u8g); - t -= y; - - /* topmost pos start half of that empty space from the top */ - t >>= 1; - y = u8g_GetHeight(lrc_u8g); - y -= t; - - y -= MNU_ENTRY_HEIGHT; - mnu_DrawEntry(y, mnu_title, 0, 0); - - y -= MNU_ENTRY_HEIGHT; - - - for( i = 0; i < mnu_max; i++ ) - { - y -= MNU_ENTRY_HEIGHT; - mnu_DrawEntry(y, mnu_list[i], 0, i == mnu_pos); - } -} - -void mnu_Step(uint8_t key_cmd) -{ - if ( key_cmd == CHESS_KEY_NEXT ) - { - if ( mnu_pos+1 < mnu_max ) - mnu_pos++; - } - else if ( key_cmd == CHESS_KEY_PREV ) - { - if ( mnu_pos > 0 ) - mnu_pos--; - } -} - - - - -uint8_t chess_key_code = 0; -uint8_t chess_key_cmd = 0; -#define CHESS_STATE_MENU 0 -#define CHESS_STATE_SELECT_START 1 -#define CHESS_STATE_SELECT_PIECE 2 -#define CHESS_STATE_SELECT_TARGET_POS 3 -#define CHESS_STATE_THINKING 4 -#define CHESS_STATE_GAME_END 5 -uint8_t chess_state = CHESS_STATE_MENU; -uint8_t chess_source_pos = 255; -uint8_t chess_target_pos = 255; - -const uint8_t chess_pieces_body_bm[] PROGMEM = -{ - /* PAWN */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, */ - /* KNIGHT */ 0x00, 0x00, 0x1c, 0x2c, 0x04, 0x04, 0x0e, 0x00, - /* BISHOP */ 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0x08, 0x00, 0x00, /* 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x08, 0x00, 0x00, */ - /* ROOK */ 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0x1c, 0x00, - /* QUEEN */ 0x00, 0x00, 0x14, 0x1c, 0x08, 0x1c, 0x08, 0x00, - /* KING */ 0x00, 0x00, 0x00, 0x08, 0x3e, 0x1c, 0x08, 0x00, -}; - -#ifdef NOT_REQUIRED -/* white pieces are constructed by painting black pieces and cutting out the white area */ -const uint8_t chess_white_pieces_bm[] PROGMEM = -{ - /* PAWN */ 0x00, 0x00, 0x0c, 0x12, 0x12, 0x0c, 0x1e, 0x00, - /* KNIGHT */ 0x00, 0x1c, 0x22, 0x52, 0x6a, 0x0a, 0x11, 0x1f, - /* BISHOP */ 0x00, 0x08, 0x14, 0x22, 0x22, 0x14, 0x08, 0x7f, - /* ROOK */ 0x00, 0x55, 0x7f, 0x22, 0x22, 0x22, 0x22, 0x7f, - /* QUEEN */ 0x00, 0x55, 0x2a, 0x22, 0x14, 0x22, 0x14, 0x7f, - /* KING */ 0x08, 0x1c, 0x49, 0x77, 0x41, 0x22, 0x14, 0x7f, -}; -#endif - -const uint8_t chess_black_pieces_bm[] PROGMEM = -{ - /* PAWN */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x3c, 0x00, /* 0x00, 0x00, 0x0c, 0x1e, 0x1e, 0x0c, 0x1e, 0x00, */ - /* KNIGHT */ 0x00, 0x1c, 0x3e, 0x7e, 0x6e, 0x0e, 0x1f, 0x1f, - /* BISHOP */ 0x00, 0x1c, 0x2e, 0x3e, 0x3e, 0x1c, 0x08, 0x7f, /*0x00, 0x08, 0x1c, 0x3e, 0x3e, 0x1c, 0x08, 0x7f,*/ - /* ROOK */ 0x00, 0x55, 0x7f, 0x3e, 0x3e, 0x3e, 0x3e, 0x7f, - /* QUEEN */ 0x00, 0x55, 0x3e, 0x3e, 0x1c, 0x3e, 0x1c, 0x7f, - /* KING -*/ 0x08, 0x1c, 0x49, 0x7f, 0x7f, 0x3e, 0x1c, 0x7f, -}; - - -#if defined(DOGXL160_HW_GR) -#define BOXSIZE 13 -#define BOXOFFSET 3 -#else -#define BOXSIZE 8 -#define BOXOFFSET 1 -#endif - -u8g_uint_t chess_low_edge; -uint8_t chess_boxsize = 8; -uint8_t chess_boxoffset = 1; - - -void chess_DrawFrame(uint8_t pos, uint8_t is_bold) -{ - u8g_uint_t x0, y0; - - x0 = pos; - x0 &= 15; - if ( lrc_obj.orientation != COLOR_WHITE ) - x0 ^= 7; - - y0 = pos; - y0>>= 4; - if ( lrc_obj.orientation != COLOR_WHITE ) - y0 ^= 7; - - x0 *= chess_boxsize; - y0 *= chess_boxsize; - - u8g_SetDefaultForegroundColor(lrc_u8g); - u8g_DrawFrame(lrc_u8g, x0, chess_low_edge - y0 - chess_boxsize+1, chess_boxsize, chess_boxsize); - - - if ( is_bold ) - { - x0--; - y0++; - - u8g_DrawFrame(lrc_u8g, x0, chess_low_edge - y0 - chess_boxsize +1, chess_boxsize+2, chess_boxsize+2); - } -} - - -void chess_DrawBoard(void) -{ - uint8_t i, j, cp; - const uint8_t *ptr; /* pointer into PROGMEM */ - - if ( U8G_MODE_GET_BITS_PER_PIXEL(u8g_GetMode(lrc_u8g)) > 1 ) - { - for( i = 0; i < 8; i++ ) - for( j = 0; j < 8; j++ ) - { - uint8_t x,y; - x = i; - x*=chess_boxsize; - y = j; - y*=chess_boxsize; - if ( ((i^j) & 1) == 0 ) - u8g_SetDefaultMidColor(lrc_u8g); - else - u8g_SetDefaultBackgroundColor(lrc_u8g); - u8g_DrawBox(lrc_u8g, x,chess_low_edge-y-chess_boxsize+1,chess_boxsize,chess_boxsize); - } - //u8g_SetDefaultForegroundColor(lrc_u8g); - } - else - { - uint8_t x_offset = 1; - u8g_SetDefaultForegroundColor(lrc_u8g); - for( i = 0; i < 8*8; i+=8 ) - { - for( j = 0; j < 8*8; j+=8 ) - { - if ( ((i^j) & 8) == 0 ) - { - u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-0); - u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-2); - u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-4); - u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-6); - u8g_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-0); - u8g_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-6); - u8g_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-0); - u8g_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-6); - u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-0); - u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-2); - u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-4); - u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-6); - } - } - } - } - - for ( i = 0; i < 8; i++ ) - { - for ( j = 0; j < 8; j++ ) - { - /* get piece from global board */ - if ( lrc_obj.orientation == COLOR_WHITE ) - { - cp = lrc_obj.board[i*8+j]; - } - else - { - cp = lrc_obj.board[(7-i)*8+7-j]; - } - if ( cp_GetPiece(cp) != PIECE_NONE ) - { - ptr = chess_black_pieces_bm; - ptr += (cp_GetPiece(cp)-1)*8; - u8g_SetDefaultForegroundColor(lrc_u8g); - u8g_DrawBitmapP(lrc_u8g, j*chess_boxsize+chess_boxoffset-1, chess_low_edge - (i*chess_boxsize+chess_boxsize-chess_boxoffset), 1, 8, ptr); - - if ( cp_GetColor(cp) == lrc_obj.strike_out_color ) - { - ptr = chess_pieces_body_bm; - ptr += (cp_GetPiece(cp)-1)*8; - u8g_SetDefaultBackgroundColor(lrc_u8g); - u8g_DrawBitmapP(lrc_u8g, j*chess_boxsize+chess_boxoffset-1, chess_low_edge - (i*chess_boxsize+chess_boxsize-chess_boxoffset), 1, 8, ptr); - } - } - } - } - - if ( (chess_source_pos & 0x88) == 0 ) - { - chess_DrawFrame(chess_source_pos, 1); - } - - if ( (chess_target_pos & 0x88) == 0 ) - { - chess_DrawFrame(chess_target_pos, 0); - } - -} - - -void chess_Thinking(void) -{ -} - -void chess_Init(u8g_t *u8g, uint8_t body_color) -{ - lrc_u8g = u8g; - - chess_low_edge = u8g_GetHeight(lrc_u8g); - chess_low_edge--; - - - if ( U8G_MODE_GET_BITS_PER_PIXEL(u8g_GetMode(lrc_u8g)) == 1 ) - { - - chess_boxsize = 8; - chess_boxoffset = 1; - } - else - { - - /* - if ( u8g_GetHeight(lrc_u8g) >= 12*8 ) - { - chess_boxsize = 12; - chess_boxoffset = 3; - } - else */ if ( u8g_GetHeight(lrc_u8g) >= 11*8 ) - { - chess_boxsize = 10; - chess_boxoffset = 2; - } - else - { - chess_boxsize = 8; - chess_boxoffset = 1; - } - - if ( u8g_GetHeight(lrc_u8g) > 64 ) - chess_low_edge -= (u8g_GetHeight(lrc_u8g)-chess_boxsize*8) / 2; - - } - - lrc_obj.strike_out_color = body_color; - chess_SetupBoard(); -} - - - -void chess_Draw(void) -{ - if ( chess_state == CHESS_STATE_MENU ) - { - if ( lrc_obj.ply_count == 0) - mnu_max = 2; - else - mnu_max = 4; - mnu_Draw(); - } - else - { - chess_DrawBoard(); - - { - uint8_t i; - uint8_t entries = lrc_obj.chm_pos; - if ( entries > 4 ) - entries = 4; - - u8g_SetFont(lrc_u8g, u8g_font_5x7); - u8g_SetDefaultForegroundColor(lrc_u8g); - for( i = 0; i < entries; i++ ) - { - -#if defined(DOGXL160_HW_GR) || defined(DOGXL160_HW_BW) - dog_DrawStr(u8g_GetWidth(lrc_u8g)-35, u8g_GetHeight(lrc_u8g)-8*(i+1), font_5x7, cu_GetHalfMoveStr(lrc_obj.chm_pos-entries+i)); -#else - u8g_DrawStr(lrc_u8g, u8g_GetWidth(lrc_u8g)-35, 8*(i+1), cu_GetHalfMoveStr(lrc_obj.chm_pos-entries+i)); -#endif - - } - - } - - if ( chess_state == CHESS_STATE_SELECT_PIECE ) - mnu_DrawHome(chess_source_pos == 255); - else if ( chess_state == CHESS_STATE_SELECT_TARGET_POS ) - mnu_DrawHome(chess_target_pos == 255); - else - mnu_DrawHome(0); - - if ( chess_state == CHESS_STATE_GAME_END ) - { - switch( lrc_obj.lost_side_color ) - { - case COLOR_WHITE: - mnu_DrawEntry(u8g_GetHeight(lrc_u8g) / 2-2, "Black wins", 1, 1); - break; - case COLOR_BLACK: - mnu_DrawEntry(u8g_GetHeight(lrc_u8g) / 2-2, "White wins", 1, 1); - break; - default: - mnu_DrawEntry(u8g_GetHeight(lrc_u8g) / 2-2, "Stalemate", 1, 1); - break; - } - } - } -} - - -void chess_Step(uint8_t keycode) -{ - if ( keycode == CHESS_KEY_NONE ) - { - chess_key_cmd = chess_key_code; - chess_key_code = CHESS_KEY_NONE; - } - else - { - chess_key_cmd = CHESS_KEY_NONE; - chess_key_code = keycode; - } - //chess_ComputerMove(2); - switch(chess_state) - { - case CHESS_STATE_MENU: - mnu_Step(chess_key_cmd); - if ( chess_key_cmd == CHESS_KEY_SELECT ) - { - if ( mnu_pos == 0 ) - { - chess_SetupBoard(); - lrc_obj.orientation = 0; - chess_state = CHESS_STATE_SELECT_START; - } - else if ( mnu_pos == 1 ) - { - chess_SetupBoard(); - lrc_obj.orientation = 1; - chess_state = CHESS_STATE_THINKING; - } - else if ( mnu_pos == 2 ) - { - if ( lrc_obj.ply_count >= 2 ) - { - cu_UndoHalfMove(); - cu_UndoHalfMove(); - lrc_obj.ply_count-=2; - if ( lrc_obj.ply_count == 0 ) - mnu_pos = 0; - } - chess_state = CHESS_STATE_SELECT_START; - } - else if ( mnu_pos == 3 ) - { - chess_state = CHESS_STATE_SELECT_START; - } - } - break; - case CHESS_STATE_SELECT_START: - chess_ClearMarks(); - chess_MarkMovable(); - chess_source_pos = chess_GetNextMarked(255, 0); - chess_target_pos = ILLEGAL_POSITION; - chess_state = CHESS_STATE_SELECT_PIECE; - break; - - case CHESS_STATE_SELECT_PIECE: - if ( chess_key_cmd == CHESS_KEY_NEXT ) - { - chess_source_pos = chess_GetNextMarked(chess_source_pos, 0); - } - else if ( chess_key_cmd == CHESS_KEY_PREV ) - { - chess_source_pos = chess_GetNextMarked(chess_source_pos, 1); - } - else if ( chess_key_cmd == CHESS_KEY_SELECT ) - { - if ( chess_source_pos == 255 ) - { - chess_state = CHESS_STATE_MENU; - } - else - { - chess_ClearMarks(); - chess_MarkTargetMoves(chess_source_pos); - chess_target_pos = chess_GetNextMarked(255, 0); - chess_state = CHESS_STATE_SELECT_TARGET_POS; - } - } - break; - case CHESS_STATE_SELECT_TARGET_POS: - if ( chess_key_cmd == CHESS_KEY_NEXT ) - { - chess_target_pos = chess_GetNextMarked(chess_target_pos, 0); - } - else if ( chess_key_cmd == CHESS_KEY_PREV ) - { - chess_target_pos = chess_GetNextMarked(chess_target_pos, 1); - } - else if ( chess_key_cmd == CHESS_KEY_BACK ) - { - chess_ClearMarks(); - chess_MarkMovable(); - chess_target_pos = ILLEGAL_POSITION; - chess_state = CHESS_STATE_SELECT_PIECE; - } - else if ( chess_key_cmd == CHESS_KEY_SELECT ) - { - chess_ManualMove(chess_source_pos, chess_target_pos); - if ( lrc_obj.is_game_end != 0 ) - chess_state = CHESS_STATE_GAME_END; - else - chess_state = CHESS_STATE_THINKING; - /* clear marks as some kind of feedback to the user... it simply looks better */ - chess_source_pos = ILLEGAL_POSITION; - chess_target_pos = ILLEGAL_POSITION; - chess_ClearMarks(); - } - break; - case CHESS_STATE_THINKING: - chess_ComputerMove(2); - if ( lrc_obj.is_game_end != 0 ) - chess_state = CHESS_STATE_GAME_END; - else - chess_state = CHESS_STATE_SELECT_START; - break; - case CHESS_STATE_GAME_END: - if ( chess_key_cmd != CHESS_KEY_NONE ) - { - chess_state = CHESS_STATE_MENU; - chess_SetupBoard(); - } - break; - } - -} - -#endif - -