NEED TESTING: implemented check and checkmate - TODO: avoid checkmate by moving another piece in between

Fri, 04 Apr 2014 17:36:42 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 04 Apr 2014 17:36:42 +0200
changeset 28
0c1371488d87
parent 27
efeb98bc69c9
child 29
c6a1ad6cf749

NEED TESTING: implemented check and checkmate - TODO: avoid checkmate by moving another piece in between

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
     1.1 --- a/src/chess/rules.c	Thu Apr 03 16:07:04 2014 +0200
     1.2 +++ b/src/chess/rules.c	Fri Apr 04 17:36:42 2014 +0200
     1.3 @@ -90,12 +90,14 @@
     1.4      }
     1.5  }
     1.6  
     1.7 -_Bool is_covered(GameState *gamestate,uint8_t row,uint8_t file,uint8_t color) {
     1.8 +_Bool get_any_threat_for(GameState *gamestate, uint8_t row, uint8_t file,
     1.9 +        uint8_t color, Move *threat) {
    1.10      Move threats[16];
    1.11      int threatcount = 0;
    1.12      for (uint8_t r = 0 ; r < 8 ; r++) {
    1.13          for (uint8_t f = 0 ; f < 8 ; f++) {
    1.14              if ((gamestate->board[r][f] & COLOR_MASK) == color) {
    1.15 +                memset(&(threats[threatcount]), 0, sizeof(Move));
    1.16                  threats[threatcount].piece = gamestate->board[r][f];
    1.17                  threats[threatcount].fromrow = r;
    1.18                  threats[threatcount].fromfile = f;
    1.19 @@ -108,6 +110,9 @@
    1.20      
    1.21      for (int i = 0 ; i < threatcount ; i++) {
    1.22          if (validate_move(gamestate, &(threats[i]))) {
    1.23 +            if (threat) {
    1.24 +                *threat = threats[i];
    1.25 +            }
    1.26              return 1;
    1.27          }
    1.28      }
    1.29 @@ -158,7 +163,7 @@
    1.30              gamestate->board[move->torow][fileidx('d')] = color|ROOK;
    1.31          }
    1.32      }
    1.33 -    
    1.34 +
    1.35      addmove(gamestate, move);
    1.36  }
    1.37  
    1.38 @@ -179,8 +184,8 @@
    1.39      result = msrc(gamestate->board, move) == move->piece;
    1.40      
    1.41      /* can't capture own pieces */
    1.42 -    if ((mdst(gamestate->board, move) & COLOR_MASK)
    1.43 -        == (move->piece & COLOR_MASK)) {
    1.44 +    uint8_t piececolor = (move->piece & COLOR_MASK);
    1.45 +    if ((mdst(gamestate->board, move) & COLOR_MASK) == piececolor) {
    1.46          return 0;
    1.47      }
    1.48      
    1.49 @@ -219,13 +224,70 @@
    1.50          return 0;
    1.51      }
    1.52      
    1.53 -    /* is piece pinned */
    1.54 -    // TODO: make it so
    1.55 +    /* find kings for check validation */
    1.56 +    uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0;
    1.57 +    for (uint8_t row = 0 ; row < 8 ; row++) {
    1.58 +        for (uint8_t file = 0 ; file < 8 ; file++) {
    1.59 +            if (gamestate->board[row][file] ==
    1.60 +                    (piececolor == WHITE?WKING:BKING)) {
    1.61 +                mykingfile = file;
    1.62 +                mykingrow = row;
    1.63 +            } else if (gamestate->board[row][file] ==
    1.64 +                    (piececolor == WHITE?BKING:WKING)) {
    1.65 +                opkingfile = file;
    1.66 +                opkingrow = row;
    1.67 +            }
    1.68 +        }
    1.69 +    }
    1.70 +    
    1.71 +    /* simulation move for check validation */
    1.72 +    GameState simulation;
    1.73 +    memcpy(&simulation, gamestate, sizeof(GameState));
    1.74 +    apply_move(&simulation, move);
    1.75 +    
    1.76 +    /* don't move into or stay in check position */
    1.77 +    if (is_covered(&simulation, mykingrow, mykingfile,
    1.78 +        opponent_color(piececolor))) {
    1.79 +        return 0;
    1.80 +    }
    1.81      
    1.82      /* correct check and checkmate flags (move is still valid) */
    1.83 -    // TODO: make it so
    1.84 +    Move threat;
    1.85 +    move->check = get_any_threat_for(&simulation, opkingrow, opkingfile,
    1.86 +        piececolor, &threat);
    1.87      
    1.88 -    return result;
    1.89 +    if (move->check) {
    1.90 +        /* determine possible escape fields */
    1.91 +        _Bool canescape = 0;
    1.92 +        for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
    1.93 +            for (int df = -1 ; df <= 1 && !canescape ; df++) {
    1.94 +                if (!(dr == 0 && df == 0)  &&
    1.95 +                        isidx(opkingrow + dr) && isidx(opkingfile + df)) {
    1.96 +                    
    1.97 +                    /* escape field neither blocked nor covered */
    1.98 +                    if ((simulation.board[opkingrow + dr][opkingfile + df]
    1.99 +                            & COLOR_MASK) != opponent_color(piececolor)) {
   1.100 +                        canescape |= !is_covered(&simulation,
   1.101 +                            opkingrow + dr, opkingfile + df, piececolor);
   1.102 +                    }
   1.103 +                }
   1.104 +            }
   1.105 +        }
   1.106 +        /* can't escape, can we capture? */
   1.107 +        if (!canescape) {
   1.108 +            canescape = is_covered(&simulation, threat.fromrow,
   1.109 +                threat.fromfile, opponent_color(piececolor));
   1.110 +
   1.111 +            /* can't capture, can we block? */
   1.112 +            // TODO: make it so
   1.113 +            
   1.114 +            if (!canescape) {
   1.115 +                gamestate->checkmate = 1;
   1.116 +            }
   1.117 +        }
   1.118 +    }
   1.119 +    
   1.120 +    return 1;
   1.121  }
   1.122  
   1.123  int eval_move(GameState *gamestate, char *mstr, Move *move) {
     2.1 --- a/src/chess/rules.h	Thu Apr 03 16:07:04 2014 +0200
     2.2 +++ b/src/chess/rules.h	Fri Apr 04 17:36:42 2014 +0200
     2.3 @@ -102,7 +102,7 @@
     2.4  #define mdst(b,m) b[(m)->torow][(m)->tofile]
     2.5  #define msrc(b,m) b[(m)->fromrow][(m)->fromfile]
     2.6  
     2.7 -#define isidx(idx) ((uint8_t)idx < 8)
     2.8 +#define isidx(idx) ((uint8_t)(idx) < 8)
     2.9  
    2.10  #define isfile(file) (file >= 'a' && file <= 'h')
    2.11  #define isrow(row) (row >= '1' && row <= '8')
    2.12 @@ -145,6 +145,24 @@
    2.13  /**
    2.14   * Checks, if a specified field is covered by a piece of a certain color.
    2.15   * 
    2.16 + * Note: when the field is covered by multiple pieces, this function returns
    2.17 + * the first piece it can find.
    2.18 + * 
    2.19 + * @param gamestate the current game state
    2.20 + * @param row row of the field to check
    2.21 + * @param file file of the field to check
    2.22 + * @param color the color of the piece that should threaten the field
    2.23 + * @param threat if not NULL: a pointer to the move structure where
    2.24 + * the move that could be performed to capture the field should be stored
    2.25 + * @return TRUE, if any piece of the specified color threatens the specified
    2.26 + * field (i.e. could capture an opponent piece)
    2.27 + */
    2.28 +_Bool get_any_threat_for(GameState *gamestate, uint8_t row, uint8_t file,
    2.29 +        uint8_t color, Move *threat);
    2.30 +
    2.31 +/**
    2.32 + * Checks, if a specified field is covered by a piece of a certain color.
    2.33 + * 
    2.34   * @param gamestate the current game state
    2.35   * @param row row of the field to check
    2.36   * @param file file of the field to check
    2.37 @@ -152,7 +170,8 @@
    2.38   * @return TRUE, if any piece of the specified color threatens the specified
    2.39   * field (i.e. could capture an opponent piece)
    2.40   */
    2.41 -_Bool is_covered(GameState *gamestate,uint8_t row,uint8_t file,uint8_t color);
    2.42 +#define is_covered(gamestate, row, file, color) \
    2.43 +    get_any_threat_for(gamestate, row, file, color, NULL)
    2.44  
    2.45  /**
    2.46   * Evaluates a move syntactically and stores the move data in the specified
     3.1 --- a/src/game.c	Thu Apr 03 16:07:04 2014 +0200
     3.2 +++ b/src/game.c	Fri Apr 04 17:36:42 2014 +0200
     3.3 @@ -106,7 +106,7 @@
     3.4              }
     3.5              if (!logelem->next) {
     3.6                  if (gamestate->checkmate) {
     3.7 -                    addch('#');
     3.8 +                    addstr("\b#");
     3.9                  } else if (gamestate->stalemate) {
    3.10                      addstr(" stalemate");
    3.11                  }
    3.12 @@ -343,9 +343,9 @@
    3.13  
    3.14  void game_start_singlemachine(Settings *settings) {
    3.15      GameState gamestate;
    3.16 +    memset(&gamestate, 0, sizeof(GameState));
    3.17      init_board(&gamestate);
    3.18      gamestate.mycolor = WHITE;
    3.19 -    gamestate.movelist = gamestate.lastmove = NULL;
    3.20      // TODO: time limit
    3.21      _Bool running;
    3.22      do {
    3.23 @@ -354,6 +354,8 @@
    3.24          running = !domove_singlemachine(&gamestate);
    3.25          gamestate.mycolor = opponent_color(gamestate.mycolor);
    3.26      }  while (running);
    3.27 +    move(0,0);
    3.28 +    draw_board(&gamestate);
    3.29      
    3.30      gamestate_cleanup(&gamestate);
    3.31      
    3.32 @@ -369,9 +371,9 @@
    3.33      
    3.34      // TODO: time limit
    3.35      GameState gamestate;
    3.36 +    memset(&gamestate, 0, sizeof(GameState));
    3.37      init_board(&gamestate);
    3.38      gamestate.mycolor = myturn ? WHITE:BLACK;
    3.39 -    gamestate.movelist = gamestate.lastmove = NULL;
    3.40      
    3.41      _Bool running;
    3.42      do {
    3.43 @@ -386,6 +388,9 @@
    3.44          myturn ^= TRUE;
    3.45      }  while (running);
    3.46      
    3.47 +    move(0,0);
    3.48 +    draw_board(&gamestate);
    3.49 +    
    3.50      gamestate_cleanup(&gamestate);
    3.51      
    3.52      mvaddstr(getmaxy(stdscr)-1, 0,

mercurial