src/chess/rules.c

changeset 48
0cedda2544da
parent 47
d726e4b46c33
child 49
02c509a44e98
     1.1 --- a/src/chess/rules.c	Wed May 28 15:47:57 2014 +0200
     1.2 +++ b/src/chess/rules.c	Wed Jun 11 15:38:01 2014 +0200
     1.3 @@ -33,6 +33,17 @@
     1.4  #include <stdlib.h>
     1.5  #include <sys/time.h>
     1.6  
     1.7 +static GameState gamestate_copy_sim(GameState *gamestate) {
     1.8 +    GameState simulation = *gamestate;
     1.9 +    if (simulation.lastmove) {
    1.10 +        MoveList *lastmovecopy = malloc(sizeof(MoveList));
    1.11 +        *lastmovecopy = *(simulation.lastmove);
    1.12 +        simulation.movelist = simulation.lastmove = lastmovecopy;
    1.13 +    }
    1.14 +        
    1.15 +    return simulation;
    1.16 +}
    1.17 +
    1.18  void gamestate_cleanup(GameState *gamestate) {
    1.19      MoveList *elem;
    1.20      elem = gamestate->movelist;
    1.21 @@ -145,67 +156,75 @@
    1.22      addmove(gamestate, move);
    1.23  }
    1.24  
    1.25 -static _Bool validate_move_rules(GameState *gamestate, Move *move) {
    1.26 +static int validate_move_rules(GameState *gamestate, Move *move) {
    1.27      /* validate indices (don't trust opponent) */
    1.28      if (!chkidx(move)) {
    1.29 -        return 0;
    1.30 +        return INVALID_POSITION;
    1.31      }
    1.32      
    1.33      /* must move */
    1.34      if (move->fromfile == move->tofile && move->fromrow == move->torow) {
    1.35 -        return 0;
    1.36 +        return INVALID_MOVE_SYNTAX;
    1.37      }
    1.38      
    1.39      /* does piece exist */
    1.40      if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK))
    1.41             != (move->piece&(PIECE_MASK|COLOR_MASK))) {
    1.42 -        return 0;
    1.43 +        return INVALID_POSITION;
    1.44      }
    1.45      
    1.46      /* can't capture own pieces */
    1.47      if ((mdst(gamestate->board, move) & COLOR_MASK)
    1.48              == (move->piece & COLOR_MASK)) {
    1.49 -        return 0;
    1.50 +        return RULES_VIOLATED;
    1.51      }
    1.52      
    1.53      /* must capture, if and only if destination is occupied */
    1.54      if ((mdst(gamestate->board, move) == 0 && move->capture) ||
    1.55              (mdst(gamestate->board, move) != 0 && !move->capture)) {
    1.56 -        return 0;
    1.57 +        return INVALID_MOVE_SYNTAX;
    1.58      }
    1.59      
    1.60      /* validate individual rules */
    1.61 +    _Bool chkrules;
    1.62      switch (move->piece & PIECE_MASK) {
    1.63      case PAWN:
    1.64 -        return pawn_chkrules(gamestate, move) &&
    1.65 +        chkrules = pawn_chkrules(gamestate, move) &&
    1.66              !pawn_isblocked(gamestate, move);
    1.67 +        break;
    1.68      case ROOK:
    1.69 -        return rook_chkrules(move) &&
    1.70 +        chkrules = rook_chkrules(move) &&
    1.71              !rook_isblocked(gamestate, move);
    1.72 +        break;
    1.73      case KNIGHT:
    1.74 -        return knight_chkrules(move); /* knight is never blocked */
    1.75 +        chkrules = knight_chkrules(move); /* knight is never blocked */
    1.76 +        break;
    1.77      case BISHOP:
    1.78 -        return bishop_chkrules(move) &&
    1.79 +        chkrules = bishop_chkrules(move) &&
    1.80              !bishop_isblocked(gamestate, move);
    1.81 +        break;
    1.82      case QUEEN:
    1.83 -        return queen_chkrules(move) &&
    1.84 +        chkrules = queen_chkrules(move) &&
    1.85              !queen_isblocked(gamestate, move);
    1.86 +        break;
    1.87      case KING:
    1.88 -        return king_chkrules(gamestate, move) &&
    1.89 +        chkrules = king_chkrules(gamestate, move) &&
    1.90              !king_isblocked(gamestate, move);
    1.91 +        break;
    1.92      default:
    1.93 -        return 0;
    1.94 +        return INVALID_MOVE_SYNTAX;
    1.95      }
    1.96 +    
    1.97 +    return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED;
    1.98  }
    1.99  
   1.100 -_Bool validate_move(GameState *gamestate, Move *move) {
   1.101 -    // TODO: provide more details via a return code
   1.102 +int validate_move(GameState *gamestate, Move *move) {
   1.103      
   1.104 -    _Bool result = validate_move_rules(gamestate, move);
   1.105 +    int result = validate_move_rules(gamestate, move);
   1.106      
   1.107      /* cancel processing to save resources */
   1.108 -    if (!result) {
   1.109 -        return 0;
   1.110 +    if (result != VALID_MOVE_SEMANTICS) {
   1.111 +        return result;
   1.112      }
   1.113      
   1.114      /* find kings for check validation */
   1.115 @@ -226,15 +245,23 @@
   1.116          }
   1.117      }
   1.118      
   1.119 -    /* simulation move for check validation */
   1.120 -    GameState simulation = *gamestate;
   1.121 +    /* simulate move for check validation */
   1.122 +    GameState simulation = gamestate_copy_sim(gamestate);
   1.123      Move simmove = *move;
   1.124      apply_move(&simulation, &simmove);
   1.125      
   1.126      /* don't move into or stay in check position */
   1.127      if (is_covered(&simulation, mykingrow, mykingfile,
   1.128          opponent_color(piececolor))) {
   1.129 -        return 0;
   1.130 +        
   1.131 +        gamestate_cleanup(&simulation);
   1.132 +        if ((move->piece & PIECE_MASK) == KING) {
   1.133 +            return KING_MOVES_INTO_CHECK;
   1.134 +        } else {
   1.135 +            /* last move is always not null in this case */
   1.136 +            return gamestate->lastmove->move.check ?
   1.137 +                KING_IN_CHECK : PIECE_PINNED;
   1.138 +        }
   1.139      }
   1.140      
   1.141      /* correct check and checkmate flags (move is still valid) */
   1.142 @@ -315,7 +342,9 @@
   1.143          }
   1.144      }
   1.145      
   1.146 -    return 1;
   1.147 +    gamestate_cleanup(&simulation);
   1.148 +    
   1.149 +    return VALID_MOVE_SEMANTICS;
   1.150  }
   1.151  
   1.152  _Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file,
   1.153 @@ -351,7 +380,8 @@
   1.154      _Bool result = 0;
   1.155      
   1.156      for (int i = 0 ; i < candidatecount ; i++) {
   1.157 -        if (validate_move_rules(gamestate, &(candidates[i]))) {
   1.158 +        if (validate_move_rules(gamestate, &(candidates[i]))
   1.159 +                == VALID_MOVE_SEMANTICS) {
   1.160              result = 1;
   1.161              if (threats && threatcount) {
   1.162                  threats[(*threatcount)++] = candidates[i];
   1.163 @@ -375,10 +405,14 @@
   1.164          }
   1.165      }
   1.166  
   1.167 -    GameState simulation = *gamestate;
   1.168 +    GameState simulation = gamestate_copy_sim(gamestate);
   1.169      Move simmove = *move;
   1.170      apply_move(&simulation, &simmove);
   1.171 -    return is_covered(&simulation, kingrow, kingfile, opponent_color(color));
   1.172 +    _Bool covered = is_covered(&simulation,
   1.173 +        kingrow, kingfile, opponent_color(color));
   1.174 +    gamestate_cleanup(&simulation);
   1.175 +    
   1.176 +    return covered;
   1.177  }
   1.178  
   1.179  _Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file,
   1.180 @@ -404,7 +438,7 @@
   1.181          }
   1.182  
   1.183          for (uint8_t i = 0 ; i < candidatecount ; i++) {
   1.184 -            GameState simulation = *gamestate;
   1.185 +            GameState simulation = gamestate_copy_sim(gamestate);
   1.186              Move simmove = candidates[i];
   1.187              apply_move(&simulation, &simmove);
   1.188              if (!is_covered(&simulation, kingrow, kingfile,
   1.189 @@ -414,6 +448,7 @@
   1.190                      threats[(*threatcount)++] = candidates[i];
   1.191                  }
   1.192              }
   1.193 +            gamestate_cleanup(&simulation);
   1.194          }
   1.195          
   1.196          return result;
   1.197 @@ -421,7 +456,7 @@
   1.198          return 0;
   1.199      }
   1.200  }
   1.201 -#include <ncurses.h>
   1.202 +
   1.203  static int getlocation(GameState *gamestate, Move *move) {   
   1.204  
   1.205      uint8_t color = move->piece & COLOR_MASK;
   1.206 @@ -473,6 +508,9 @@
   1.207      move->fromrow = POS_UNSPECIFIED;
   1.208  
   1.209      size_t len = strlen(mstr);
   1.210 +    if (len < 1 || len > 6) {
   1.211 +        return INVALID_MOVE_SYNTAX;
   1.212 +    }
   1.213      
   1.214      /* evaluate check/checkmate flags */
   1.215      if (mstr[len-1] == '+') {
   1.216 @@ -513,7 +551,6 @@
   1.217              move->tofile = fileidx(mstr[1]);
   1.218              move->torow = rowidx(mstr[2]);
   1.219          }
   1.220 -        
   1.221      } else if (len == 4) {
   1.222          move->piece = getpiece(mstr[0]);
   1.223          if (!move->piece) {

mercurial