src/chess/rules.c

changeset 23
824c9522ce66
parent 21
2e5846019b4f
child 25
3ab0c2e1a4e2
equal deleted inserted replaced
22:41bbfd4d17a3 23:824c9522ce66
28 */ 28 */
29 29
30 #include "rules.h" 30 #include "rules.h"
31 #include "chess.h" 31 #include "chess.h"
32 #include <string.h> 32 #include <string.h>
33 #include <stdlib.h>
34
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 }
44
45 static void addmove(GameState* gamestate, Move *move) {
46 MoveList *elem = malloc(sizeof(MoveList));
47 elem->next = NULL;
48 elem->move = *move;
49
50 if (gamestate->lastmove) {
51 gamestate->lastmove->next = elem;
52 gamestate->lastmove = elem;
53 } else {
54 gamestate->movelist = gamestate->lastmove = elem;
55 }
56 }
33 57
34 char getpiecechr(uint8_t piece) { 58 char getpiecechr(uint8_t piece) {
35 switch (piece & PIECE_MASK) { 59 switch (piece & PIECE_MASK) {
36 case ROOK: return 'R'; 60 case ROOK: return 'R';
37 case KNIGHT: return 'N'; 61 case KNIGHT: return 'N';
51 case 'K': return KING; 75 case 'K': return KING;
52 default: return 0; 76 default: return 0;
53 } 77 }
54 } 78 }
55 79
56 /** 80 static int getlocation(GameState *gamestate, Move *move) {
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; 81 uint8_t piece = move->piece & PIECE_MASK;
65 switch (piece) { 82 switch (piece) {
66 case PAWN: return pawn_getlocation(board, move); 83 case PAWN: return pawn_getlocation(gamestate, move);
67 case ROOK: return rook_getlocation(board, move); 84 case ROOK: return rook_getlocation(gamestate, move);
68 case KNIGHT: return knight_getlocation(board, move); 85 case KNIGHT: return knight_getlocation(gamestate, move);
69 case BISHOP: return bishop_getlocation(board, move); 86 case BISHOP: return bishop_getlocation(gamestate, move);
70 case QUEEN: return queen_getlocation(board, move); 87 case QUEEN: return queen_getlocation(gamestate, move);
71 case KING: return king_getlocation(board, move); 88 case KING: return king_getlocation(gamestate, move);
72 default: return INVALID_MOVE_SYNTAX; 89 default: return INVALID_MOVE_SYNTAX;
73 } 90 }
74 } 91 }
75 92
76 93
77 void apply_move(Board board, Move *move) { 94 void apply_move(GameState *gamestate, Move *move) {
78 uint8_t piece = move->piece & PIECE_MASK; 95 uint8_t piece = move->piece & PIECE_MASK;
79 uint8_t color = move->piece & COLOR_MASK; 96 uint8_t color = move->piece & COLOR_MASK;
80 97
81 /* en passant capture */ 98 /* en passant capture */
82 if (move->capture && piece == PAWN && 99 if (move->capture && piece == PAWN &&
83 mdst(board, move) == 0) { 100 mdst(gamestate->board, move) == 0) {
84 board[move->fromrow][move->tofile] = 0; 101 gamestate->board[move->fromrow][move->tofile] = 0;
85 } 102 }
86 103
87 /* remove old en passant threats */ 104 /* remove old en passant threats */
88 for (uint8_t file = 0 ; file < 8 ; file++) { 105 for (uint8_t file = 0 ; file < 8 ; file++) {
89 board[3][file] &= ~ENPASSANT_THREAT; 106 gamestate->board[3][file] &= ~ENPASSANT_THREAT;
90 board[4][file] &= ~ENPASSANT_THREAT; 107 gamestate->board[4][file] &= ~ENPASSANT_THREAT;
91 } 108 }
92 109
93 /* add new en passant threat */ 110 /* add new en passant threat */
94 if (piece == PAWN && ( 111 if (piece == PAWN && (
95 (move->fromrow == 1 && move->torow == 3) || 112 (move->fromrow == 1 && move->torow == 3) ||
96 (move->fromrow == 6 && move->torow == 4))) { 113 (move->fromrow == 6 && move->torow == 4))) {
97 move->piece |= ENPASSANT_THREAT; 114 move->piece |= ENPASSANT_THREAT;
98 } 115 }
99 116
100 /* move (and maybe capture or promote) */ 117 /* move (and maybe capture or promote) */
101 msrc(board, move) = 0; 118 msrc(gamestate->board, move) = 0;
102 if (move->promotion) { 119 if (move->promotion) {
103 mdst(board, move) = move->promotion; 120 mdst(gamestate->board, move) = move->promotion;
104 } else { 121 } else {
105 mdst(board, move) = move->piece; 122 mdst(gamestate->board, move) = move->piece;
106 } 123 }
107 124
108 /* castling */ 125 /* castling */
109 if (piece == KING && 126 if (piece == KING &&
110 move->fromfile == fileidx('e')) { 127 move->fromfile == fileidx('e')) {
111 128
112 if (move->tofile == fileidx('g')) { 129 if (move->tofile == fileidx('g')) {
113 board[move->torow][fileidx('h')] = 0; 130 gamestate->board[move->torow][fileidx('h')] = 0;
114 board[move->torow][fileidx('f')] = color|ROOK; 131 gamestate->board[move->torow][fileidx('f')] = color|ROOK;
115 } else if (move->tofile == fileidx('c')) { 132 } else if (move->tofile == fileidx('c')) {
116 board[move->torow][fileidx('a')] = 0; 133 gamestate->board[move->torow][fileidx('a')] = 0;
117 board[move->torow][fileidx('d')] = color|ROOK; 134 gamestate->board[move->torow][fileidx('d')] = color|ROOK;
118 } 135 }
119 } 136 }
120 } 137
121 138 addmove(gamestate, move);
122 _Bool validate_move(Board board, Move *move) { 139 }
140
141 _Bool validate_move(GameState *gamestate, Move *move) {
123 _Bool result; 142 _Bool result;
124 143
125 /* validate indices (don't trust opponent) */ 144 /* validate indices (don't trust opponent) */
126 if (!chkidx(move)) { 145 if (!chkidx(move)) {
127 return 0; 146 return 0;
131 if (move->fromfile == move->tofile && move->fromrow == move->torow) { 150 if (move->fromfile == move->tofile && move->fromrow == move->torow) {
132 return 0; 151 return 0;
133 } 152 }
134 153
135 /* does piece exist */ 154 /* does piece exist */
136 result = msrc(board, move) == move->piece; 155 result = msrc(gamestate->board, move) == move->piece;
137 156
138 /* can't capture own pieces */ 157 /* can't capture own pieces */
139 if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) { 158 if ((mdst(gamestate->board, move) & COLOR_MASK)
159 == (move->piece & COLOR_MASK)) {
140 return 0; 160 return 0;
141 } 161 }
142 162
143 /* validate individual rules */ 163 /* validate individual rules */
144 switch (move->piece & PIECE_MASK) { 164 switch (move->piece & PIECE_MASK) {
145 case PAWN: 165 case PAWN:
146 result = result && pawn_chkrules(board, move); 166 result = result && pawn_chkrules(gamestate, move);
147 result = result && !pawn_isblocked(board, move); 167 result = result && !pawn_isblocked(gamestate, move);
148 break; 168 break;
149 case ROOK: 169 case ROOK:
150 result = result && rook_chkrules(move); 170 result = result && rook_chkrules(move);
151 result = result && !rook_isblocked(board, move); 171 result = result && !rook_isblocked(gamestate, move);
152 break; 172 break;
153 case KNIGHT: 173 case KNIGHT:
154 result = result && knight_chkrules(move); 174 result = result && knight_chkrules(move);
155 result = result && !knight_isblocked(board, move); 175 result = result && !knight_isblocked(gamestate, move);
156 break; 176 break;
157 case BISHOP: 177 case BISHOP:
158 result = result && bishop_chkrules(move); 178 result = result && bishop_chkrules(move);
159 result = result && !bishop_isblocked(board, move); 179 result = result && !bishop_isblocked(gamestate, move);
160 break; 180 break;
161 case QUEEN: 181 case QUEEN:
162 result = result && queen_chkrules(move); 182 result = result && queen_chkrules(move);
163 result = result && !queen_isblocked(board, move); 183 result = result && !queen_isblocked(gamestate, move);
164 break; 184 break;
165 case KING: 185 case KING:
166 result = result && king_chkrules(board, move); 186 result = result && king_chkrules(gamestate, move);
167 result = result && !king_isblocked(board, move); 187 result = result && !king_isblocked(gamestate, move);
168 break; 188 break;
169 default: 189 default:
170 result = 0; 190 result = 0;
171 } 191 }
172 192
177 // TODO: make it so 197 // TODO: make it so
178 198
179 return result; 199 return result;
180 } 200 }
181 201
182 int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) { 202 int eval_move(GameState *gamestate, char *mstr, Move *move) {
183 memset(move, 0, sizeof(Move)); 203 memset(move, 0, sizeof(Move));
184 move->fromfile = POS_UNSPECIFIED; 204 move->fromfile = POS_UNSPECIFIED;
185 move->fromrow = POS_UNSPECIFIED; 205 move->fromrow = POS_UNSPECIFIED;
186 206
187 size_t len = strlen(mstr); 207 size_t len = strlen(mstr);
199 if (len > 3 && mstr[len-2] == '=') { 219 if (len > 3 && mstr[len-2] == '=') {
200 move->promotion = getpiece(mstr[len-1]); 220 move->promotion = getpiece(mstr[len-1]);
201 if (!move->promotion) { 221 if (!move->promotion) {
202 return INVALID_MOVE_SYNTAX; 222 return INVALID_MOVE_SYNTAX;
203 } else { 223 } else {
204 move->promotion |= mycolor; 224 move->promotion |= gamestate->mycolor;
205 len -= 2; 225 len -= 2;
206 mstr[len] = 0; 226 mstr[len] = 0;
207 } 227 }
208 } 228 }
209 229
216 if (strcmp(mstr, "O-O") == 0) { 236 if (strcmp(mstr, "O-O") == 0) {
217 /* king side castling */ 237 /* king side castling */
218 move->piece = KING; 238 move->piece = KING;
219 move->fromfile = fileidx('e'); 239 move->fromfile = fileidx('e');
220 move->tofile = fileidx('g'); 240 move->tofile = fileidx('g');
221 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7; 241 move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
222 } else { 242 } else {
223 /* move (e.g. "Nf3") */ 243 /* move (e.g. "Nf3") */
224 move->piece = getpiece(mstr[0]); 244 move->piece = getpiece(mstr[0]);
225 move->tofile = fileidx(mstr[1]); 245 move->tofile = fileidx(mstr[1]);
226 move->torow = rowidx(mstr[2]); 246 move->torow = rowidx(mstr[2]);
252 if (strcmp(mstr, "O-O-O") == 0) { 272 if (strcmp(mstr, "O-O-O") == 0) {
253 /* queen side castling "O-O-O" */ 273 /* queen side castling "O-O-O" */
254 move->piece = KING; 274 move->piece = KING;
255 move->fromfile = fileidx('e'); 275 move->fromfile = fileidx('e');
256 move->tofile = fileidx('c'); 276 move->tofile = fileidx('c');
257 move->fromrow = move->torow = mycolor == WHITE ? 0 : 7; 277 move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
258 } else { 278 } else {
259 move->piece = getpiece(mstr[0]); 279 move->piece = getpiece(mstr[0]);
260 if (mstr[2] == 'x') { 280 if (mstr[2] == 'x') {
261 move->capture = 1; 281 move->capture = 1;
262 if (move->piece) { 282 if (move->piece) {
288 } 308 }
289 } 309 }
290 310
291 311
292 if (move->piece) { 312 if (move->piece) {
293 if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0) 313 if (move->piece == PAWN
314 && move->torow == (gamestate->mycolor==WHITE?7:0)
294 && !move->promotion) { 315 && !move->promotion) {
295 return NEED_PROMOTION; 316 return NEED_PROMOTION;
296 } 317 }
297 318
298 move->piece |= mycolor; 319 move->piece |= gamestate->mycolor;
299 if (move->fromfile == POS_UNSPECIFIED 320 if (move->fromfile == POS_UNSPECIFIED
300 || move->fromrow == POS_UNSPECIFIED) { 321 || move->fromrow == POS_UNSPECIFIED) {
301 return getlocation(board, move); 322 return getlocation(gamestate, move);
302 } else { 323 } else {
303 return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION; 324 return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
304 } 325 }
305 } else { 326 } else {
306 return INVALID_MOVE_SYNTAX; 327 return INVALID_MOVE_SYNTAX;

mercurial