Wed, 28 May 2014 15:47:57 +0200
refactoring of getlocation mechanism for better short algebraic notation support (does now respect pinned pieces) + fixed a bug where a pawn could advance through a piece (e.g. e2e4 could jump over a piece on e3)
--- a/src/chess/bishop.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/bishop.c Wed May 28 15:47:57 2014 +0200 @@ -52,77 +52,3 @@ return 0; } - -static int bishop_getloc_fixedfile(GameState *gamestate, Move *move) { - uint8_t d = abs(move->fromfile - move->tofile); - if (gamestate->board[move->torow - d][move->fromfile] == move->piece) { - move->fromrow = move->torow - d; - } - if (gamestate->board[move->torow + d][move->fromfile] == move->piece) { - if (move->fromrow == POS_UNSPECIFIED) { - move->fromrow = move->torow + d; - } else { - return AMBIGUOUS_MOVE; /* rare situation after promotion */ - } - } - return move->fromrow == POS_UNSPECIFIED ? - INVALID_POSITION : VALID_MOVE_SYNTAX; -} - -static int bishop_getloc_fixedrow(GameState *gamestate, Move *move) { - uint8_t d = abs(move->fromrow - move->torow); - if (gamestate->board[move->fromrow][move->tofile - d] == move->piece) { - move->fromfile = move->tofile - d; - } - if (gamestate->board[move->fromrow][move->tofile + d] == move->piece) { - if (move->fromfile == POS_UNSPECIFIED) { - move->fromfile = move->tofile + d; - } else { - return AMBIGUOUS_MOVE; /* rare situation after promotion */ - } - } - return move->fromfile == POS_UNSPECIFIED ? - INVALID_POSITION : VALID_MOVE_SYNTAX; -} - -int bishop_getlocation(GameState *gamestate, Move *move) { - - if (move->fromfile != POS_UNSPECIFIED) { - return bishop_getloc_fixedfile(gamestate, move); - } - - if (move->fromrow != POS_UNSPECIFIED) { - return bishop_getloc_fixedrow(gamestate, move); - } - - _Bool amb = 0; - for (int d = -7 ; d < 8 ; d++) { - uint8_t row = move->torow + d; - if (isidx(row)) { - uint8_t file = move->tofile + d; - if (isidx(file) && gamestate->board[row][file] == move->piece) { - if (amb) { - return AMBIGUOUS_MOVE; - } - amb = 1; - move->fromrow = row; - move->fromfile = file; - } - file = move->tofile - d; - if (isidx(file) && gamestate->board[row][file] == move->piece) { - if (amb) { - return AMBIGUOUS_MOVE; - } - amb = 1; - move->fromrow = row; - move->fromfile = file; - } - } - } - - if (move->fromrow == POS_UNSPECIFIED || move->fromfile == POS_UNSPECIFIED) { - return INVALID_POSITION; - } else { - return VALID_MOVE_SYNTAX; - } -}
--- a/src/chess/bishop.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/bishop.h Wed May 28 15:47:57 2014 +0200 @@ -38,7 +38,6 @@ _Bool bishop_chkrules(Move *move); _Bool bishop_isblocked(GameState *gamestate, Move *move); -int bishop_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/king.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/king.c Wed May 28 15:47:57 2014 +0200 @@ -69,9 +69,11 @@ _Bool king_isblocked(GameState *gamestate, Move *move) { uint8_t opponent_color = opponent_color(move->piece&COLOR_MASK); - _Bool blocked = is_covered(gamestate, move->torow, move->tofile, - opponent_color); + // being in check does not "block" the king, so don't test it here + _Bool blocked = 0; + + // just test, if castling move is blocked if (abs(move->tofile - move->fromfile) == 2) { if (move->tofile == fileidx('c')) { blocked |= gamestate->board[move->torow][fileidx('b')]; @@ -84,33 +86,3 @@ return blocked; } - -int king_getlocation(GameState *gamestate, Move *move) { - - uint8_t file, row; - - for (int f = -1 ; f <= 1 ; f++) { - for (int r = -1 ; r <= 1 ; r++) { - if (f == 0 && r == 0) { - continue; - } - file = move->tofile + f; - row = move->torow + r; - if (isidx(file) && isidx(row)) { - if (gamestate->board[row][file] == move->piece) { - if ((move->fromfile != POS_UNSPECIFIED - && move->fromfile != file) || - (move->fromrow != POS_UNSPECIFIED - && move->fromrow != row)) { - return INVALID_POSITION; - } - move->fromfile = file; - move->fromrow = row; - return VALID_MOVE_SYNTAX; - } - } - } - } - - return INVALID_POSITION; -}
--- a/src/chess/king.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/king.h Wed May 28 15:47:57 2014 +0200 @@ -39,7 +39,6 @@ _Bool king_chkrules(GameState *gamestate, Move *move); _Bool king_isblocked(GameState *gamestate, Move *move); -int king_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/knight.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/knight.c Wed May 28 15:47:57 2014 +0200 @@ -37,98 +37,3 @@ return (dx == 2 && dy == 1) || (dx == 1 && dy == 2); } - -static int knight_getloc_fixedrow(GameState *gamestate, Move *move) { - int d = 3 - abs(move->fromrow - move->torow); - - if (d == 1 || d == 2) { - if (move->tofile < 6 && - gamestate->board[move->fromrow][move->tofile + d] == move->piece) { - if (move->fromfile == POS_UNSPECIFIED) { - move->fromfile = move->tofile + d; - return VALID_MOVE_SYNTAX; - } else { - return AMBIGUOUS_MOVE; - } - } - if (move->tofile > 1 && - gamestate->board[move->fromrow][move->tofile - d] == move->piece) { - if (move->fromfile == POS_UNSPECIFIED) { - move->fromfile = move->tofile - d; - return VALID_MOVE_SYNTAX; - } else { - return AMBIGUOUS_MOVE; - } - } - } - - return INVALID_POSITION; -} - -static int knight_getloc_fixedfile(GameState *gamestate, Move *move) { - int d = 3 - abs(move->fromfile - move->tofile); - - if (d == 1 || d == 2) { - if (move->torow < 6 && - gamestate->board[move->torow + d][move->fromfile] == move->piece) { - if (move->fromrow == POS_UNSPECIFIED) { - move->fromrow = move->torow + d; - return VALID_MOVE_SYNTAX; - } else { - return AMBIGUOUS_MOVE; - } - } - if (move->torow > 1 && - gamestate->board[move->torow - d][move->fromfile] == move->piece) { - if (move->fromrow == POS_UNSPECIFIED) { - move->fromrow = move->torow - d; - return VALID_MOVE_SYNTAX; - } else { - return AMBIGUOUS_MOVE; - } - } - } - - return INVALID_POSITION; -} - -int knight_getlocation(GameState *gamestate, Move *move) { - - if (move->fromfile != POS_UNSPECIFIED) { - return knight_getloc_fixedfile(gamestate, move); - } - - if (move->fromrow != POS_UNSPECIFIED) { - return knight_getloc_fixedrow(gamestate, move); - } - - for (int x = -2 ; x <= 2 ; x++) { - if (x == 0) { - continue; - } - for (int y = -2 ; y <= 2 ; y++) { - if (y == 0 || y == x) { - continue; - } - uint8_t cx = move->tofile + x; - uint8_t cy = move->torow + y; - - if (isidx(cx) && isidx(cy) - && gamestate->board[cy][cx] == move->piece) { - if (move->fromfile == POS_UNSPECIFIED - && move->fromrow == POS_UNSPECIFIED) { - move->fromfile = cx; - move->fromrow = cy; - } else { - return AMBIGUOUS_MOVE; - } - } - } - } - - if (move->fromfile == POS_UNSPECIFIED || move->fromrow == POS_UNSPECIFIED) { - return INVALID_POSITION; - } else { - return VALID_MOVE_SYNTAX; - } -}
--- a/src/chess/knight.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/knight.h Wed May 28 15:47:57 2014 +0200 @@ -38,7 +38,6 @@ _Bool knight_chkrules(Move *move); #define knight_isblocked(gs,m) 0 -int knight_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/pawn.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/pawn.c Wed May 28 15:47:57 2014 +0200 @@ -71,28 +71,10 @@ } _Bool pawn_isblocked(GameState *gamestate, Move *move) { - return mdst(gamestate->board, move) && !move->capture; -} - -int pawn_getlocation(GameState *gamestate, Move *move) { - int8_t d = ((move->piece & COLOR_MASK) == WHITE ? -1 : 1); - - if (move->fromfile == POS_UNSPECIFIED) { - move->fromfile = move->tofile; - } - move->fromrow = move->torow + d; - if (move->fromrow > 6) { - return INVALID_POSITION; + if (move->torow == move->fromrow + 1 || move->torow == move->fromrow - 1) { + return mdst(gamestate->board, move) && !move->capture; } else { - /* advanced first move */ - if (move->fromrow == (d < 0 ? 2 : 5) && - msrc(gamestate->board,move) != move->piece) { - - move->fromrow += d; - if (move->fromrow > 6) { - return INVALID_POSITION; - } - } + return mdst(gamestate->board, move) || + gamestate->board[(move->fromrow+move->torow)/2][move->tofile]; } - return VALID_MOVE_SYNTAX; }
--- a/src/chess/pawn.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/pawn.h Wed May 28 15:47:57 2014 +0200 @@ -38,7 +38,6 @@ _Bool pawn_chkrules(GameState *gamestate, Move *move); _Bool pawn_isblocked(GameState *gamestate, Move *move); -int pawn_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/queen.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/queen.c Wed May 28 15:47:57 2014 +0200 @@ -43,28 +43,3 @@ return bishop_isblocked(gamestate, move); } } - -int queen_getlocation(GameState *gamestate, Move *move) { - - Move moveasrook = *move; - int rookaspect = rook_getlocation(gamestate, &moveasrook); - - Move moveasbishop = *move; - int bishopaspect = bishop_getlocation(gamestate, &moveasbishop); - - if (rookaspect == VALID_MOVE_SYNTAX && bishopaspect == VALID_MOVE_SYNTAX) { - return AMBIGUOUS_MOVE; - } - - if (rookaspect == VALID_MOVE_SYNTAX) { - *move = moveasrook; - return VALID_MOVE_SYNTAX; - } - - if (bishopaspect == VALID_MOVE_SYNTAX) { - *move = moveasbishop; - return VALID_MOVE_SYNTAX; - } - - return INVALID_POSITION; -}
--- a/src/chess/queen.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/queen.h Wed May 28 15:47:57 2014 +0200 @@ -38,7 +38,6 @@ _Bool queen_chkrules(Move *move); _Bool queen_isblocked(GameState *gamestate, Move *move); -int queen_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/rook.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/rook.c Wed May 28 15:47:57 2014 +0200 @@ -58,95 +58,3 @@ return 0; } - -static int rook_getloc_fixedrow(GameState *gamestate, Move *move) { - uint8_t file = POS_UNSPECIFIED; - for (uint8_t f = 0 ; f < 8 ; f++) { - if (gamestate->board[move->fromrow][f] == move->piece) { - if (file == POS_UNSPECIFIED) { - file = f; - } else { - return AMBIGUOUS_MOVE; - } - } - } - if (file == POS_UNSPECIFIED) { - return INVALID_POSITION; - } else { - move->fromfile = file; - return VALID_MOVE_SYNTAX; - } -} - -static int rook_getloc_fixedfile(GameState *gamestate, Move *move) { - uint8_t row = POS_UNSPECIFIED; - for (uint8_t r = 0 ; r < 8 ; r++) { - if (gamestate->board[r][move->fromfile] == move->piece) { - if (row == POS_UNSPECIFIED) { - row = r; - } else { - return AMBIGUOUS_MOVE; - } - } - } - if (row == POS_UNSPECIFIED) { - return INVALID_POSITION; - } else { - move->fromrow = row; - return VALID_MOVE_SYNTAX; - } -} - -int rook_getlocation(GameState *gamestate, Move *move) { - - if (move->fromfile != POS_UNSPECIFIED) { - if (move->fromfile == move->tofile) { - return rook_getloc_fixedfile(gamestate, move); - } else { - if (gamestate->board[move->torow][move->fromfile] == move->piece) { - move->fromrow = move->torow; - return VALID_MOVE_SYNTAX; - } else { - return INVALID_POSITION; - } - } - } - - if (move->fromrow != POS_UNSPECIFIED) { - if (move->fromrow == move->torow) { - return rook_getloc_fixedrow(gamestate, move); - } else { - if (gamestate->board[move->fromrow][move->tofile] == move->piece) { - move->fromfile = move->tofile; - return VALID_MOVE_SYNTAX; - } else { - return INVALID_POSITION; - } - } - } - - Move chkrowmove = *move, chkfilemove = *move; - - chkrowmove.fromrow = move->torow; - int chkrow = rook_getloc_fixedrow(gamestate, &chkrowmove); - - chkfilemove.fromfile = move->tofile; - int chkfile = rook_getloc_fixedfile(gamestate, &chkfilemove); - - if ((chkrow == VALID_MOVE_SYNTAX && chkfile == VALID_MOVE_SYNTAX) || - chkrow == AMBIGUOUS_MOVE || chkfile == AMBIGUOUS_MOVE) { - return AMBIGUOUS_MOVE; - } - - if (chkrow == VALID_MOVE_SYNTAX) { - *move = chkrowmove; - return VALID_MOVE_SYNTAX; - } - - if (chkfile == VALID_MOVE_SYNTAX) { - *move = chkfilemove; - return VALID_MOVE_SYNTAX; - } - - return INVALID_POSITION; -}
--- a/src/chess/rook.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/rook.h Wed May 28 15:47:57 2014 +0200 @@ -38,7 +38,6 @@ _Bool rook_chkrules(Move *move); _Bool rook_isblocked(GameState *gamestate, Move *move); -int rook_getlocation(GameState *gamestate, Move *move); #ifdef __cplusplus }
--- a/src/chess/rules.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/rules.c Wed May 28 15:47:57 2014 +0200 @@ -98,19 +98,6 @@ } } -static int getlocation(GameState *gamestate, Move *move) { - uint8_t piece = move->piece & PIECE_MASK; - switch (piece) { - case PAWN: return pawn_getlocation(gamestate, move); - case ROOK: return rook_getlocation(gamestate, move); - case KNIGHT: return knight_getlocation(gamestate, move); - case BISHOP: return bishop_getlocation(gamestate, move); - case QUEEN: return queen_getlocation(gamestate, move); - case KING: return king_getlocation(gamestate, move); - default: return INVALID_MOVE_SYNTAX; - } -} - void apply_move(GameState *gamestate, Move *move) { uint8_t piece = move->piece & PIECE_MASK; uint8_t color = move->piece & COLOR_MASK; @@ -170,13 +157,20 @@ } /* does piece exist */ - if (msrc(gamestate->board, move) != move->piece) { + if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) + != (move->piece&(PIECE_MASK|COLOR_MASK))) { return 0; } /* can't capture own pieces */ if ((mdst(gamestate->board, move) & COLOR_MASK) - == (move->piece & COLOR_MASK)) { + == (move->piece & COLOR_MASK)) { + return 0; + } + + /* must capture, if and only if destination is occupied */ + if ((mdst(gamestate->board, move) == 0 && move->capture) || + (mdst(gamestate->board, move) != 0 && !move->capture)) { return 0; } @@ -205,6 +199,7 @@ } _Bool validate_move(GameState *gamestate, Move *move) { + // TODO: provide more details via a return code _Bool result = validate_move_rules(gamestate, move); @@ -232,9 +227,9 @@ } /* simulation move for check validation */ - GameState simulation; - memcpy(&simulation, gamestate, sizeof(GameState)); - apply_move(&simulation, move); + GameState simulation = *gamestate; + Move simmove = *move; + apply_move(&simulation, &simmove); /* don't move into or stay in check position */ if (is_covered(&simulation, mykingrow, mykingfile, @@ -323,6 +318,155 @@ return 1; } +_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, + uint8_t color, Move *threats, uint8_t *threatcount) { + Move candidates[32]; + int candidatecount = 0; + for (uint8_t r = 0 ; r < 8 ; r++) { + for (uint8_t f = 0 ; f < 8 ; f++) { + if ((gamestate->board[r][f] & COLOR_MASK) == color) { + // non-capturing move + memset(&(candidates[candidatecount]), 0, sizeof(Move)); + candidates[candidatecount].piece = gamestate->board[r][f]; + candidates[candidatecount].fromrow = r; + candidates[candidatecount].fromfile = f; + candidates[candidatecount].torow = row; + candidates[candidatecount].tofile = file; + candidatecount++; + + // capturing move + memcpy(&(candidates[candidatecount]), + &(candidates[candidatecount-1]), sizeof(Move)); + candidates[candidatecount].capture = 1; + candidatecount++; + } + } + } + + if (threatcount) { + *threatcount = 0; + } + + + _Bool result = 0; + + for (int i = 0 ; i < candidatecount ; i++) { + if (validate_move_rules(gamestate, &(candidates[i]))) { + result = 1; + if (threats && threatcount) { + threats[(*threatcount)++] = candidates[i]; + } + } + } + + return result; +} + +_Bool is_pinned(GameState *gamestate, Move *move) { + uint8_t color = move->piece & COLOR_MASK; + + uint8_t kingfile = 0, kingrow = 0; + for (uint8_t row = 0 ; row < 8 ; row++) { + for (uint8_t file = 0 ; file < 8 ; file++) { + if (gamestate->board[row][file] == (color|KING)) { + kingfile = file; + kingrow = row; + } + } + } + + GameState simulation = *gamestate; + Move simmove = *move; + apply_move(&simulation, &simmove); + return is_covered(&simulation, kingrow, kingfile, opponent_color(color)); +} + +_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, + uint8_t color, Move *threats, uint8_t *threatcount) { + + if (threatcount) { + *threatcount = 0; + } + + Move candidates[16]; + uint8_t candidatecount; + if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { + + _Bool result = 0; + uint8_t kingfile = 0, kingrow = 0; + for (uint8_t row = 0 ; row < 8 ; row++) { + for (uint8_t file = 0 ; file < 8 ; file++) { + if (gamestate->board[row][file] == (color|KING)) { + kingfile = file; + kingrow = row; + } + } + } + + for (uint8_t i = 0 ; i < candidatecount ; i++) { + GameState simulation = *gamestate; + Move simmove = candidates[i]; + apply_move(&simulation, &simmove); + if (!is_covered(&simulation, kingrow, kingfile, + opponent_color(color))) { + result = 1; + if (threats && threatcount) { + threats[(*threatcount)++] = candidates[i]; + } + } + } + + return result; + } else { + return 0; + } +} +#include <ncurses.h> +static int getlocation(GameState *gamestate, Move *move) { + + uint8_t color = move->piece & COLOR_MASK; + _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; + + Move threats[16], *threat = NULL; + uint8_t threatcount; + + if (get_threats(gamestate, move->torow, move->tofile, color, + threats, &threatcount)) { + + // find threats for the specified position + for (uint8_t i = 0 ; i < threatcount ; i++) { + if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) + == move->piece && + (move->fromrow == POS_UNSPECIFIED || + move->fromrow == threats[i].fromrow) && + (move->fromfile == POS_UNSPECIFIED || + move->fromfile == threats[i].fromfile)) { + + if (threat) { + return AMBIGUOUS_MOVE; + } else { + threat = &(threats[i]); + } + } + } + + // can't threaten specified position + if (!threat) { + return INVALID_POSITION; + } + + // found threat is no real threat + if (is_pinned(gamestate, threat)) { + return incheck?KING_IN_CHECK:PIECE_PINNED; + } else { + memcpy(move, threat, sizeof(Move)); + return VALID_MOVE_SYNTAX; + } + } else { + return INVALID_POSITION; + } +} + int eval_move(GameState *gamestate, char *mstr, Move *move) { memset(move, 0, sizeof(Move)); move->fromfile = POS_UNSPECIFIED; @@ -452,83 +596,6 @@ } } -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - Move candidates[16]; - int candidatecount = 0; - for (uint8_t r = 0 ; r < 8 ; r++) { - for (uint8_t f = 0 ; f < 8 ; f++) { - if ((gamestate->board[r][f] & COLOR_MASK) == color) { - memset(&(candidates[candidatecount]), 0, sizeof(Move)); - candidates[candidatecount].piece = gamestate->board[r][f]; - candidates[candidatecount].fromrow = r; - candidates[candidatecount].fromfile = f; - candidates[candidatecount].torow = row; - candidates[candidatecount].tofile = file; - candidatecount++; - } - } - } - - if (threatcount) { - *threatcount = 0; - } - - - _Bool result = 0; - - for (int i = 0 ; i < candidatecount ; i++) { - if (validate_move_rules(gamestate, &(candidates[i]))) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; -} - -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move *threats, uint8_t *threatcount) { - - Move candidates[16]; - uint8_t candidatecount; - if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { - - if (threatcount) { - *threatcount = 0; - } - _Bool result = 0; - uint8_t kingfile = 0, kingrow = 0; - for (uint8_t row = 0 ; row < 8 ; row++) { - for (uint8_t file = 0 ; file < 8 ; file++) { - if ((gamestate->board[row][file] & COLOR_MASK) == color) { - kingfile = file; - kingrow = row; - } - } - } - - for (uint8_t i = 0 ; i < candidatecount ; i++) { - GameState simulation; - memcpy(&simulation, gamestate, sizeof(GameState)); - apply_move(&simulation, &(candidates[i])); - if (!is_covered(&simulation, kingrow, kingfile, - opponent_color(color))) { - result = 1; - if (threats && threatcount) { - threats[(*threatcount)++] = candidates[i]; - } - } - } - - return result; - } else { - return 0; - } -} - _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, uint8_t color) {
--- a/src/chess/rules.h Thu Apr 17 12:16:14 2014 +0200 +++ b/src/chess/rules.h Wed May 28 15:47:57 2014 +0200 @@ -38,6 +38,8 @@ #define INVALID_POSITION 2 #define AMBIGUOUS_MOVE 3 #define NEED_PROMOTION 4 +#define PIECE_PINNED 5 +#define KING_IN_CHECK 6 #define PIECE_MASK 0x0F @@ -167,9 +169,10 @@ * @param row row of the field to check * @param file file of the field to check * @param color the color of the piece that should threaten the field - * @param threats the array where to store the threats (should be able to the - * rare maximum of 16 elements) - * @param threatcount a pointer to an uint8_t where to store the amount of threats + * @param threats the array where to store the threats (should be able to hold + * the rare maximum of 16 elements) + * @param threatcount a pointer to an uint8_t where the count of threats is + * stored * @return TRUE, if any piece of the specified color threatens the specified * field (i.e. could capture an opponent piece) */ @@ -187,9 +190,10 @@ * @param row row of the field to check * @param file file of the field to check * @param color the color of the piece that should threaten the field - * @param threats the array where to store the threats (should be able to the - * rare maximum of 16 elements) - * @param threatcount a pointer to an uint8_t where to store the amount of threats + * @param threats the array where to store the threats (should be able to hold + * the rare maximum of 16 elements) + * @param threatcount a pointer to an uint8_t where the count of threats is + * stored * @return TRUE, if any piece of the specified color threatens the specified * field (i.e. could capture an opponent piece) */ @@ -242,6 +246,22 @@ uint8_t color); /** + * Checks, if the specified move cannot be performed, because the piece is + * either pinned or cannot remove the check. + * + * Note: in chess a piece is pinned, when it can't be moved because the move + * would result in a check position. But this function <u>also</u> returns true, + * if the king is already in check position and the specified move does not + * protect the king. + * + * @param gamestate the current game state + * @param move the move to check + * @return TRUE, if the move cannot be performed because the king would be in + * check after the move + */ +_Bool is_pinned(GameState *gamestate, Move *move); + +/** * Evaluates a move syntactically and stores the move data in the specified * object. *
--- a/src/game.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/game.c Wed May 28 15:47:57 2014 +0200 @@ -167,8 +167,17 @@ case NEED_PROMOTION: printw("You need to promote the pawn (append \"=Q\" e.g.)!"); break; + case KING_IN_CHECK: + printw("Your king is in check!"); + break; + case PIECE_PINNED: + printw("This piece is pinned!"); + break; + case INVALID_MOVE_SYNTAX: + printw("Can't interpret move - please use algebraic notation."); + break; default: - printw("Can't interpret move - please use algebraic notation."); + printw("Unknown move parser error."); } }
--- a/src/main.c Thu Apr 17 12:16:14 2014 +0200 +++ b/src/main.c Wed May 28 15:47:57 2014 +0200 @@ -41,8 +41,11 @@ uint8_t timeunit = 60; size_t len; - for (int opt ; (opt = getopt(argc, argv, "a:bhp:rst:")) != -1 ;) { + for (int opt ; (opt = getopt(argc, argv, "a:bc:hp:rst:")) != -1 ;) { switch (opt) { + case 'c': + settings->continuepgn = optarg; + break; case 'b': settings->gameinfo.servercolor = BLACK; break; @@ -108,6 +111,7 @@ memset(&settings, 0, sizeof(Settings)); settings.gameinfo.servercolor = WHITE; settings.port = "27015"; + settings.continuepgn = NULL; return settings; } @@ -147,21 +151,26 @@ if (settings.printhelp) { printf( - "Usage: terminal-chess [OPTION]... [HOST]\n" - "Starts/joins a network chess game\n" - "\nGeneral options\n" - " -h This help page\n" - " -p TCP port to use (default: 27015)\n" - "\nServer options\n" - " -a <time> Specifies the time to add after each move\n" - " -b Server plays black pieces (default: white)\n" - " -r Distribute color randomly\n" - " -s Single machine mode\n" - " -t <time> Specifies time limit (default: no limit)\n" - "\nNotes\n" - "The time unit for -a is seconds and for -t minutes by default. To " - "specify\nseconds for the -t option, use the s suffix.\n" - "Example: -t 150s\n" +"Usage: terminal-chess [OPTION]... [HOST]\n" +"Starts/joins a network chess game\n" +"\nGeneral options\n" +" -h This help page\n" +" -p TCP port to use (default: 27015)\n" +"\nServer options\n" +" -a <time> Specifies the time to add after each move\n" +" -b Server plays black pieces (default: white)\n" +// TODO: implement and activate feature +//" -c <PGN file> Continue the specified game\n" +" -r Distribute color randomly\n" +" -s Single machine mode\n" +// TODO: implement and activate feature +//" -S <PGN file> Compute and print statistics for the specified game\n" +" -t <time> Specifies time limit (default: no limit)\n" +"\nNotes\n" +"The time unit for -a is seconds and for -t minutes by default. To " +"specify\nseconds for the -t option, use the s suffix.\n" +"Example: -t 150s\n\n" +"Use '-' for PGN files to read PGN data from standard input\n" ); return EXIT_SUCCESS; }