Wed, 11 Jun 2014 16:54:20 +0200
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 |
1.1 --- a/src/chess/rules.c Wed Jun 11 15:38:01 2014 +0200 1.2 +++ b/src/chess/rules.c Wed Jun 11 16:54:20 2014 +0200 1.3 @@ -54,6 +54,81 @@ 1.4 }; 1.5 } 1.6 1.7 +/* MUST be called IMMEDIATLY after applying a move to work correctly */ 1.8 +static void format_move(GameState *gamestate, Move *move) { 1.9 + char *string = move->string; 1.10 + 1.11 + /* at least 8 characters should be available, wipe them out */ 1.12 + memset(string, 0, 8); 1.13 + 1.14 + /* special formats for castling */ 1.15 + if ((move->piece&PIECE_MASK) == KING && 1.16 + abs(move->tofile-move->fromfile) == 2) { 1.17 + if (move->tofile==fileidx('c')) { 1.18 + memcpy(string, "O-O-O", 5); 1.19 + } else { 1.20 + memcpy(string, "O-O", 3); 1.21 + } 1.22 + } 1.23 + 1.24 + /* start by notating the piece character */ 1.25 + string[0] = getpiecechr(move->piece); 1.26 + int idx = string[0] ? 1 : 0; 1.27 + 1.28 + /* find out how many source information we do need */ 1.29 + uint8_t piece = move->piece & PIECE_MASK; 1.30 + if (piece == PAWN) { 1.31 + if (move->capture) { 1.32 + string[idx++] = filechr(move->fromfile); 1.33 + } 1.34 + } else if (piece != KING) { 1.35 + Move threats[16]; 1.36 + uint8_t threatcount; 1.37 + get_real_threats(gamestate, move->torow, move->tofile, 1.38 + move->piece&COLOR_MASK, threats, &threatcount); 1.39 + if (threatcount > 1) { 1.40 + int ambrows = 0, ambfiles = 0; 1.41 + for (uint8_t i = 0 ; i < threatcount ; i++) { 1.42 + if (threats[i].fromrow == move->fromrow) { 1.43 + ambrows++; 1.44 + } 1.45 + if (threats[i].fromfile == move->fromfile) { 1.46 + ambfiles++; 1.47 + } 1.48 + } 1.49 + /* ambiguous row, name file */ 1.50 + if (ambrows > 1) { 1.51 + string[idx++] = filechr(move->fromfile); 1.52 + } 1.53 + /* ambiguous file, name row */ 1.54 + if (ambfiles > 1) { 1.55 + string[idx++] = filechr(move->fromrow); 1.56 + } 1.57 + } 1.58 + } 1.59 + 1.60 + /* capturing? */ 1.61 + if (move->capture) { 1.62 + string[idx++] = 'x'; 1.63 + } 1.64 + 1.65 + /* destination */ 1.66 + string[idx++] = filechr(move->tofile); 1.67 + string[idx++] = rowchr(move->torow); 1.68 + 1.69 + /* promotion? */ 1.70 + if (move->promotion) { 1.71 + string[idx++] = '='; 1.72 + string[idx++] = getpiecechr(move->promotion); 1.73 + } 1.74 + 1.75 + /* check? */ 1.76 + if (move->check) { 1.77 + /* works only, if this function is called when applying the move */ 1.78 + string[idx++] = gamestate->checkmate?'#':'+'; 1.79 + } 1.80 +} 1.81 + 1.82 static void addmove(GameState* gamestate, Move *move) { 1.83 MoveList *elem = malloc(sizeof(MoveList)); 1.84 elem->next = NULL; 1.85 @@ -109,7 +184,7 @@ 1.86 } 1.87 } 1.88 1.89 -void apply_move(GameState *gamestate, Move *move) { 1.90 +static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) { 1.91 uint8_t piece = move->piece & PIECE_MASK; 1.92 uint8_t color = move->piece & COLOR_MASK; 1.93 1.94 @@ -141,8 +216,7 @@ 1.95 } 1.96 1.97 /* castling */ 1.98 - if (piece == KING && 1.99 - move->fromfile == fileidx('e')) { 1.100 + if (piece == KING && move->fromfile == fileidx('e')) { 1.101 1.102 if (move->tofile == fileidx('g')) { 1.103 gamestate->board[move->torow][fileidx('h')] = 0; 1.104 @@ -153,9 +227,19 @@ 1.105 } 1.106 } 1.107 1.108 + if (!simulate) { 1.109 + if (!move->string[0]) { 1.110 + format_move(gamestate, move); 1.111 + } 1.112 + } 1.113 + /* add move, even in simulation (checkmate test needs it) */ 1.114 addmove(gamestate, move); 1.115 } 1.116 1.117 +void apply_move(GameState *gamestate, Move *move) { 1.118 + apply_move_impl(gamestate, move, 0); 1.119 +} 1.120 + 1.121 static int validate_move_rules(GameState *gamestate, Move *move) { 1.122 /* validate indices (don't trust opponent) */ 1.123 if (!chkidx(move)) { 1.124 @@ -248,7 +332,7 @@ 1.125 /* simulate move for check validation */ 1.126 GameState simulation = gamestate_copy_sim(gamestate); 1.127 Move simmove = *move; 1.128 - apply_move(&simulation, &simmove); 1.129 + apply_move_impl(&simulation, &simmove, 1); 1.130 1.131 /* don't move into or stay in check position */ 1.132 if (is_covered(&simulation, mykingrow, mykingfile, 1.133 @@ -448,7 +532,6 @@ 1.134 threats[(*threatcount)++] = candidates[i]; 1.135 } 1.136 } 1.137 - gamestate_cleanup(&simulation); 1.138 } 1.139 1.140 return result; 1.141 @@ -468,6 +551,8 @@ 1.142 if (get_threats(gamestate, move->torow, move->tofile, color, 1.143 threats, &threatcount)) { 1.144 1.145 + int reason = INVALID_POSITION; 1.146 + 1.147 // find threats for the specified position 1.148 for (uint8_t i = 0 ; i < threatcount ; i++) { 1.149 if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) 1.150 @@ -480,23 +565,23 @@ 1.151 if (threat) { 1.152 return AMBIGUOUS_MOVE; 1.153 } else { 1.154 - threat = &(threats[i]); 1.155 + // found threat is no real threat 1.156 + if (is_pinned(gamestate, &(threats[i]))) { 1.157 + reason = incheck?KING_IN_CHECK:PIECE_PINNED; 1.158 + } else { 1.159 + threat = &(threats[i]); 1.160 + } 1.161 } 1.162 } 1.163 } 1.164 1.165 // can't threaten specified position 1.166 if (!threat) { 1.167 - return INVALID_POSITION; 1.168 + return reason; 1.169 } 1.170 1.171 - // found threat is no real threat 1.172 - if (is_pinned(gamestate, threat)) { 1.173 - return incheck?KING_IN_CHECK:PIECE_PINNED; 1.174 - } else { 1.175 - memcpy(move, threat, sizeof(Move)); 1.176 - return VALID_MOVE_SYNTAX; 1.177 - } 1.178 + memcpy(move, threat, sizeof(Move)); 1.179 + return VALID_MOVE_SYNTAX; 1.180 } else { 1.181 return INVALID_POSITION; 1.182 }
2.1 --- a/src/chess/rules.h Wed Jun 11 15:38:01 2014 +0200 2.2 +++ b/src/chess/rules.h Wed Jun 11 16:54:20 2014 +0200 2.3 @@ -90,6 +90,7 @@ 2.4 uint8_t capture; 2.5 struct movetimeval timestamp; 2.6 struct movetimeval movetime; 2.7 + char string[8]; 2.8 } Move; 2.9 2.10 typedef struct MoveList MoveList; 2.11 @@ -140,6 +141,10 @@ 2.12 #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED) 2.13 #define rowidx_s(c) (isrow(c)?rowidx(c):POS_UNSPECIFIED) 2.14 2.15 +/** 2.16 + * Cleans up a game state and frees the memory for the movement list. 2.17 + * @param gamestate the game state to clean up 2.18 + */ 2.19 void gamestate_cleanup(GameState *gamestate); 2.20 2.21 /**
3.1 --- a/src/game.c Wed Jun 11 15:38:01 2014 +0200 3.2 +++ b/src/game.c Wed Jun 11 16:54:20 2014 +0200 3.3 @@ -123,29 +123,9 @@ 3.4 } 3.5 3.6 if (logelem) { 3.7 - Move move = logelem->move; 3.8 - if ((move.piece&PIECE_MASK) == KING && 3.9 - abs(move.tofile-move.fromfile) == 2) { 3.10 - addstr(move.tofile==fileidx('c')?"O-O-O":"O-O"); 3.11 - } else { 3.12 - char logstr[] = { 3.13 - getpiecechr(move.piece), 3.14 - filechr(move.fromfile), rowchr(move.fromrow), 3.15 - move.capture ? 'x':'\0', 3.16 - filechr(move.tofile), rowchr(move.torow), 3.17 - move.check ? '+' : (move.promotion ? '=' : '\0'), 3.18 - move.promotion ? getpiecechr(move.promotion) : '\0' 3.19 - }; 3.20 - for (int stri = 0 ; stri < sizeof(logstr) ; stri++) { 3.21 - if (logstr[stri]) { 3.22 - addch(logstr[stri]); 3.23 - } 3.24 - } 3.25 - } 3.26 + addstr(logelem->move.string); 3.27 if (!logelem->next) { 3.28 - if (gamestate->checkmate) { 3.29 - addstr("\b#"); 3.30 - } else if (gamestate->stalemate) { 3.31 + if (gamestate->stalemate) { 3.32 addstr(" stalemate"); 3.33 } 3.34 } 3.35 @@ -311,7 +291,8 @@ 3.36 int eval_result = eval_move(gamestate, movestr, &move); 3.37 switch (eval_result) { 3.38 case VALID_MOVE_SYNTAX: 3.39 - net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move)); 3.40 + net_send_data(opponent, NETCODE_MOVE, &move, 3.41 + sizeof(Move)-8); 3.42 code = net_recieve_code(opponent); 3.43 move.check = code == NETCODE_CHECK || 3.44 code == NETCODE_CHECKMATE; 3.45 @@ -407,7 +388,7 @@ 3.46 } 3.47 break; 3.48 case NETCODE_MOVE: 3.49 - net_recieve_data(opponent, &move, sizeof(Move)); 3.50 + net_recieve_data(opponent, &move, sizeof(Move)-8); 3.51 code = validate_move(gamestate, &move); 3.52 if (code == VALID_MOVE_SEMANTICS) { 3.53 apply_move(gamestate, &move);
4.1 --- a/src/network.h Wed Jun 11 15:38:01 2014 +0200 4.2 +++ b/src/network.h Wed Jun 11 16:54:20 2014 +0200 4.3 @@ -49,7 +49,7 @@ 4.4 #define NETCODE_TIMEOVER 0x44 4.5 #define NETCODE_CONNLOST 0x80 4.6 4.7 -#define NETCODE_VERSION 14 4.8 +#define NETCODE_VERSION 15 4.9 4.10 typedef struct { 4.11 int fd; /* -1, if we are the client */