src/chess/rules.c

changeset 179
5ef724e21702
parent 177
18dbb0dc9cd6
--- a/src/chess/rules.c	Fri Aug 21 16:08:50 2026 +0200
+++ b/src/chess/rules.c	Fri Aug 21 17:04:43 2026 +0200
@@ -297,6 +297,79 @@
     return false;
 }
 
+static bool check_no_material_color(Color color, const GameState *gamestate) {
+    /* count the available pieces */
+    unsigned piece_count[7] = {0};
+    unsigned op_piece_count[7] = {0};
+    bool has_bbishop = false, has_wbishop = false;
+    bool op_has_bbishop = false, op_has_wbishop = false;
+    for (Row r = 0 ; r < 8 ; r++) {
+        for (File f = 0 ; f < 8 ; f++) {
+            Piece p = piece_at(gamestate, r, f);
+            if (piece_color(p) == color) {
+                piece_count[piece_type(p)]++;
+                if (piece_type(p) == BISHOP) {
+                    if (field_color(r, f) == WHITE) {
+                        has_wbishop = true;
+                    } else {
+                        has_bbishop = true;
+                    }
+                }
+            } else {
+                op_piece_count[piece_type(p)]++;
+                if (piece_type(p) == BISHOP) {
+                    if (field_color(r, f) == WHITE) {
+                        op_has_wbishop = true;
+                    } else {
+                        op_has_bbishop = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /* rooks and queens are always enough - don't test them below */
+    if (piece_count[ROOK] > 0 || piece_count[QUEEN] > 0)
+        return false;
+
+    /* only the king left */
+    if (piece_count[PAWN] == 0 && piece_count[KNIGHT] == 0
+            && piece_count[BISHOP] == 0)
+        return true;
+
+    /* king + knight and the opponent has only king + queens */
+    if (piece_count[PAWN] == 0 && piece_count[BISHOP] == 0
+            && piece_count[KNIGHT] == 1
+            && op_piece_count[ROOK] == 0 && op_piece_count[BISHOP] == 0
+            && op_piece_count[KNIGHT] == 0 && op_piece_count[PAWN] == 0
+            && op_piece_count[QUEEN] > 0)
+        return true;
+
+    /* king + bishop and the opponent doesn't have
+     * opposite color bishops or knights or pawns */
+    if (piece_count[PAWN] == 0 && piece_count[KNIGHT] == 0
+            && piece_count[BISHOP] > 0) {
+
+        if (op_piece_count[KNIGHT] > 0 || op_piece_count[PAWN] > 0)
+            return false;
+
+        if (has_bbishop && op_has_wbishop)
+            return false;
+
+        if (has_wbishop && op_has_bbishop)
+            return false;
+
+        return true;
+    }
+
+    return false;
+}
+
+bool check_no_material(const GameState *gamestate) {
+    return check_no_material_color(WHITE, gamestate)
+        && check_no_material_color(BLACK, gamestate);
+}
+
 char getpiecechr(Piece piece) {
     switch (piece_type(piece)) {
     case ROOK: return 'R';
@@ -417,6 +490,8 @@
     /* calculate gamestate flags in order of efficiency */
     if (move->checkmate) {
         gamestate->checkmate = true;
+    } else if (check_no_material(gamestate)) {
+        gamestate->nomaterial = true;
     } else if (check_threefold_repetition(gamestate)) {
         gamestate->threefold = true;
     } else if (check_stalemate(gamestate)) {

mercurial