src/chess/rules.c

Mon, 31 Mar 2014 14:00:58 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 31 Mar 2014 14:00:58 +0200
changeset 21
2e5846019b4f
parent 19
6a26114297a1
child 23
824c9522ce66
permissions
-rw-r--r--

implemented rook + some fixes

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2014 Mike Becker. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  *
    28  */
    30 #include "rules.h"
    31 #include "chess.h"
    32 #include <string.h>
    34 char getpiecechr(uint8_t piece) {
    35     switch (piece & PIECE_MASK) {
    36     case ROOK: return 'R';
    37     case KNIGHT: return 'N';
    38     case BISHOP: return 'B';
    39     case QUEEN: return 'Q';
    40     case KING: return 'K';
    41     default: return '\0';
    42     }
    43 }
    45 uint8_t getpiece(char c) {
    46     switch (c) {
    47         case 'R': return ROOK;
    48         case 'N': return KNIGHT;
    49         case 'B': return BISHOP;
    50         case 'Q': return QUEEN;
    51         case 'K': return KING;
    52         default: return 0;
    53     }
    54 }
    56 /**
    57  * Guesses the location of a piece for short algebraic notation.
    58  * 
    59  * @param board the current state of the board
    60  * @param move the move date to operate on
    61  * @return status code (see rules/rules.h for the codes)
    62  */
    63 static int getlocation(Board board, Move *move) {   
    64     uint8_t piece = move->piece & PIECE_MASK;
    65     switch (piece) {
    66         case PAWN: return pawn_getlocation(board, move);
    67         case ROOK: return rook_getlocation(board, move);
    68         case KNIGHT: return knight_getlocation(board, move);
    69         case BISHOP: return bishop_getlocation(board, move);
    70         case QUEEN: return queen_getlocation(board, move);
    71         case KING: return king_getlocation(board, move);
    72         default: return INVALID_MOVE_SYNTAX;
    73     }
    74 }
    77 void apply_move(Board board, Move *move) {
    78     uint8_t piece = move->piece & PIECE_MASK;
    79     uint8_t color = move->piece & COLOR_MASK;
    81     /* en passant capture */
    82     if (move->capture && piece == PAWN &&
    83         mdst(board, move) == 0) {
    84         board[move->fromrow][move->tofile] = 0;
    85     }
    87     /* remove old en passant threats */
    88     for (uint8_t file = 0 ; file < 8 ; file++) {
    89         board[3][file] &= ~ENPASSANT_THREAT;
    90         board[4][file] &= ~ENPASSANT_THREAT;
    91     }
    93     /* add new en passant threat */
    94     if (piece == PAWN && (
    95         (move->fromrow == 1 && move->torow == 3) ||
    96         (move->fromrow == 6 && move->torow == 4))) {
    97         move->piece |= ENPASSANT_THREAT;
    98     }
   100     /* move (and maybe capture or promote) */
   101     msrc(board, move) = 0;
   102     if (move->promotion) {
   103         mdst(board, move) = move->promotion;
   104     } else {
   105         mdst(board, move) = move->piece;
   106     }
   108     /* castling */
   109     if (piece == KING &&
   110         move->fromfile == fileidx('e')) {
   112         if (move->tofile == fileidx('g')) {
   113             board[move->torow][fileidx('h')] = 0;
   114             board[move->torow][fileidx('f')] = color|ROOK;
   115         } else if (move->tofile == fileidx('c')) {
   116             board[move->torow][fileidx('a')] = 0;
   117             board[move->torow][fileidx('d')] = color|ROOK;
   118         }
   119     }
   120 }
   122 _Bool validate_move(Board board, Move *move) {
   123     _Bool result;
   125     /* validate indices (don't trust opponent) */
   126     if (!chkidx(move)) {
   127         return 0;
   128     }
   130     /* must move */
   131     if (move->fromfile == move->tofile && move->fromrow == move->torow) {
   132         return 0;
   133     }
   135     /* does piece exist */
   136     result = msrc(board, move) == move->piece;
   138     /* can't capture own pieces */
   139     if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) {
   140         return 0;
   141     }
   143     /* validate individual rules */
   144     switch (move->piece & PIECE_MASK) {
   145     case PAWN:
   146         result = result && pawn_chkrules(board, move);
   147         result = result && !pawn_isblocked(board, move);
   148         break;
   149     case ROOK:
   150         result = result && rook_chkrules(move);
   151         result = result && !rook_isblocked(board, move);
   152         break;
   153     case KNIGHT:
   154         result = result && knight_chkrules(move);
   155         result = result && !knight_isblocked(board, move);
   156         break;
   157     case BISHOP:
   158         result = result && bishop_chkrules(move);
   159         result = result && !bishop_isblocked(board, move);
   160         break;
   161     case QUEEN:
   162         result = result && queen_chkrules(move);
   163         result = result && !queen_isblocked(board, move);
   164         break;
   165     case KING:
   166         result = result && king_chkrules(board, move);
   167         result = result && !king_isblocked(board, move);
   168         break;
   169     default:
   170         result = 0;
   171     }
   173     /* is piece pinned */
   174     // TODO: make it so
   176     /* correct check and checkmate flags */
   177     // TODO: make it so
   179     return result;
   180 }
   182 int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
   183     memset(move, 0, sizeof(Move));
   184     move->fromfile = POS_UNSPECIFIED;
   185     move->fromrow = POS_UNSPECIFIED;
   187     size_t len = strlen(mstr);
   189     /* evaluate check/checkmate flags */
   190     if (mstr[len-1] == '+') {
   191         len--; mstr[len] = '\0';
   192         move->check = 1;
   193     } else if (mstr[len-1] == '#') {
   194         len--; mstr[len] = '\0';
   195         move->checkmate = 1;
   196     }
   198     /* evaluate promotion */
   199     if (len > 3 && mstr[len-2] == '=') {
   200         move->promotion = getpiece(mstr[len-1]);
   201         if (!move->promotion) {
   202             return INVALID_MOVE_SYNTAX;
   203         } else {
   204             move->promotion |= mycolor;
   205             len -= 2;
   206             mstr[len] = 0;
   207         }
   208     }
   210     if (len == 2) {
   211         /* pawn move (e.g. "e4") */
   212         move->piece = PAWN;
   213         move->tofile = fileidx(mstr[0]);
   214         move->torow = rowidx(mstr[1]);
   215     } else if (len == 3) {
   216         if (strcmp(mstr, "O-O") == 0) {
   217             /* king side castling */
   218             move->piece = KING;
   219             move->fromfile = fileidx('e');
   220             move->tofile = fileidx('g');
   221             move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
   222         } else {
   223             /* move (e.g. "Nf3") */
   224             move->piece = getpiece(mstr[0]);
   225             move->tofile = fileidx(mstr[1]);
   226             move->torow = rowidx(mstr[2]);
   227         }
   229     } else if (len == 4) {
   230         move->piece = getpiece(mstr[0]);
   231         if (!move->piece) {
   232             move->piece = PAWN;
   233             move->fromfile = fileidx(mstr[0]);
   234         }
   235         if (mstr[1] == 'x') {
   236             /* capture (e.g. "Nxf3", "dxe5") */
   237             move->capture = 1;
   238         } else {
   239             /* move (e.g. "Ndf3", "N2c3", "e2e4") */
   240             if (isfile(mstr[1])) {
   241                 move->fromfile = fileidx(mstr[1]);
   242                 if (move->piece == PAWN) {
   243                     move->piece = 0;
   244                 }
   245             } else {
   246                 move->fromrow = rowidx(mstr[1]);
   247             }
   248         }
   249         move->tofile = fileidx(mstr[2]);
   250         move->torow = rowidx(mstr[3]);
   251     } else if (len == 5) {
   252         if (strcmp(mstr, "O-O-O") == 0) {
   253             /* queen side castling "O-O-O" */
   254             move->piece = KING;
   255             move->fromfile = fileidx('e');
   256             move->tofile = fileidx('c');
   257             move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
   258         } else {
   259             move->piece = getpiece(mstr[0]);
   260             if (mstr[2] == 'x') {
   261                 move->capture = 1;
   262                 if (move->piece) {
   263                     /* capture (e.g. "Ndxf3") */
   264                     move->fromfile = fileidx(mstr[1]);
   265                 } else {
   266                     /* long notation capture (e.g. "e5xf6") */
   267                     move->piece = PAWN;
   268                     move->fromfile = fileidx(mstr[0]);
   269                     move->fromrow = rowidx(mstr[1]);
   270                 }
   271             } else {
   272                 /* long notation move (e.g. "Nc5a4") */
   273                 move->fromfile = fileidx(mstr[1]);
   274                 move->fromrow = rowidx(mstr[2]);
   275             }
   276             move->tofile = fileidx(mstr[3]);
   277             move->torow = rowidx(mstr[4]);
   278         }
   279     } else if (len == 6) {
   280         /* long notation capture (e.g. "Nc5xf3") */
   281         if (mstr[3] == 'x') {
   282             move->capture = 1;
   283             move->piece = getpiece(mstr[0]);
   284             move->fromfile = fileidx(mstr[1]);
   285             move->fromrow = rowidx(mstr[2]);
   286             move->tofile = fileidx(mstr[4]);
   287             move->torow = rowidx(mstr[5]);
   288         }
   289     }
   292     if (move->piece) {
   293         if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0)
   294             && !move->promotion) {
   295             return NEED_PROMOTION;
   296         }
   298         move->piece |= mycolor;
   299         if (move->fromfile == POS_UNSPECIFIED
   300             || move->fromrow == POS_UNSPECIFIED) {
   301             return getlocation(board, move);
   302         } else {
   303             return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
   304         }
   305     } else {
   306         return INVALID_MOVE_SYNTAX;
   307     }
   308 }

mercurial