src/chess/rules.c

changeset 28
0c1371488d87
parent 27
efeb98bc69c9
child 29
c6a1ad6cf749
--- a/src/chess/rules.c	Thu Apr 03 16:07:04 2014 +0200
+++ b/src/chess/rules.c	Fri Apr 04 17:36:42 2014 +0200
@@ -90,12 +90,14 @@
     }
 }
 
-_Bool is_covered(GameState *gamestate,uint8_t row,uint8_t file,uint8_t color) {
+_Bool get_any_threat_for(GameState *gamestate, uint8_t row, uint8_t file,
+        uint8_t color, Move *threat) {
     Move threats[16];
     int threatcount = 0;
     for (uint8_t r = 0 ; r < 8 ; r++) {
         for (uint8_t f = 0 ; f < 8 ; f++) {
             if ((gamestate->board[r][f] & COLOR_MASK) == color) {
+                memset(&(threats[threatcount]), 0, sizeof(Move));
                 threats[threatcount].piece = gamestate->board[r][f];
                 threats[threatcount].fromrow = r;
                 threats[threatcount].fromfile = f;
@@ -108,6 +110,9 @@
     
     for (int i = 0 ; i < threatcount ; i++) {
         if (validate_move(gamestate, &(threats[i]))) {
+            if (threat) {
+                *threat = threats[i];
+            }
             return 1;
         }
     }
@@ -158,7 +163,7 @@
             gamestate->board[move->torow][fileidx('d')] = color|ROOK;
         }
     }
-    
+
     addmove(gamestate, move);
 }
 
@@ -179,8 +184,8 @@
     result = msrc(gamestate->board, move) == move->piece;
     
     /* can't capture own pieces */
-    if ((mdst(gamestate->board, move) & COLOR_MASK)
-        == (move->piece & COLOR_MASK)) {
+    uint8_t piececolor = (move->piece & COLOR_MASK);
+    if ((mdst(gamestate->board, move) & COLOR_MASK) == piececolor) {
         return 0;
     }
     
@@ -219,13 +224,70 @@
         return 0;
     }
     
-    /* is piece pinned */
-    // TODO: make it so
+    /* find kings for check validation */
+    uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0;
+    for (uint8_t row = 0 ; row < 8 ; row++) {
+        for (uint8_t file = 0 ; file < 8 ; file++) {
+            if (gamestate->board[row][file] ==
+                    (piececolor == WHITE?WKING:BKING)) {
+                mykingfile = file;
+                mykingrow = row;
+            } else if (gamestate->board[row][file] ==
+                    (piececolor == WHITE?BKING:WKING)) {
+                opkingfile = file;
+                opkingrow = row;
+            }
+        }
+    }
+    
+    /* simulation move for check validation */
+    GameState simulation;
+    memcpy(&simulation, gamestate, sizeof(GameState));
+    apply_move(&simulation, move);
+    
+    /* don't move into or stay in check position */
+    if (is_covered(&simulation, mykingrow, mykingfile,
+        opponent_color(piececolor))) {
+        return 0;
+    }
     
     /* correct check and checkmate flags (move is still valid) */
-    // TODO: make it so
+    Move threat;
+    move->check = get_any_threat_for(&simulation, opkingrow, opkingfile,
+        piececolor, &threat);
     
-    return result;
+    if (move->check) {
+        /* determine possible escape fields */
+        _Bool canescape = 0;
+        for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
+            for (int df = -1 ; df <= 1 && !canescape ; df++) {
+                if (!(dr == 0 && df == 0)  &&
+                        isidx(opkingrow + dr) && isidx(opkingfile + df)) {
+                    
+                    /* escape field neither blocked nor covered */
+                    if ((simulation.board[opkingrow + dr][opkingfile + df]
+                            & COLOR_MASK) != opponent_color(piececolor)) {
+                        canescape |= !is_covered(&simulation,
+                            opkingrow + dr, opkingfile + df, piececolor);
+                    }
+                }
+            }
+        }
+        /* can't escape, can we capture? */
+        if (!canescape) {
+            canescape = is_covered(&simulation, threat.fromrow,
+                threat.fromfile, opponent_color(piececolor));
+
+            /* can't capture, can we block? */
+            // TODO: make it so
+            
+            if (!canescape) {
+                gamestate->checkmate = 1;
+            }
+        }
+    }
+    
+    return 1;
 }
 
 int eval_move(GameState *gamestate, char *mstr, Move *move) {

mercurial