diff -r 6008840b859e -r 6a26114297a1 src/chess/rules.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/chess/rules.c Mon Mar 31 11:16:32 2014 +0200 @@ -0,0 +1,303 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "rules.h" +#include "chess.h" +#include + +char getpiecechr(uint8_t piece) { + switch (piece & PIECE_MASK) { + case ROOK: return 'R'; + case KNIGHT: return 'N'; + case BISHOP: return 'B'; + case QUEEN: return 'Q'; + case KING: return 'K'; + default: return '\0'; + } +} + +uint8_t getpiece(char c) { + switch (c) { + case 'R': return ROOK; + case 'N': return KNIGHT; + case 'B': return BISHOP; + case 'Q': return QUEEN; + case 'K': return KING; + default: return 0; + } +} + +/** + * Guesses the location of a piece for short algebraic notation. + * + * @param board the current state of the board + * @param move the move date to operate on + * @return status code (see rules/rules.h for the codes) + */ +static int getlocation(Board board, Move *move) { + uint8_t piece = move->piece & PIECE_MASK; + switch (piece) { + case PAWN: return pawn_getlocation(board, move); + case ROOK: return rook_getlocation(board, move); + case KNIGHT: return knight_getlocation(board, move); + case BISHOP: return bishop_getlocation(board, move); + case QUEEN: return queen_getlocation(board, move); + case KING: return king_getlocation(board, move); + default: return INVALID_MOVE_SYNTAX; + } +} + + +void apply_move(Board board, Move *move) { + uint8_t piece = move->piece & PIECE_MASK; + uint8_t color = move->piece & COLOR_MASK; + + /* en passant capture */ + if (move->capture && piece == PAWN && + mdst(board, move) == 0) { + board[move->fromrow][move->tofile] = 0; + } + + /* remove old en passant threats */ + for (uint8_t file = 0 ; file < 8 ; file++) { + board[3][file] &= ~ENPASSANT_THREAT; + board[4][file] &= ~ENPASSANT_THREAT; + } + + /* add new en passant threat */ + if (piece == PAWN && ( + (move->fromrow == 1 && move->torow == 3) || + (move->fromrow == 6 && move->torow == 4))) { + move->piece |= ENPASSANT_THREAT; + } + + /* move (and maybe capture or promote) */ + msrc(board, move) = 0; + if (move->promotion) { + mdst(board, move) = move->promotion; + } else { + mdst(board, move) = move->piece; + } + + /* castling */ + if (piece == KING && + move->fromfile == fileidx('e')) { + + if (move->tofile == fileidx('g')) { + board[move->torow][fileidx('h')] = 0; + board[move->torow][fileidx('f')] = color|ROOK; + } else if (move->tofile == fileidx('c')) { + board[move->torow][fileidx('a')] = 0; + board[move->torow][fileidx('d')] = color|ROOK; + } + } +} + +_Bool validate_move(Board board, Move *move) { + _Bool result; + + /* validate indices (don't trust opponent) */ + if (!chkidx(move)) { + return 0; + } + + /* does piece exist */ + result = msrc(board, move) == move->piece; + + /* can't capture own pieces */ + if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) { + return 0; + } + + /* validate individual rules */ + switch (move->piece & PIECE_MASK) { + case PAWN: + result = result && pawn_chkrules(board, move); + result = result && !pawn_isblocked(board, move); + break; + case ROOK: + result = result && rook_chkrules(move); + result = result && !rook_isblocked(board, move); + break; + case KNIGHT: + result = result && knight_chkrules(move); + result = result && !knight_isblocked(board, move); + break; + case BISHOP: + result = result && bishop_chkrules(move); + result = result && !bishop_isblocked(board, move); + break; + case QUEEN: + result = result && queen_chkrules(move); + result = result && !queen_isblocked(board, move); + break; + case KING: + result = result && king_chkrules(board, move); + result = result && !king_isblocked(board, move); + break; + default: + result = 0; + } + + /* is piece pinned */ + // TODO: make it so + + /* correct check and checkmate flags */ + // TODO: make it so + + return result; +} + +int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) { + memset(move, 0, sizeof(Move)); + move->fromfile = POS_UNSPECIFIED; + move->fromrow = POS_UNSPECIFIED; + + size_t len = strlen(mstr); + + /* evaluate check/checkmate flags */ + if (mstr[len-1] == '+') { + len--; mstr[len] = '\0'; + move->check = 1; + } else if (mstr[len-1] == '#') { + len--; mstr[len] = '\0'; + move->checkmate = 1; + } + + /* evaluate promotion */ + if (len > 3 && mstr[len-2] == '=') { + move->promotion = getpiece(mstr[len-1]); + if (!move->promotion) { + return INVALID_MOVE_SYNTAX; + } else { + move->promotion |= mycolor; + len -= 2; + mstr[len] = 0; + } + } + + if (len == 2) { + /* pawn move (e.g. "e4") */ + move->piece = PAWN; + move->tofile = fileidx(mstr[0]); + move->torow = rowidx(mstr[1]); + } else if (len == 3) { + if (strcmp(mstr, "O-O") == 0) { + /* king side castling */ + move->piece = KING; + move->fromfile = fileidx('e'); + move->tofile = fileidx('g'); + move->fromrow = move->torow = mycolor == WHITE ? 0 : 7; + } else { + /* move (e.g. "Nf3") */ + move->piece = getpiece(mstr[0]); + move->tofile = fileidx(mstr[1]); + move->torow = rowidx(mstr[2]); + } + + } else if (len == 4) { + move->piece = getpiece(mstr[0]); + if (!move->piece) { + move->piece = PAWN; + move->fromfile = fileidx(mstr[0]); + } + if (mstr[1] == 'x') { + /* capture (e.g. "Nxf3", "dxe5") */ + move->capture = 1; + } else { + /* move (e.g. "Ndf3", "N2c3", "e2e4") */ + if (isfile(mstr[1])) { + move->fromfile = fileidx(mstr[1]); + if (move->piece == PAWN) { + move->piece = 0; + } + } else { + move->fromrow = rowidx(mstr[1]); + } + } + move->tofile = fileidx(mstr[2]); + move->torow = rowidx(mstr[3]); + } else if (len == 5) { + if (strcmp(mstr, "O-O-O") == 0) { + /* queen side castling "O-O-O" */ + move->piece = KING; + move->fromfile = fileidx('e'); + move->tofile = fileidx('c'); + move->fromrow = move->torow = mycolor == WHITE ? 0 : 7; + } else { + move->piece = getpiece(mstr[0]); + if (mstr[2] == 'x') { + move->capture = 1; + if (move->piece) { + /* capture (e.g. "Ndxf3") */ + move->fromfile = fileidx(mstr[1]); + } else { + /* long notation capture (e.g. "e5xf6") */ + move->piece = PAWN; + move->fromfile = fileidx(mstr[0]); + move->fromrow = rowidx(mstr[1]); + } + } else { + /* long notation move (e.g. "Nc5a4") */ + move->fromfile = fileidx(mstr[1]); + move->fromrow = rowidx(mstr[2]); + } + move->tofile = fileidx(mstr[3]); + move->torow = rowidx(mstr[4]); + } + } else if (len == 6) { + /* long notation capture (e.g. "Nc5xf3") */ + if (mstr[3] == 'x') { + move->capture = 1; + move->piece = getpiece(mstr[0]); + move->fromfile = fileidx(mstr[1]); + move->fromrow = rowidx(mstr[2]); + move->tofile = fileidx(mstr[4]); + move->torow = rowidx(mstr[5]); + } + } + + + if (move->piece) { + if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0) + && !move->promotion) { + return NEED_PROMOTION; + } + + move->piece |= mycolor; + if (move->fromfile == POS_UNSPECIFIED + || move->fromrow == POS_UNSPECIFIED) { + return getlocation(board, move); + } else { + return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION; + } + } else { + return INVALID_MOVE_SYNTAX; + } +}