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)
1.1 --- a/src/chess/bishop.c Thu Apr 17 12:16:14 2014 +0200 1.2 +++ b/src/chess/bishop.c Wed May 28 15:47:57 2014 +0200 1.3 @@ -52,77 +52,3 @@ 1.4 1.5 return 0; 1.6 } 1.7 - 1.8 -static int bishop_getloc_fixedfile(GameState *gamestate, Move *move) { 1.9 - uint8_t d = abs(move->fromfile - move->tofile); 1.10 - if (gamestate->board[move->torow - d][move->fromfile] == move->piece) { 1.11 - move->fromrow = move->torow - d; 1.12 - } 1.13 - if (gamestate->board[move->torow + d][move->fromfile] == move->piece) { 1.14 - if (move->fromrow == POS_UNSPECIFIED) { 1.15 - move->fromrow = move->torow + d; 1.16 - } else { 1.17 - return AMBIGUOUS_MOVE; /* rare situation after promotion */ 1.18 - } 1.19 - } 1.20 - return move->fromrow == POS_UNSPECIFIED ? 1.21 - INVALID_POSITION : VALID_MOVE_SYNTAX; 1.22 -} 1.23 - 1.24 -static int bishop_getloc_fixedrow(GameState *gamestate, Move *move) { 1.25 - uint8_t d = abs(move->fromrow - move->torow); 1.26 - if (gamestate->board[move->fromrow][move->tofile - d] == move->piece) { 1.27 - move->fromfile = move->tofile - d; 1.28 - } 1.29 - if (gamestate->board[move->fromrow][move->tofile + d] == move->piece) { 1.30 - if (move->fromfile == POS_UNSPECIFIED) { 1.31 - move->fromfile = move->tofile + d; 1.32 - } else { 1.33 - return AMBIGUOUS_MOVE; /* rare situation after promotion */ 1.34 - } 1.35 - } 1.36 - return move->fromfile == POS_UNSPECIFIED ? 1.37 - INVALID_POSITION : VALID_MOVE_SYNTAX; 1.38 -} 1.39 - 1.40 -int bishop_getlocation(GameState *gamestate, Move *move) { 1.41 - 1.42 - if (move->fromfile != POS_UNSPECIFIED) { 1.43 - return bishop_getloc_fixedfile(gamestate, move); 1.44 - } 1.45 - 1.46 - if (move->fromrow != POS_UNSPECIFIED) { 1.47 - return bishop_getloc_fixedrow(gamestate, move); 1.48 - } 1.49 - 1.50 - _Bool amb = 0; 1.51 - for (int d = -7 ; d < 8 ; d++) { 1.52 - uint8_t row = move->torow + d; 1.53 - if (isidx(row)) { 1.54 - uint8_t file = move->tofile + d; 1.55 - if (isidx(file) && gamestate->board[row][file] == move->piece) { 1.56 - if (amb) { 1.57 - return AMBIGUOUS_MOVE; 1.58 - } 1.59 - amb = 1; 1.60 - move->fromrow = row; 1.61 - move->fromfile = file; 1.62 - } 1.63 - file = move->tofile - d; 1.64 - if (isidx(file) && gamestate->board[row][file] == move->piece) { 1.65 - if (amb) { 1.66 - return AMBIGUOUS_MOVE; 1.67 - } 1.68 - amb = 1; 1.69 - move->fromrow = row; 1.70 - move->fromfile = file; 1.71 - } 1.72 - } 1.73 - } 1.74 - 1.75 - if (move->fromrow == POS_UNSPECIFIED || move->fromfile == POS_UNSPECIFIED) { 1.76 - return INVALID_POSITION; 1.77 - } else { 1.78 - return VALID_MOVE_SYNTAX; 1.79 - } 1.80 -}
2.1 --- a/src/chess/bishop.h Thu Apr 17 12:16:14 2014 +0200 2.2 +++ b/src/chess/bishop.h Wed May 28 15:47:57 2014 +0200 2.3 @@ -38,7 +38,6 @@ 2.4 2.5 _Bool bishop_chkrules(Move *move); 2.6 _Bool bishop_isblocked(GameState *gamestate, Move *move); 2.7 -int bishop_getlocation(GameState *gamestate, Move *move); 2.8 2.9 #ifdef __cplusplus 2.10 }
3.1 --- a/src/chess/king.c Thu Apr 17 12:16:14 2014 +0200 3.2 +++ b/src/chess/king.c Wed May 28 15:47:57 2014 +0200 3.3 @@ -69,9 +69,11 @@ 3.4 _Bool king_isblocked(GameState *gamestate, Move *move) { 3.5 3.6 uint8_t opponent_color = opponent_color(move->piece&COLOR_MASK); 3.7 - _Bool blocked = is_covered(gamestate, move->torow, move->tofile, 3.8 - opponent_color); 3.9 3.10 + // being in check does not "block" the king, so don't test it here 3.11 + _Bool blocked = 0; 3.12 + 3.13 + // just test, if castling move is blocked 3.14 if (abs(move->tofile - move->fromfile) == 2) { 3.15 if (move->tofile == fileidx('c')) { 3.16 blocked |= gamestate->board[move->torow][fileidx('b')]; 3.17 @@ -84,33 +86,3 @@ 3.18 3.19 return blocked; 3.20 } 3.21 - 3.22 -int king_getlocation(GameState *gamestate, Move *move) { 3.23 - 3.24 - uint8_t file, row; 3.25 - 3.26 - for (int f = -1 ; f <= 1 ; f++) { 3.27 - for (int r = -1 ; r <= 1 ; r++) { 3.28 - if (f == 0 && r == 0) { 3.29 - continue; 3.30 - } 3.31 - file = move->tofile + f; 3.32 - row = move->torow + r; 3.33 - if (isidx(file) && isidx(row)) { 3.34 - if (gamestate->board[row][file] == move->piece) { 3.35 - if ((move->fromfile != POS_UNSPECIFIED 3.36 - && move->fromfile != file) || 3.37 - (move->fromrow != POS_UNSPECIFIED 3.38 - && move->fromrow != row)) { 3.39 - return INVALID_POSITION; 3.40 - } 3.41 - move->fromfile = file; 3.42 - move->fromrow = row; 3.43 - return VALID_MOVE_SYNTAX; 3.44 - } 3.45 - } 3.46 - } 3.47 - } 3.48 - 3.49 - return INVALID_POSITION; 3.50 -}
4.1 --- a/src/chess/king.h Thu Apr 17 12:16:14 2014 +0200 4.2 +++ b/src/chess/king.h Wed May 28 15:47:57 2014 +0200 4.3 @@ -39,7 +39,6 @@ 4.4 4.5 _Bool king_chkrules(GameState *gamestate, Move *move); 4.6 _Bool king_isblocked(GameState *gamestate, Move *move); 4.7 -int king_getlocation(GameState *gamestate, Move *move); 4.8 4.9 #ifdef __cplusplus 4.10 }
5.1 --- a/src/chess/knight.c Thu Apr 17 12:16:14 2014 +0200 5.2 +++ b/src/chess/knight.c Wed May 28 15:47:57 2014 +0200 5.3 @@ -37,98 +37,3 @@ 5.4 5.5 return (dx == 2 && dy == 1) || (dx == 1 && dy == 2); 5.6 } 5.7 - 5.8 -static int knight_getloc_fixedrow(GameState *gamestate, Move *move) { 5.9 - int d = 3 - abs(move->fromrow - move->torow); 5.10 - 5.11 - if (d == 1 || d == 2) { 5.12 - if (move->tofile < 6 && 5.13 - gamestate->board[move->fromrow][move->tofile + d] == move->piece) { 5.14 - if (move->fromfile == POS_UNSPECIFIED) { 5.15 - move->fromfile = move->tofile + d; 5.16 - return VALID_MOVE_SYNTAX; 5.17 - } else { 5.18 - return AMBIGUOUS_MOVE; 5.19 - } 5.20 - } 5.21 - if (move->tofile > 1 && 5.22 - gamestate->board[move->fromrow][move->tofile - d] == move->piece) { 5.23 - if (move->fromfile == POS_UNSPECIFIED) { 5.24 - move->fromfile = move->tofile - d; 5.25 - return VALID_MOVE_SYNTAX; 5.26 - } else { 5.27 - return AMBIGUOUS_MOVE; 5.28 - } 5.29 - } 5.30 - } 5.31 - 5.32 - return INVALID_POSITION; 5.33 -} 5.34 - 5.35 -static int knight_getloc_fixedfile(GameState *gamestate, Move *move) { 5.36 - int d = 3 - abs(move->fromfile - move->tofile); 5.37 - 5.38 - if (d == 1 || d == 2) { 5.39 - if (move->torow < 6 && 5.40 - gamestate->board[move->torow + d][move->fromfile] == move->piece) { 5.41 - if (move->fromrow == POS_UNSPECIFIED) { 5.42 - move->fromrow = move->torow + d; 5.43 - return VALID_MOVE_SYNTAX; 5.44 - } else { 5.45 - return AMBIGUOUS_MOVE; 5.46 - } 5.47 - } 5.48 - if (move->torow > 1 && 5.49 - gamestate->board[move->torow - d][move->fromfile] == move->piece) { 5.50 - if (move->fromrow == POS_UNSPECIFIED) { 5.51 - move->fromrow = move->torow - d; 5.52 - return VALID_MOVE_SYNTAX; 5.53 - } else { 5.54 - return AMBIGUOUS_MOVE; 5.55 - } 5.56 - } 5.57 - } 5.58 - 5.59 - return INVALID_POSITION; 5.60 -} 5.61 - 5.62 -int knight_getlocation(GameState *gamestate, Move *move) { 5.63 - 5.64 - if (move->fromfile != POS_UNSPECIFIED) { 5.65 - return knight_getloc_fixedfile(gamestate, move); 5.66 - } 5.67 - 5.68 - if (move->fromrow != POS_UNSPECIFIED) { 5.69 - return knight_getloc_fixedrow(gamestate, move); 5.70 - } 5.71 - 5.72 - for (int x = -2 ; x <= 2 ; x++) { 5.73 - if (x == 0) { 5.74 - continue; 5.75 - } 5.76 - for (int y = -2 ; y <= 2 ; y++) { 5.77 - if (y == 0 || y == x) { 5.78 - continue; 5.79 - } 5.80 - uint8_t cx = move->tofile + x; 5.81 - uint8_t cy = move->torow + y; 5.82 - 5.83 - if (isidx(cx) && isidx(cy) 5.84 - && gamestate->board[cy][cx] == move->piece) { 5.85 - if (move->fromfile == POS_UNSPECIFIED 5.86 - && move->fromrow == POS_UNSPECIFIED) { 5.87 - move->fromfile = cx; 5.88 - move->fromrow = cy; 5.89 - } else { 5.90 - return AMBIGUOUS_MOVE; 5.91 - } 5.92 - } 5.93 - } 5.94 - } 5.95 - 5.96 - if (move->fromfile == POS_UNSPECIFIED || move->fromrow == POS_UNSPECIFIED) { 5.97 - return INVALID_POSITION; 5.98 - } else { 5.99 - return VALID_MOVE_SYNTAX; 5.100 - } 5.101 -}
6.1 --- a/src/chess/knight.h Thu Apr 17 12:16:14 2014 +0200 6.2 +++ b/src/chess/knight.h Wed May 28 15:47:57 2014 +0200 6.3 @@ -38,7 +38,6 @@ 6.4 6.5 _Bool knight_chkrules(Move *move); 6.6 #define knight_isblocked(gs,m) 0 6.7 -int knight_getlocation(GameState *gamestate, Move *move); 6.8 6.9 #ifdef __cplusplus 6.10 }
7.1 --- a/src/chess/pawn.c Thu Apr 17 12:16:14 2014 +0200 7.2 +++ b/src/chess/pawn.c Wed May 28 15:47:57 2014 +0200 7.3 @@ -71,28 +71,10 @@ 7.4 } 7.5 7.6 _Bool pawn_isblocked(GameState *gamestate, Move *move) { 7.7 - return mdst(gamestate->board, move) && !move->capture; 7.8 + if (move->torow == move->fromrow + 1 || move->torow == move->fromrow - 1) { 7.9 + return mdst(gamestate->board, move) && !move->capture; 7.10 + } else { 7.11 + return mdst(gamestate->board, move) || 7.12 + gamestate->board[(move->fromrow+move->torow)/2][move->tofile]; 7.13 + } 7.14 } 7.15 - 7.16 -int pawn_getlocation(GameState *gamestate, Move *move) { 7.17 - int8_t d = ((move->piece & COLOR_MASK) == WHITE ? -1 : 1); 7.18 - 7.19 - if (move->fromfile == POS_UNSPECIFIED) { 7.20 - move->fromfile = move->tofile; 7.21 - } 7.22 - move->fromrow = move->torow + d; 7.23 - if (move->fromrow > 6) { 7.24 - return INVALID_POSITION; 7.25 - } else { 7.26 - /* advanced first move */ 7.27 - if (move->fromrow == (d < 0 ? 2 : 5) && 7.28 - msrc(gamestate->board,move) != move->piece) { 7.29 - 7.30 - move->fromrow += d; 7.31 - if (move->fromrow > 6) { 7.32 - return INVALID_POSITION; 7.33 - } 7.34 - } 7.35 - } 7.36 - return VALID_MOVE_SYNTAX; 7.37 -}
8.1 --- a/src/chess/pawn.h Thu Apr 17 12:16:14 2014 +0200 8.2 +++ b/src/chess/pawn.h Wed May 28 15:47:57 2014 +0200 8.3 @@ -38,7 +38,6 @@ 8.4 8.5 _Bool pawn_chkrules(GameState *gamestate, Move *move); 8.6 _Bool pawn_isblocked(GameState *gamestate, Move *move); 8.7 -int pawn_getlocation(GameState *gamestate, Move *move); 8.8 8.9 #ifdef __cplusplus 8.10 }
9.1 --- a/src/chess/queen.c Thu Apr 17 12:16:14 2014 +0200 9.2 +++ b/src/chess/queen.c Wed May 28 15:47:57 2014 +0200 9.3 @@ -43,28 +43,3 @@ 9.4 return bishop_isblocked(gamestate, move); 9.5 } 9.6 } 9.7 - 9.8 -int queen_getlocation(GameState *gamestate, Move *move) { 9.9 - 9.10 - Move moveasrook = *move; 9.11 - int rookaspect = rook_getlocation(gamestate, &moveasrook); 9.12 - 9.13 - Move moveasbishop = *move; 9.14 - int bishopaspect = bishop_getlocation(gamestate, &moveasbishop); 9.15 - 9.16 - if (rookaspect == VALID_MOVE_SYNTAX && bishopaspect == VALID_MOVE_SYNTAX) { 9.17 - return AMBIGUOUS_MOVE; 9.18 - } 9.19 - 9.20 - if (rookaspect == VALID_MOVE_SYNTAX) { 9.21 - *move = moveasrook; 9.22 - return VALID_MOVE_SYNTAX; 9.23 - } 9.24 - 9.25 - if (bishopaspect == VALID_MOVE_SYNTAX) { 9.26 - *move = moveasbishop; 9.27 - return VALID_MOVE_SYNTAX; 9.28 - } 9.29 - 9.30 - return INVALID_POSITION; 9.31 -}
10.1 --- a/src/chess/queen.h Thu Apr 17 12:16:14 2014 +0200 10.2 +++ b/src/chess/queen.h Wed May 28 15:47:57 2014 +0200 10.3 @@ -38,7 +38,6 @@ 10.4 10.5 _Bool queen_chkrules(Move *move); 10.6 _Bool queen_isblocked(GameState *gamestate, Move *move); 10.7 -int queen_getlocation(GameState *gamestate, Move *move); 10.8 10.9 #ifdef __cplusplus 10.10 }
11.1 --- a/src/chess/rook.c Thu Apr 17 12:16:14 2014 +0200 11.2 +++ b/src/chess/rook.c Wed May 28 15:47:57 2014 +0200 11.3 @@ -58,95 +58,3 @@ 11.4 11.5 return 0; 11.6 } 11.7 - 11.8 -static int rook_getloc_fixedrow(GameState *gamestate, Move *move) { 11.9 - uint8_t file = POS_UNSPECIFIED; 11.10 - for (uint8_t f = 0 ; f < 8 ; f++) { 11.11 - if (gamestate->board[move->fromrow][f] == move->piece) { 11.12 - if (file == POS_UNSPECIFIED) { 11.13 - file = f; 11.14 - } else { 11.15 - return AMBIGUOUS_MOVE; 11.16 - } 11.17 - } 11.18 - } 11.19 - if (file == POS_UNSPECIFIED) { 11.20 - return INVALID_POSITION; 11.21 - } else { 11.22 - move->fromfile = file; 11.23 - return VALID_MOVE_SYNTAX; 11.24 - } 11.25 -} 11.26 - 11.27 -static int rook_getloc_fixedfile(GameState *gamestate, Move *move) { 11.28 - uint8_t row = POS_UNSPECIFIED; 11.29 - for (uint8_t r = 0 ; r < 8 ; r++) { 11.30 - if (gamestate->board[r][move->fromfile] == move->piece) { 11.31 - if (row == POS_UNSPECIFIED) { 11.32 - row = r; 11.33 - } else { 11.34 - return AMBIGUOUS_MOVE; 11.35 - } 11.36 - } 11.37 - } 11.38 - if (row == POS_UNSPECIFIED) { 11.39 - return INVALID_POSITION; 11.40 - } else { 11.41 - move->fromrow = row; 11.42 - return VALID_MOVE_SYNTAX; 11.43 - } 11.44 -} 11.45 - 11.46 -int rook_getlocation(GameState *gamestate, Move *move) { 11.47 - 11.48 - if (move->fromfile != POS_UNSPECIFIED) { 11.49 - if (move->fromfile == move->tofile) { 11.50 - return rook_getloc_fixedfile(gamestate, move); 11.51 - } else { 11.52 - if (gamestate->board[move->torow][move->fromfile] == move->piece) { 11.53 - move->fromrow = move->torow; 11.54 - return VALID_MOVE_SYNTAX; 11.55 - } else { 11.56 - return INVALID_POSITION; 11.57 - } 11.58 - } 11.59 - } 11.60 - 11.61 - if (move->fromrow != POS_UNSPECIFIED) { 11.62 - if (move->fromrow == move->torow) { 11.63 - return rook_getloc_fixedrow(gamestate, move); 11.64 - } else { 11.65 - if (gamestate->board[move->fromrow][move->tofile] == move->piece) { 11.66 - move->fromfile = move->tofile; 11.67 - return VALID_MOVE_SYNTAX; 11.68 - } else { 11.69 - return INVALID_POSITION; 11.70 - } 11.71 - } 11.72 - } 11.73 - 11.74 - Move chkrowmove = *move, chkfilemove = *move; 11.75 - 11.76 - chkrowmove.fromrow = move->torow; 11.77 - int chkrow = rook_getloc_fixedrow(gamestate, &chkrowmove); 11.78 - 11.79 - chkfilemove.fromfile = move->tofile; 11.80 - int chkfile = rook_getloc_fixedfile(gamestate, &chkfilemove); 11.81 - 11.82 - if ((chkrow == VALID_MOVE_SYNTAX && chkfile == VALID_MOVE_SYNTAX) || 11.83 - chkrow == AMBIGUOUS_MOVE || chkfile == AMBIGUOUS_MOVE) { 11.84 - return AMBIGUOUS_MOVE; 11.85 - } 11.86 - 11.87 - if (chkrow == VALID_MOVE_SYNTAX) { 11.88 - *move = chkrowmove; 11.89 - return VALID_MOVE_SYNTAX; 11.90 - } 11.91 - 11.92 - if (chkfile == VALID_MOVE_SYNTAX) { 11.93 - *move = chkfilemove; 11.94 - return VALID_MOVE_SYNTAX; 11.95 - } 11.96 - 11.97 - return INVALID_POSITION; 11.98 -}
12.1 --- a/src/chess/rook.h Thu Apr 17 12:16:14 2014 +0200 12.2 +++ b/src/chess/rook.h Wed May 28 15:47:57 2014 +0200 12.3 @@ -38,7 +38,6 @@ 12.4 12.5 _Bool rook_chkrules(Move *move); 12.6 _Bool rook_isblocked(GameState *gamestate, Move *move); 12.7 -int rook_getlocation(GameState *gamestate, Move *move); 12.8 12.9 #ifdef __cplusplus 12.10 }
13.1 --- a/src/chess/rules.c Thu Apr 17 12:16:14 2014 +0200 13.2 +++ b/src/chess/rules.c Wed May 28 15:47:57 2014 +0200 13.3 @@ -98,19 +98,6 @@ 13.4 } 13.5 } 13.6 13.7 -static int getlocation(GameState *gamestate, Move *move) { 13.8 - uint8_t piece = move->piece & PIECE_MASK; 13.9 - switch (piece) { 13.10 - case PAWN: return pawn_getlocation(gamestate, move); 13.11 - case ROOK: return rook_getlocation(gamestate, move); 13.12 - case KNIGHT: return knight_getlocation(gamestate, move); 13.13 - case BISHOP: return bishop_getlocation(gamestate, move); 13.14 - case QUEEN: return queen_getlocation(gamestate, move); 13.15 - case KING: return king_getlocation(gamestate, move); 13.16 - default: return INVALID_MOVE_SYNTAX; 13.17 - } 13.18 -} 13.19 - 13.20 void apply_move(GameState *gamestate, Move *move) { 13.21 uint8_t piece = move->piece & PIECE_MASK; 13.22 uint8_t color = move->piece & COLOR_MASK; 13.23 @@ -170,13 +157,20 @@ 13.24 } 13.25 13.26 /* does piece exist */ 13.27 - if (msrc(gamestate->board, move) != move->piece) { 13.28 + if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) 13.29 + != (move->piece&(PIECE_MASK|COLOR_MASK))) { 13.30 return 0; 13.31 } 13.32 13.33 /* can't capture own pieces */ 13.34 if ((mdst(gamestate->board, move) & COLOR_MASK) 13.35 - == (move->piece & COLOR_MASK)) { 13.36 + == (move->piece & COLOR_MASK)) { 13.37 + return 0; 13.38 + } 13.39 + 13.40 + /* must capture, if and only if destination is occupied */ 13.41 + if ((mdst(gamestate->board, move) == 0 && move->capture) || 13.42 + (mdst(gamestate->board, move) != 0 && !move->capture)) { 13.43 return 0; 13.44 } 13.45 13.46 @@ -205,6 +199,7 @@ 13.47 } 13.48 13.49 _Bool validate_move(GameState *gamestate, Move *move) { 13.50 + // TODO: provide more details via a return code 13.51 13.52 _Bool result = validate_move_rules(gamestate, move); 13.53 13.54 @@ -232,9 +227,9 @@ 13.55 } 13.56 13.57 /* simulation move for check validation */ 13.58 - GameState simulation; 13.59 - memcpy(&simulation, gamestate, sizeof(GameState)); 13.60 - apply_move(&simulation, move); 13.61 + GameState simulation = *gamestate; 13.62 + Move simmove = *move; 13.63 + apply_move(&simulation, &simmove); 13.64 13.65 /* don't move into or stay in check position */ 13.66 if (is_covered(&simulation, mykingrow, mykingfile, 13.67 @@ -323,6 +318,155 @@ 13.68 return 1; 13.69 } 13.70 13.71 +_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, 13.72 + uint8_t color, Move *threats, uint8_t *threatcount) { 13.73 + Move candidates[32]; 13.74 + int candidatecount = 0; 13.75 + for (uint8_t r = 0 ; r < 8 ; r++) { 13.76 + for (uint8_t f = 0 ; f < 8 ; f++) { 13.77 + if ((gamestate->board[r][f] & COLOR_MASK) == color) { 13.78 + // non-capturing move 13.79 + memset(&(candidates[candidatecount]), 0, sizeof(Move)); 13.80 + candidates[candidatecount].piece = gamestate->board[r][f]; 13.81 + candidates[candidatecount].fromrow = r; 13.82 + candidates[candidatecount].fromfile = f; 13.83 + candidates[candidatecount].torow = row; 13.84 + candidates[candidatecount].tofile = file; 13.85 + candidatecount++; 13.86 + 13.87 + // capturing move 13.88 + memcpy(&(candidates[candidatecount]), 13.89 + &(candidates[candidatecount-1]), sizeof(Move)); 13.90 + candidates[candidatecount].capture = 1; 13.91 + candidatecount++; 13.92 + } 13.93 + } 13.94 + } 13.95 + 13.96 + if (threatcount) { 13.97 + *threatcount = 0; 13.98 + } 13.99 + 13.100 + 13.101 + _Bool result = 0; 13.102 + 13.103 + for (int i = 0 ; i < candidatecount ; i++) { 13.104 + if (validate_move_rules(gamestate, &(candidates[i]))) { 13.105 + result = 1; 13.106 + if (threats && threatcount) { 13.107 + threats[(*threatcount)++] = candidates[i]; 13.108 + } 13.109 + } 13.110 + } 13.111 + 13.112 + return result; 13.113 +} 13.114 + 13.115 +_Bool is_pinned(GameState *gamestate, Move *move) { 13.116 + uint8_t color = move->piece & COLOR_MASK; 13.117 + 13.118 + uint8_t kingfile = 0, kingrow = 0; 13.119 + for (uint8_t row = 0 ; row < 8 ; row++) { 13.120 + for (uint8_t file = 0 ; file < 8 ; file++) { 13.121 + if (gamestate->board[row][file] == (color|KING)) { 13.122 + kingfile = file; 13.123 + kingrow = row; 13.124 + } 13.125 + } 13.126 + } 13.127 + 13.128 + GameState simulation = *gamestate; 13.129 + Move simmove = *move; 13.130 + apply_move(&simulation, &simmove); 13.131 + return is_covered(&simulation, kingrow, kingfile, opponent_color(color)); 13.132 +} 13.133 + 13.134 +_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, 13.135 + uint8_t color, Move *threats, uint8_t *threatcount) { 13.136 + 13.137 + if (threatcount) { 13.138 + *threatcount = 0; 13.139 + } 13.140 + 13.141 + Move candidates[16]; 13.142 + uint8_t candidatecount; 13.143 + if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { 13.144 + 13.145 + _Bool result = 0; 13.146 + uint8_t kingfile = 0, kingrow = 0; 13.147 + for (uint8_t row = 0 ; row < 8 ; row++) { 13.148 + for (uint8_t file = 0 ; file < 8 ; file++) { 13.149 + if (gamestate->board[row][file] == (color|KING)) { 13.150 + kingfile = file; 13.151 + kingrow = row; 13.152 + } 13.153 + } 13.154 + } 13.155 + 13.156 + for (uint8_t i = 0 ; i < candidatecount ; i++) { 13.157 + GameState simulation = *gamestate; 13.158 + Move simmove = candidates[i]; 13.159 + apply_move(&simulation, &simmove); 13.160 + if (!is_covered(&simulation, kingrow, kingfile, 13.161 + opponent_color(color))) { 13.162 + result = 1; 13.163 + if (threats && threatcount) { 13.164 + threats[(*threatcount)++] = candidates[i]; 13.165 + } 13.166 + } 13.167 + } 13.168 + 13.169 + return result; 13.170 + } else { 13.171 + return 0; 13.172 + } 13.173 +} 13.174 +#include <ncurses.h> 13.175 +static int getlocation(GameState *gamestate, Move *move) { 13.176 + 13.177 + uint8_t color = move->piece & COLOR_MASK; 13.178 + _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; 13.179 + 13.180 + Move threats[16], *threat = NULL; 13.181 + uint8_t threatcount; 13.182 + 13.183 + if (get_threats(gamestate, move->torow, move->tofile, color, 13.184 + threats, &threatcount)) { 13.185 + 13.186 + // find threats for the specified position 13.187 + for (uint8_t i = 0 ; i < threatcount ; i++) { 13.188 + if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) 13.189 + == move->piece && 13.190 + (move->fromrow == POS_UNSPECIFIED || 13.191 + move->fromrow == threats[i].fromrow) && 13.192 + (move->fromfile == POS_UNSPECIFIED || 13.193 + move->fromfile == threats[i].fromfile)) { 13.194 + 13.195 + if (threat) { 13.196 + return AMBIGUOUS_MOVE; 13.197 + } else { 13.198 + threat = &(threats[i]); 13.199 + } 13.200 + } 13.201 + } 13.202 + 13.203 + // can't threaten specified position 13.204 + if (!threat) { 13.205 + return INVALID_POSITION; 13.206 + } 13.207 + 13.208 + // found threat is no real threat 13.209 + if (is_pinned(gamestate, threat)) { 13.210 + return incheck?KING_IN_CHECK:PIECE_PINNED; 13.211 + } else { 13.212 + memcpy(move, threat, sizeof(Move)); 13.213 + return VALID_MOVE_SYNTAX; 13.214 + } 13.215 + } else { 13.216 + return INVALID_POSITION; 13.217 + } 13.218 +} 13.219 + 13.220 int eval_move(GameState *gamestate, char *mstr, Move *move) { 13.221 memset(move, 0, sizeof(Move)); 13.222 move->fromfile = POS_UNSPECIFIED; 13.223 @@ -452,83 +596,6 @@ 13.224 } 13.225 } 13.226 13.227 -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, 13.228 - uint8_t color, Move *threats, uint8_t *threatcount) { 13.229 - Move candidates[16]; 13.230 - int candidatecount = 0; 13.231 - for (uint8_t r = 0 ; r < 8 ; r++) { 13.232 - for (uint8_t f = 0 ; f < 8 ; f++) { 13.233 - if ((gamestate->board[r][f] & COLOR_MASK) == color) { 13.234 - memset(&(candidates[candidatecount]), 0, sizeof(Move)); 13.235 - candidates[candidatecount].piece = gamestate->board[r][f]; 13.236 - candidates[candidatecount].fromrow = r; 13.237 - candidates[candidatecount].fromfile = f; 13.238 - candidates[candidatecount].torow = row; 13.239 - candidates[candidatecount].tofile = file; 13.240 - candidatecount++; 13.241 - } 13.242 - } 13.243 - } 13.244 - 13.245 - if (threatcount) { 13.246 - *threatcount = 0; 13.247 - } 13.248 - 13.249 - 13.250 - _Bool result = 0; 13.251 - 13.252 - for (int i = 0 ; i < candidatecount ; i++) { 13.253 - if (validate_move_rules(gamestate, &(candidates[i]))) { 13.254 - result = 1; 13.255 - if (threats && threatcount) { 13.256 - threats[(*threatcount)++] = candidates[i]; 13.257 - } 13.258 - } 13.259 - } 13.260 - 13.261 - return result; 13.262 -} 13.263 - 13.264 -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, 13.265 - uint8_t color, Move *threats, uint8_t *threatcount) { 13.266 - 13.267 - Move candidates[16]; 13.268 - uint8_t candidatecount; 13.269 - if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { 13.270 - 13.271 - if (threatcount) { 13.272 - *threatcount = 0; 13.273 - } 13.274 - _Bool result = 0; 13.275 - uint8_t kingfile = 0, kingrow = 0; 13.276 - for (uint8_t row = 0 ; row < 8 ; row++) { 13.277 - for (uint8_t file = 0 ; file < 8 ; file++) { 13.278 - if ((gamestate->board[row][file] & COLOR_MASK) == color) { 13.279 - kingfile = file; 13.280 - kingrow = row; 13.281 - } 13.282 - } 13.283 - } 13.284 - 13.285 - for (uint8_t i = 0 ; i < candidatecount ; i++) { 13.286 - GameState simulation; 13.287 - memcpy(&simulation, gamestate, sizeof(GameState)); 13.288 - apply_move(&simulation, &(candidates[i])); 13.289 - if (!is_covered(&simulation, kingrow, kingfile, 13.290 - opponent_color(color))) { 13.291 - result = 1; 13.292 - if (threats && threatcount) { 13.293 - threats[(*threatcount)++] = candidates[i]; 13.294 - } 13.295 - } 13.296 - } 13.297 - 13.298 - return result; 13.299 - } else { 13.300 - return 0; 13.301 - } 13.302 -} 13.303 - 13.304 _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, 13.305 uint8_t color) { 13.306
14.1 --- a/src/chess/rules.h Thu Apr 17 12:16:14 2014 +0200 14.2 +++ b/src/chess/rules.h Wed May 28 15:47:57 2014 +0200 14.3 @@ -38,6 +38,8 @@ 14.4 #define INVALID_POSITION 2 14.5 #define AMBIGUOUS_MOVE 3 14.6 #define NEED_PROMOTION 4 14.7 +#define PIECE_PINNED 5 14.8 +#define KING_IN_CHECK 6 14.9 14.10 14.11 #define PIECE_MASK 0x0F 14.12 @@ -167,9 +169,10 @@ 14.13 * @param row row of the field to check 14.14 * @param file file of the field to check 14.15 * @param color the color of the piece that should threaten the field 14.16 - * @param threats the array where to store the threats (should be able to the 14.17 - * rare maximum of 16 elements) 14.18 - * @param threatcount a pointer to an uint8_t where to store the amount of threats 14.19 + * @param threats the array where to store the threats (should be able to hold 14.20 + * the rare maximum of 16 elements) 14.21 + * @param threatcount a pointer to an uint8_t where the count of threats is 14.22 + * stored 14.23 * @return TRUE, if any piece of the specified color threatens the specified 14.24 * field (i.e. could capture an opponent piece) 14.25 */ 14.26 @@ -187,9 +190,10 @@ 14.27 * @param row row of the field to check 14.28 * @param file file of the field to check 14.29 * @param color the color of the piece that should threaten the field 14.30 - * @param threats the array where to store the threats (should be able to the 14.31 - * rare maximum of 16 elements) 14.32 - * @param threatcount a pointer to an uint8_t where to store the amount of threats 14.33 + * @param threats the array where to store the threats (should be able to hold 14.34 + * the rare maximum of 16 elements) 14.35 + * @param threatcount a pointer to an uint8_t where the count of threats is 14.36 + * stored 14.37 * @return TRUE, if any piece of the specified color threatens the specified 14.38 * field (i.e. could capture an opponent piece) 14.39 */ 14.40 @@ -242,6 +246,22 @@ 14.41 uint8_t color); 14.42 14.43 /** 14.44 + * Checks, if the specified move cannot be performed, because the piece is 14.45 + * either pinned or cannot remove the check. 14.46 + * 14.47 + * Note: in chess a piece is pinned, when it can't be moved because the move 14.48 + * would result in a check position. But this function <u>also</u> returns true, 14.49 + * if the king is already in check position and the specified move does not 14.50 + * protect the king. 14.51 + * 14.52 + * @param gamestate the current game state 14.53 + * @param move the move to check 14.54 + * @return TRUE, if the move cannot be performed because the king would be in 14.55 + * check after the move 14.56 + */ 14.57 +_Bool is_pinned(GameState *gamestate, Move *move); 14.58 + 14.59 +/** 14.60 * Evaluates a move syntactically and stores the move data in the specified 14.61 * object. 14.62 *
15.1 --- a/src/game.c Thu Apr 17 12:16:14 2014 +0200 15.2 +++ b/src/game.c Wed May 28 15:47:57 2014 +0200 15.3 @@ -167,8 +167,17 @@ 15.4 case NEED_PROMOTION: 15.5 printw("You need to promote the pawn (append \"=Q\" e.g.)!"); 15.6 break; 15.7 + case KING_IN_CHECK: 15.8 + printw("Your king is in check!"); 15.9 + break; 15.10 + case PIECE_PINNED: 15.11 + printw("This piece is pinned!"); 15.12 + break; 15.13 + case INVALID_MOVE_SYNTAX: 15.14 + printw("Can't interpret move - please use algebraic notation."); 15.15 + break; 15.16 default: 15.17 - printw("Can't interpret move - please use algebraic notation."); 15.18 + printw("Unknown move parser error."); 15.19 } 15.20 } 15.21
16.1 --- a/src/main.c Thu Apr 17 12:16:14 2014 +0200 16.2 +++ b/src/main.c Wed May 28 15:47:57 2014 +0200 16.3 @@ -41,8 +41,11 @@ 16.4 uint8_t timeunit = 60; 16.5 size_t len; 16.6 16.7 - for (int opt ; (opt = getopt(argc, argv, "a:bhp:rst:")) != -1 ;) { 16.8 + for (int opt ; (opt = getopt(argc, argv, "a:bc:hp:rst:")) != -1 ;) { 16.9 switch (opt) { 16.10 + case 'c': 16.11 + settings->continuepgn = optarg; 16.12 + break; 16.13 case 'b': 16.14 settings->gameinfo.servercolor = BLACK; 16.15 break; 16.16 @@ -108,6 +111,7 @@ 16.17 memset(&settings, 0, sizeof(Settings)); 16.18 settings.gameinfo.servercolor = WHITE; 16.19 settings.port = "27015"; 16.20 + settings.continuepgn = NULL; 16.21 return settings; 16.22 } 16.23 16.24 @@ -147,21 +151,26 @@ 16.25 16.26 if (settings.printhelp) { 16.27 printf( 16.28 - "Usage: terminal-chess [OPTION]... [HOST]\n" 16.29 - "Starts/joins a network chess game\n" 16.30 - "\nGeneral options\n" 16.31 - " -h This help page\n" 16.32 - " -p TCP port to use (default: 27015)\n" 16.33 - "\nServer options\n" 16.34 - " -a <time> Specifies the time to add after each move\n" 16.35 - " -b Server plays black pieces (default: white)\n" 16.36 - " -r Distribute color randomly\n" 16.37 - " -s Single machine mode\n" 16.38 - " -t <time> Specifies time limit (default: no limit)\n" 16.39 - "\nNotes\n" 16.40 - "The time unit for -a is seconds and for -t minutes by default. To " 16.41 - "specify\nseconds for the -t option, use the s suffix.\n" 16.42 - "Example: -t 150s\n" 16.43 +"Usage: terminal-chess [OPTION]... [HOST]\n" 16.44 +"Starts/joins a network chess game\n" 16.45 +"\nGeneral options\n" 16.46 +" -h This help page\n" 16.47 +" -p TCP port to use (default: 27015)\n" 16.48 +"\nServer options\n" 16.49 +" -a <time> Specifies the time to add after each move\n" 16.50 +" -b Server plays black pieces (default: white)\n" 16.51 +// TODO: implement and activate feature 16.52 +//" -c <PGN file> Continue the specified game\n" 16.53 +" -r Distribute color randomly\n" 16.54 +" -s Single machine mode\n" 16.55 +// TODO: implement and activate feature 16.56 +//" -S <PGN file> Compute and print statistics for the specified game\n" 16.57 +" -t <time> Specifies time limit (default: no limit)\n" 16.58 +"\nNotes\n" 16.59 +"The time unit for -a is seconds and for -t minutes by default. To " 16.60 +"specify\nseconds for the -t option, use the s suffix.\n" 16.61 +"Example: -t 150s\n\n" 16.62 +"Use '-' for PGN files to read PGN data from standard input\n" 16.63 ); 16.64 return EXIT_SUCCESS; 16.65 }
17.1 --- a/src/terminal-chess.h Thu Apr 17 12:16:14 2014 +0200 17.2 +++ b/src/terminal-chess.h Wed May 28 15:47:57 2014 +0200 17.3 @@ -44,6 +44,7 @@ 17.4 GameInfo gameinfo; 17.5 char* port; 17.6 char* serverhost; /* NULL, if we are about to start a server */ 17.7 + char* continuepgn; 17.8 _Bool printhelp; 17.9 _Bool singlemachine; 17.10 } Settings;