--- 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; }