src/chess/rules.c

changeset 47
d726e4b46c33
parent 40
47162a7621da
child 48
0cedda2544da
     1.1 --- a/src/chess/rules.c	Thu Apr 17 12:16:14 2014 +0200
     1.2 +++ b/src/chess/rules.c	Wed May 28 15:47:57 2014 +0200
     1.3 @@ -98,19 +98,6 @@
     1.4      }
     1.5  }
     1.6  
     1.7 -static int getlocation(GameState *gamestate, Move *move) {   
     1.8 -    uint8_t piece = move->piece & PIECE_MASK;
     1.9 -    switch (piece) {
    1.10 -        case PAWN: return pawn_getlocation(gamestate, move);
    1.11 -        case ROOK: return rook_getlocation(gamestate, move);
    1.12 -        case KNIGHT: return knight_getlocation(gamestate, move);
    1.13 -        case BISHOP: return bishop_getlocation(gamestate, move);
    1.14 -        case QUEEN: return queen_getlocation(gamestate, move);
    1.15 -        case KING: return king_getlocation(gamestate, move);
    1.16 -        default: return INVALID_MOVE_SYNTAX;
    1.17 -    }
    1.18 -}
    1.19 -
    1.20  void apply_move(GameState *gamestate, Move *move) {
    1.21      uint8_t piece = move->piece & PIECE_MASK;
    1.22      uint8_t color = move->piece & COLOR_MASK;
    1.23 @@ -170,13 +157,20 @@
    1.24      }
    1.25      
    1.26      /* does piece exist */
    1.27 -    if (msrc(gamestate->board, move) != move->piece) {
    1.28 +    if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK))
    1.29 +           != (move->piece&(PIECE_MASK|COLOR_MASK))) {
    1.30          return 0;
    1.31      }
    1.32      
    1.33      /* can't capture own pieces */
    1.34      if ((mdst(gamestate->board, move) & COLOR_MASK)
    1.35 -        == (move->piece & COLOR_MASK)) {
    1.36 +            == (move->piece & COLOR_MASK)) {
    1.37 +        return 0;
    1.38 +    }
    1.39 +    
    1.40 +    /* must capture, if and only if destination is occupied */
    1.41 +    if ((mdst(gamestate->board, move) == 0 && move->capture) ||
    1.42 +            (mdst(gamestate->board, move) != 0 && !move->capture)) {
    1.43          return 0;
    1.44      }
    1.45      
    1.46 @@ -205,6 +199,7 @@
    1.47  }
    1.48  
    1.49  _Bool validate_move(GameState *gamestate, Move *move) {
    1.50 +    // TODO: provide more details via a return code
    1.51      
    1.52      _Bool result = validate_move_rules(gamestate, move);
    1.53      
    1.54 @@ -232,9 +227,9 @@
    1.55      }
    1.56      
    1.57      /* simulation move for check validation */
    1.58 -    GameState simulation;
    1.59 -    memcpy(&simulation, gamestate, sizeof(GameState));
    1.60 -    apply_move(&simulation, move);
    1.61 +    GameState simulation = *gamestate;
    1.62 +    Move simmove = *move;
    1.63 +    apply_move(&simulation, &simmove);
    1.64      
    1.65      /* don't move into or stay in check position */
    1.66      if (is_covered(&simulation, mykingrow, mykingfile,
    1.67 @@ -323,6 +318,155 @@
    1.68      return 1;
    1.69  }
    1.70  
    1.71 +_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file,
    1.72 +        uint8_t color, Move *threats, uint8_t *threatcount) {
    1.73 +    Move candidates[32];
    1.74 +    int candidatecount = 0;
    1.75 +    for (uint8_t r = 0 ; r < 8 ; r++) {
    1.76 +        for (uint8_t f = 0 ; f < 8 ; f++) {
    1.77 +            if ((gamestate->board[r][f] & COLOR_MASK) == color) {
    1.78 +                // non-capturing move
    1.79 +                memset(&(candidates[candidatecount]), 0, sizeof(Move));
    1.80 +                candidates[candidatecount].piece = gamestate->board[r][f];
    1.81 +                candidates[candidatecount].fromrow = r;
    1.82 +                candidates[candidatecount].fromfile = f;
    1.83 +                candidates[candidatecount].torow = row;
    1.84 +                candidates[candidatecount].tofile = file;
    1.85 +                candidatecount++;
    1.86 +
    1.87 +                // capturing move
    1.88 +                memcpy(&(candidates[candidatecount]),
    1.89 +                    &(candidates[candidatecount-1]), sizeof(Move));
    1.90 +                candidates[candidatecount].capture = 1;
    1.91 +                candidatecount++;
    1.92 +            }
    1.93 +        }
    1.94 +    }
    1.95 +
    1.96 +    if (threatcount) {
    1.97 +        *threatcount = 0;
    1.98 +    }
    1.99 +    
   1.100 +    
   1.101 +    _Bool result = 0;
   1.102 +    
   1.103 +    for (int i = 0 ; i < candidatecount ; i++) {
   1.104 +        if (validate_move_rules(gamestate, &(candidates[i]))) {
   1.105 +            result = 1;
   1.106 +            if (threats && threatcount) {
   1.107 +                threats[(*threatcount)++] = candidates[i];
   1.108 +            }
   1.109 +        }
   1.110 +    }
   1.111 +    
   1.112 +    return result;
   1.113 +}
   1.114 +
   1.115 +_Bool is_pinned(GameState *gamestate, Move *move) {
   1.116 +    uint8_t color = move->piece & COLOR_MASK;
   1.117 +
   1.118 +    uint8_t kingfile = 0, kingrow = 0;
   1.119 +    for (uint8_t row = 0 ; row < 8 ; row++) {
   1.120 +        for (uint8_t file = 0 ; file < 8 ; file++) {
   1.121 +            if (gamestate->board[row][file] == (color|KING)) {
   1.122 +                kingfile = file;
   1.123 +                kingrow = row;
   1.124 +            }
   1.125 +        }
   1.126 +    }
   1.127 +
   1.128 +    GameState simulation = *gamestate;
   1.129 +    Move simmove = *move;
   1.130 +    apply_move(&simulation, &simmove);
   1.131 +    return is_covered(&simulation, kingrow, kingfile, opponent_color(color));
   1.132 +}
   1.133 +
   1.134 +_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file,
   1.135 +        uint8_t color, Move *threats, uint8_t *threatcount) {
   1.136 +    
   1.137 +    if (threatcount) {
   1.138 +        *threatcount = 0;
   1.139 +    }
   1.140 +
   1.141 +    Move candidates[16];
   1.142 +    uint8_t candidatecount;
   1.143 +    if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) {
   1.144 +        
   1.145 +        _Bool result = 0;
   1.146 +        uint8_t kingfile = 0, kingrow = 0;
   1.147 +        for (uint8_t row = 0 ; row < 8 ; row++) {
   1.148 +            for (uint8_t file = 0 ; file < 8 ; file++) {
   1.149 +                if (gamestate->board[row][file] == (color|KING)) {
   1.150 +                    kingfile = file;
   1.151 +                    kingrow = row;
   1.152 +                }
   1.153 +            }
   1.154 +        }
   1.155 +
   1.156 +        for (uint8_t i = 0 ; i < candidatecount ; i++) {
   1.157 +            GameState simulation = *gamestate;
   1.158 +            Move simmove = candidates[i];
   1.159 +            apply_move(&simulation, &simmove);
   1.160 +            if (!is_covered(&simulation, kingrow, kingfile,
   1.161 +                    opponent_color(color))) {
   1.162 +                result = 1;
   1.163 +                if (threats && threatcount) {
   1.164 +                    threats[(*threatcount)++] = candidates[i];
   1.165 +                }
   1.166 +            }
   1.167 +        }
   1.168 +        
   1.169 +        return result;
   1.170 +    } else {
   1.171 +        return 0;
   1.172 +    }
   1.173 +}
   1.174 +#include <ncurses.h>
   1.175 +static int getlocation(GameState *gamestate, Move *move) {   
   1.176 +
   1.177 +    uint8_t color = move->piece & COLOR_MASK;
   1.178 +    _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0;
   1.179 +    
   1.180 +    Move threats[16], *threat = NULL;
   1.181 +    uint8_t threatcount;
   1.182 +    
   1.183 +    if (get_threats(gamestate, move->torow, move->tofile, color,
   1.184 +            threats, &threatcount)) {
   1.185 +        
   1.186 +        // find threats for the specified position
   1.187 +        for (uint8_t i = 0 ; i < threatcount ; i++) {
   1.188 +            if ((threats[i].piece & (PIECE_MASK | COLOR_MASK))
   1.189 +                    == move->piece &&
   1.190 +                    (move->fromrow == POS_UNSPECIFIED ||
   1.191 +                    move->fromrow == threats[i].fromrow) &&
   1.192 +                    (move->fromfile == POS_UNSPECIFIED ||
   1.193 +                    move->fromfile == threats[i].fromfile)) {
   1.194 +
   1.195 +                if (threat) {
   1.196 +                    return AMBIGUOUS_MOVE;
   1.197 +                } else {
   1.198 +                    threat = &(threats[i]);
   1.199 +                }
   1.200 +            }
   1.201 +        }
   1.202 +        
   1.203 +        // can't threaten specified position
   1.204 +        if (!threat) {
   1.205 +            return INVALID_POSITION;
   1.206 +        }
   1.207 +
   1.208 +        // found threat is no real threat
   1.209 +        if (is_pinned(gamestate, threat)) {
   1.210 +            return incheck?KING_IN_CHECK:PIECE_PINNED;
   1.211 +        } else {
   1.212 +            memcpy(move, threat, sizeof(Move));
   1.213 +            return VALID_MOVE_SYNTAX;
   1.214 +        }
   1.215 +    } else {
   1.216 +        return INVALID_POSITION;
   1.217 +    }
   1.218 +}
   1.219 +
   1.220  int eval_move(GameState *gamestate, char *mstr, Move *move) {
   1.221      memset(move, 0, sizeof(Move));
   1.222      move->fromfile = POS_UNSPECIFIED;
   1.223 @@ -452,83 +596,6 @@
   1.224      }
   1.225  }
   1.226  
   1.227 -_Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file,
   1.228 -        uint8_t color, Move *threats, uint8_t *threatcount) {
   1.229 -    Move candidates[16];
   1.230 -    int candidatecount = 0;
   1.231 -    for (uint8_t r = 0 ; r < 8 ; r++) {
   1.232 -        for (uint8_t f = 0 ; f < 8 ; f++) {
   1.233 -            if ((gamestate->board[r][f] & COLOR_MASK) == color) {
   1.234 -                memset(&(candidates[candidatecount]), 0, sizeof(Move));
   1.235 -                candidates[candidatecount].piece = gamestate->board[r][f];
   1.236 -                candidates[candidatecount].fromrow = r;
   1.237 -                candidates[candidatecount].fromfile = f;
   1.238 -                candidates[candidatecount].torow = row;
   1.239 -                candidates[candidatecount].tofile = file;
   1.240 -                candidatecount++;
   1.241 -            }
   1.242 -        }
   1.243 -    }
   1.244 -
   1.245 -    if (threatcount) {
   1.246 -        *threatcount = 0;
   1.247 -    }
   1.248 -    
   1.249 -    
   1.250 -    _Bool result = 0;
   1.251 -    
   1.252 -    for (int i = 0 ; i < candidatecount ; i++) {
   1.253 -        if (validate_move_rules(gamestate, &(candidates[i]))) {
   1.254 -            result = 1;
   1.255 -            if (threats && threatcount) {
   1.256 -                threats[(*threatcount)++] = candidates[i];
   1.257 -            }
   1.258 -        }
   1.259 -    }
   1.260 -    
   1.261 -    return result;
   1.262 -}
   1.263 -
   1.264 -_Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file,
   1.265 -        uint8_t color, Move *threats, uint8_t *threatcount) {
   1.266 -
   1.267 -    Move candidates[16];
   1.268 -    uint8_t candidatecount;
   1.269 -    if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) {
   1.270 -        
   1.271 -        if (threatcount) {
   1.272 -            *threatcount = 0;
   1.273 -        }
   1.274 -        _Bool result = 0;
   1.275 -        uint8_t kingfile = 0, kingrow = 0;
   1.276 -        for (uint8_t row = 0 ; row < 8 ; row++) {
   1.277 -            for (uint8_t file = 0 ; file < 8 ; file++) {
   1.278 -                if ((gamestate->board[row][file] & COLOR_MASK) == color) {
   1.279 -                    kingfile = file;
   1.280 -                    kingrow = row;
   1.281 -                }
   1.282 -            }
   1.283 -        }
   1.284 -        
   1.285 -        for (uint8_t i = 0 ; i < candidatecount ; i++) {
   1.286 -            GameState simulation;
   1.287 -            memcpy(&simulation, gamestate, sizeof(GameState));
   1.288 -            apply_move(&simulation, &(candidates[i]));
   1.289 -            if (!is_covered(&simulation, kingrow, kingfile,
   1.290 -                    opponent_color(color))) {
   1.291 -                result = 1;
   1.292 -                if (threats && threatcount) {
   1.293 -                    threats[(*threatcount)++] = candidates[i];
   1.294 -                }
   1.295 -            }
   1.296 -        }
   1.297 -        
   1.298 -        return result;
   1.299 -    } else {
   1.300 -        return 0;
   1.301 -    }
   1.302 -}
   1.303 -
   1.304  _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file,
   1.305          uint8_t color) {
   1.306      

mercurial