src/chess/rules.c

Mon, 31 Mar 2014 15:03:25 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 31 Mar 2014 15:03:25 +0200
changeset 23
824c9522ce66
parent 21
2e5846019b4f
child 25
3ab0c2e1a4e2
permissions
-rw-r--r--

introduced game state structure

     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>
    33 #include <stdlib.h>
    35 void gamestate_cleanup(GameState *gamestate) {
    36     MoveList *elem;
    37     elem = gamestate->movelist;
    38     while (elem) {
    39         MoveList *cur = elem;
    40         elem = elem->next;
    41         free(cur);
    42     };
    43 }
    45 static void addmove(GameState* gamestate, Move *move) {
    46     MoveList *elem = malloc(sizeof(MoveList));
    47     elem->next = NULL;
    48     elem->move = *move;
    50     if (gamestate->lastmove) {
    51         gamestate->lastmove->next = elem;
    52         gamestate->lastmove = elem;
    53     } else {
    54         gamestate->movelist = gamestate->lastmove = elem;
    55     }
    56 }
    58 char getpiecechr(uint8_t piece) {
    59     switch (piece & PIECE_MASK) {
    60     case ROOK: return 'R';
    61     case KNIGHT: return 'N';
    62     case BISHOP: return 'B';
    63     case QUEEN: return 'Q';
    64     case KING: return 'K';
    65     default: return '\0';
    66     }
    67 }
    69 uint8_t getpiece(char c) {
    70     switch (c) {
    71         case 'R': return ROOK;
    72         case 'N': return KNIGHT;
    73         case 'B': return BISHOP;
    74         case 'Q': return QUEEN;
    75         case 'K': return KING;
    76         default: return 0;
    77     }
    78 }
    80 static int getlocation(GameState *gamestate, Move *move) {   
    81     uint8_t piece = move->piece & PIECE_MASK;
    82     switch (piece) {
    83         case PAWN: return pawn_getlocation(gamestate, move);
    84         case ROOK: return rook_getlocation(gamestate, move);
    85         case KNIGHT: return knight_getlocation(gamestate, move);
    86         case BISHOP: return bishop_getlocation(gamestate, move);
    87         case QUEEN: return queen_getlocation(gamestate, move);
    88         case KING: return king_getlocation(gamestate, move);
    89         default: return INVALID_MOVE_SYNTAX;
    90     }
    91 }
    94 void apply_move(GameState *gamestate, Move *move) {
    95     uint8_t piece = move->piece & PIECE_MASK;
    96     uint8_t color = move->piece & COLOR_MASK;
    98     /* en passant capture */
    99     if (move->capture && piece == PAWN &&
   100         mdst(gamestate->board, move) == 0) {
   101         gamestate->board[move->fromrow][move->tofile] = 0;
   102     }
   104     /* remove old en passant threats */
   105     for (uint8_t file = 0 ; file < 8 ; file++) {
   106         gamestate->board[3][file] &= ~ENPASSANT_THREAT;
   107         gamestate->board[4][file] &= ~ENPASSANT_THREAT;
   108     }
   110     /* add new en passant threat */
   111     if (piece == PAWN && (
   112         (move->fromrow == 1 && move->torow == 3) ||
   113         (move->fromrow == 6 && move->torow == 4))) {
   114         move->piece |= ENPASSANT_THREAT;
   115     }
   117     /* move (and maybe capture or promote) */
   118     msrc(gamestate->board, move) = 0;
   119     if (move->promotion) {
   120         mdst(gamestate->board, move) = move->promotion;
   121     } else {
   122         mdst(gamestate->board, move) = move->piece;
   123     }
   125     /* castling */
   126     if (piece == KING &&
   127         move->fromfile == fileidx('e')) {
   129         if (move->tofile == fileidx('g')) {
   130             gamestate->board[move->torow][fileidx('h')] = 0;
   131             gamestate->board[move->torow][fileidx('f')] = color|ROOK;
   132         } else if (move->tofile == fileidx('c')) {
   133             gamestate->board[move->torow][fileidx('a')] = 0;
   134             gamestate->board[move->torow][fileidx('d')] = color|ROOK;
   135         }
   136     }
   138     addmove(gamestate, move);
   139 }
   141 _Bool validate_move(GameState *gamestate, Move *move) {
   142     _Bool result;
   144     /* validate indices (don't trust opponent) */
   145     if (!chkidx(move)) {
   146         return 0;
   147     }
   149     /* must move */
   150     if (move->fromfile == move->tofile && move->fromrow == move->torow) {
   151         return 0;
   152     }
   154     /* does piece exist */
   155     result = msrc(gamestate->board, move) == move->piece;
   157     /* can't capture own pieces */
   158     if ((mdst(gamestate->board, move) & COLOR_MASK)
   159         == (move->piece & COLOR_MASK)) {
   160         return 0;
   161     }
   163     /* validate individual rules */
   164     switch (move->piece & PIECE_MASK) {
   165     case PAWN:
   166         result = result && pawn_chkrules(gamestate, move);
   167         result = result && !pawn_isblocked(gamestate, move);
   168         break;
   169     case ROOK:
   170         result = result && rook_chkrules(move);
   171         result = result && !rook_isblocked(gamestate, move);
   172         break;
   173     case KNIGHT:
   174         result = result && knight_chkrules(move);
   175         result = result && !knight_isblocked(gamestate, move);
   176         break;
   177     case BISHOP:
   178         result = result && bishop_chkrules(move);
   179         result = result && !bishop_isblocked(gamestate, move);
   180         break;
   181     case QUEEN:
   182         result = result && queen_chkrules(move);
   183         result = result && !queen_isblocked(gamestate, move);
   184         break;
   185     case KING:
   186         result = result && king_chkrules(gamestate, move);
   187         result = result && !king_isblocked(gamestate, move);
   188         break;
   189     default:
   190         result = 0;
   191     }
   193     /* is piece pinned */
   194     // TODO: make it so
   196     /* correct check and checkmate flags */
   197     // TODO: make it so
   199     return result;
   200 }
   202 int eval_move(GameState *gamestate, char *mstr, Move *move) {
   203     memset(move, 0, sizeof(Move));
   204     move->fromfile = POS_UNSPECIFIED;
   205     move->fromrow = POS_UNSPECIFIED;
   207     size_t len = strlen(mstr);
   209     /* evaluate check/checkmate flags */
   210     if (mstr[len-1] == '+') {
   211         len--; mstr[len] = '\0';
   212         move->check = 1;
   213     } else if (mstr[len-1] == '#') {
   214         len--; mstr[len] = '\0';
   215         move->checkmate = 1;
   216     }
   218     /* evaluate promotion */
   219     if (len > 3 && mstr[len-2] == '=') {
   220         move->promotion = getpiece(mstr[len-1]);
   221         if (!move->promotion) {
   222             return INVALID_MOVE_SYNTAX;
   223         } else {
   224             move->promotion |= gamestate->mycolor;
   225             len -= 2;
   226             mstr[len] = 0;
   227         }
   228     }
   230     if (len == 2) {
   231         /* pawn move (e.g. "e4") */
   232         move->piece = PAWN;
   233         move->tofile = fileidx(mstr[0]);
   234         move->torow = rowidx(mstr[1]);
   235     } else if (len == 3) {
   236         if (strcmp(mstr, "O-O") == 0) {
   237             /* king side castling */
   238             move->piece = KING;
   239             move->fromfile = fileidx('e');
   240             move->tofile = fileidx('g');
   241             move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
   242         } else {
   243             /* move (e.g. "Nf3") */
   244             move->piece = getpiece(mstr[0]);
   245             move->tofile = fileidx(mstr[1]);
   246             move->torow = rowidx(mstr[2]);
   247         }
   249     } else if (len == 4) {
   250         move->piece = getpiece(mstr[0]);
   251         if (!move->piece) {
   252             move->piece = PAWN;
   253             move->fromfile = fileidx(mstr[0]);
   254         }
   255         if (mstr[1] == 'x') {
   256             /* capture (e.g. "Nxf3", "dxe5") */
   257             move->capture = 1;
   258         } else {
   259             /* move (e.g. "Ndf3", "N2c3", "e2e4") */
   260             if (isfile(mstr[1])) {
   261                 move->fromfile = fileidx(mstr[1]);
   262                 if (move->piece == PAWN) {
   263                     move->piece = 0;
   264                 }
   265             } else {
   266                 move->fromrow = rowidx(mstr[1]);
   267             }
   268         }
   269         move->tofile = fileidx(mstr[2]);
   270         move->torow = rowidx(mstr[3]);
   271     } else if (len == 5) {
   272         if (strcmp(mstr, "O-O-O") == 0) {
   273             /* queen side castling "O-O-O" */
   274             move->piece = KING;
   275             move->fromfile = fileidx('e');
   276             move->tofile = fileidx('c');
   277             move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
   278         } else {
   279             move->piece = getpiece(mstr[0]);
   280             if (mstr[2] == 'x') {
   281                 move->capture = 1;
   282                 if (move->piece) {
   283                     /* capture (e.g. "Ndxf3") */
   284                     move->fromfile = fileidx(mstr[1]);
   285                 } else {
   286                     /* long notation capture (e.g. "e5xf6") */
   287                     move->piece = PAWN;
   288                     move->fromfile = fileidx(mstr[0]);
   289                     move->fromrow = rowidx(mstr[1]);
   290                 }
   291             } else {
   292                 /* long notation move (e.g. "Nc5a4") */
   293                 move->fromfile = fileidx(mstr[1]);
   294                 move->fromrow = rowidx(mstr[2]);
   295             }
   296             move->tofile = fileidx(mstr[3]);
   297             move->torow = rowidx(mstr[4]);
   298         }
   299     } else if (len == 6) {
   300         /* long notation capture (e.g. "Nc5xf3") */
   301         if (mstr[3] == 'x') {
   302             move->capture = 1;
   303             move->piece = getpiece(mstr[0]);
   304             move->fromfile = fileidx(mstr[1]);
   305             move->fromrow = rowidx(mstr[2]);
   306             move->tofile = fileidx(mstr[4]);
   307             move->torow = rowidx(mstr[5]);
   308         }
   309     }
   312     if (move->piece) {
   313         if (move->piece == PAWN
   314             && move->torow == (gamestate->mycolor==WHITE?7:0)
   315             && !move->promotion) {
   316             return NEED_PROMOTION;
   317         }
   319         move->piece |= gamestate->mycolor;
   320         if (move->fromfile == POS_UNSPECIFIED
   321             || move->fromrow == POS_UNSPECIFIED) {
   322             return getlocation(gamestate, move);
   323         } else {
   324             return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
   325         }
   326     } else {
   327         return INVALID_MOVE_SYNTAX;
   328     }
   329 }

mercurial