logging string representation of moves in short algebraic notation

Wed, 11 Jun 2014 16:54:20 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 11 Jun 2014 16:54:20 +0200
changeset 49
02c509a44e98
parent 48
0cedda2544da
child 50
41017d0a72c5

logging string representation of moves in short algebraic notation

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
src/network.h file | annotate | diff | comparison | revisions
--- a/src/chess/rules.c	Wed Jun 11 15:38:01 2014 +0200
+++ b/src/chess/rules.c	Wed Jun 11 16:54:20 2014 +0200
@@ -54,6 +54,81 @@
     };
 }
 
+/* MUST be called IMMEDIATLY after applying a move to work correctly */
+static void format_move(GameState *gamestate, Move *move) {
+    char *string = move->string;
+    
+    /* at least 8 characters should be available, wipe them out */
+    memset(string, 0, 8);
+    
+    /* special formats for castling */
+    if ((move->piece&PIECE_MASK) == KING &&
+            abs(move->tofile-move->fromfile) == 2) {
+        if (move->tofile==fileidx('c')) {
+            memcpy(string, "O-O-O", 5);
+        } else {
+            memcpy(string, "O-O", 3);
+        }
+    }
+
+    /* start by notating the piece character */
+    string[0] = getpiecechr(move->piece);
+    int idx = string[0] ? 1 : 0;
+    
+    /* find out how many source information we do need */
+    uint8_t piece = move->piece & PIECE_MASK;
+    if (piece == PAWN) {
+        if (move->capture) {
+            string[idx++] = filechr(move->fromfile);
+        }
+    } else if (piece != KING) {
+        Move threats[16];
+        uint8_t threatcount;
+        get_real_threats(gamestate, move->torow, move->tofile,
+            move->piece&COLOR_MASK, threats, &threatcount);
+        if (threatcount > 1) {
+            int ambrows = 0, ambfiles = 0;
+            for (uint8_t i = 0 ; i < threatcount ; i++) {
+                if (threats[i].fromrow == move->fromrow) {
+                    ambrows++;
+                }
+                if (threats[i].fromfile == move->fromfile) {
+                    ambfiles++;
+                }
+            }
+            /* ambiguous row, name file */
+            if (ambrows > 1) {
+                string[idx++] = filechr(move->fromfile);
+            }
+            /* ambiguous file, name row */
+            if (ambfiles > 1) {
+                string[idx++] = filechr(move->fromrow);
+            }
+        }
+    }
+    
+    /* capturing? */
+    if (move->capture) {
+        string[idx++] = 'x';
+    }
+    
+    /* destination */
+    string[idx++] = filechr(move->tofile);
+    string[idx++] = rowchr(move->torow);
+    
+    /* promotion? */
+    if (move->promotion) {
+        string[idx++] = '=';
+        string[idx++] = getpiecechr(move->promotion);
+    }
+    
+    /* check? */
+    if (move->check) {
+        /* works only, if this function is called when applying the move */
+        string[idx++] = gamestate->checkmate?'#':'+';
+    }
+}
+
 static void addmove(GameState* gamestate, Move *move) {
     MoveList *elem = malloc(sizeof(MoveList));
     elem->next = NULL;
@@ -109,7 +184,7 @@
     }
 }
 
-void apply_move(GameState *gamestate, Move *move) {
+static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) {
     uint8_t piece = move->piece & PIECE_MASK;
     uint8_t color = move->piece & COLOR_MASK;
     
@@ -141,8 +216,7 @@
     }
     
     /* castling */
-    if (piece == KING &&
-        move->fromfile == fileidx('e')) {
+    if (piece == KING && move->fromfile == fileidx('e')) {
         
         if (move->tofile == fileidx('g')) {
             gamestate->board[move->torow][fileidx('h')] = 0;
@@ -153,9 +227,19 @@
         }
     }
 
+    if (!simulate) {
+        if (!move->string[0]) {
+            format_move(gamestate, move);
+        }
+    }
+    /* add move, even in simulation (checkmate test needs it) */
     addmove(gamestate, move);
 }
 
+void apply_move(GameState *gamestate, Move *move) {
+    apply_move_impl(gamestate, move, 0);
+}
+
 static int validate_move_rules(GameState *gamestate, Move *move) {
     /* validate indices (don't trust opponent) */
     if (!chkidx(move)) {
@@ -248,7 +332,7 @@
     /* simulate move for check validation */
     GameState simulation = gamestate_copy_sim(gamestate);
     Move simmove = *move;
-    apply_move(&simulation, &simmove);
+    apply_move_impl(&simulation, &simmove, 1);
     
     /* don't move into or stay in check position */
     if (is_covered(&simulation, mykingrow, mykingfile,
@@ -448,7 +532,6 @@
                     threats[(*threatcount)++] = candidates[i];
                 }
             }
-            gamestate_cleanup(&simulation);
         }
         
         return result;
@@ -468,6 +551,8 @@
     if (get_threats(gamestate, move->torow, move->tofile, color,
             threats, &threatcount)) {
         
+        int reason = INVALID_POSITION;
+        
         // find threats for the specified position
         for (uint8_t i = 0 ; i < threatcount ; i++) {
             if ((threats[i].piece & (PIECE_MASK | COLOR_MASK))
@@ -480,23 +565,23 @@
                 if (threat) {
                     return AMBIGUOUS_MOVE;
                 } else {
-                    threat = &(threats[i]);
+                    // found threat is no real threat
+                    if (is_pinned(gamestate, &(threats[i]))) {
+                        reason = incheck?KING_IN_CHECK:PIECE_PINNED;
+                    } else {
+                        threat = &(threats[i]);
+                    }
                 }
             }
         }
         
         // can't threaten specified position
         if (!threat) {
-            return INVALID_POSITION;
+            return reason;
         }
 
-        // found threat is no real threat
-        if (is_pinned(gamestate, threat)) {
-            return incheck?KING_IN_CHECK:PIECE_PINNED;
-        } else {
-            memcpy(move, threat, sizeof(Move));
-            return VALID_MOVE_SYNTAX;
-        }
+        memcpy(move, threat, sizeof(Move));
+        return VALID_MOVE_SYNTAX;
     } else {
         return INVALID_POSITION;
     }
--- a/src/chess/rules.h	Wed Jun 11 15:38:01 2014 +0200
+++ b/src/chess/rules.h	Wed Jun 11 16:54:20 2014 +0200
@@ -90,6 +90,7 @@
     uint8_t capture;
     struct movetimeval timestamp;
     struct movetimeval movetime;
+    char string[8];
 } Move;
 
 typedef struct MoveList MoveList;
@@ -140,6 +141,10 @@
 #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED)
 #define rowidx_s(c) (isrow(c)?rowidx(c):POS_UNSPECIFIED)
 
+/**
+ * Cleans up a game state and frees the memory for the movement list.
+ * @param gamestate the game state to clean up
+ */
 void gamestate_cleanup(GameState *gamestate);
 
 /**
--- a/src/game.c	Wed Jun 11 15:38:01 2014 +0200
+++ b/src/game.c	Wed Jun 11 16:54:20 2014 +0200
@@ -123,29 +123,9 @@
         }
 
         if (logelem) {
-            Move move = logelem->move;
-            if ((move.piece&PIECE_MASK) == KING &&
-                abs(move.tofile-move.fromfile) == 2) {
-                addstr(move.tofile==fileidx('c')?"O-O-O":"O-O");
-            } else {
-                char logstr[] = {
-                    getpiecechr(move.piece),
-                    filechr(move.fromfile), rowchr(move.fromrow),
-                    move.capture ? 'x':'\0',
-                    filechr(move.tofile), rowchr(move.torow),
-                    move.check ? '+' : (move.promotion ? '=' : '\0'),
-                    move.promotion ? getpiecechr(move.promotion) : '\0'
-                };
-                for (int stri = 0 ; stri < sizeof(logstr) ; stri++) {
-                    if (logstr[stri]) {
-                        addch(logstr[stri]);
-                    }
-                }
-            }
+            addstr(logelem->move.string);
             if (!logelem->next) {
-                if (gamestate->checkmate) {
-                    addstr("\b#");
-                } else if (gamestate->stalemate) {
+                if (gamestate->stalemate) {
                     addstr(" stalemate");
                 }
             }
@@ -311,7 +291,8 @@
                 int eval_result = eval_move(gamestate, movestr, &move);
                 switch (eval_result) {
                 case VALID_MOVE_SYNTAX:
-                    net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move));
+                    net_send_data(opponent, NETCODE_MOVE, &move,
+                        sizeof(Move)-8);
                     code = net_recieve_code(opponent);
                     move.check = code == NETCODE_CHECK ||
                         code == NETCODE_CHECKMATE;
@@ -407,7 +388,7 @@
                 }
                 break;
             case NETCODE_MOVE:
-                net_recieve_data(opponent, &move, sizeof(Move));
+                net_recieve_data(opponent, &move, sizeof(Move)-8);
                 code = validate_move(gamestate, &move);
                 if (code == VALID_MOVE_SEMANTICS) {
                     apply_move(gamestate, &move);
--- a/src/network.h	Wed Jun 11 15:38:01 2014 +0200
+++ b/src/network.h	Wed Jun 11 16:54:20 2014 +0200
@@ -49,7 +49,7 @@
 #define NETCODE_TIMEOVER 0x44
 #define NETCODE_CONNLOST 0x80
 
-#define NETCODE_VERSION 14
+#define NETCODE_VERSION 15
 
 typedef struct {
     int fd; /* -1, if we are the client */

mercurial