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)

Wed, 28 May 2014 15:47:57 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 28 May 2014 15:47:57 +0200
changeset 47
d726e4b46c33
parent 46
4dcfb4c58b6d
child 48
0cedda2544da

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)

src/chess/bishop.c file | annotate | diff | comparison | revisions
src/chess/bishop.h file | annotate | diff | comparison | revisions
src/chess/king.c file | annotate | diff | comparison | revisions
src/chess/king.h file | annotate | diff | comparison | revisions
src/chess/knight.c file | annotate | diff | comparison | revisions
src/chess/knight.h file | annotate | diff | comparison | revisions
src/chess/pawn.c file | annotate | diff | comparison | revisions
src/chess/pawn.h file | annotate | diff | comparison | revisions
src/chess/queen.c file | annotate | diff | comparison | revisions
src/chess/queen.h file | annotate | diff | comparison | revisions
src/chess/rook.c file | annotate | diff | comparison | revisions
src/chess/rook.h file | annotate | diff | comparison | revisions
src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
     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;

mercurial