1 /****************************************************************************
4 Copyright (c) 2001 Jerome Jacovella-St-Louis
7 chessutils.ec - Utilities to validate moves
8 ****************************************************************************/
11 enum PieceType : byte { Empty, Pawn, Knight, Bishop, Rook, Queen, King };
12 enum Player : byte { White, Black };
14 int materialValues[PieceType] = { 0, 10, 30, 35, 50, 90, 10000 };
19 Player player : 1 : 3;
20 PieceType type : 3 : 0;
34 enum State { Normal, Check, CheckMate, StaleMate };
39 bool isLocalPlayer[Player];
42 bool kingMoved[Player], qRookMoved[Player], kRookMoved[Player];
47 int pieceCount[Player][PieceType];
48 int materialValue[Player];
54 static bool FreeWay(Piece board[8][8], int x1, int y1, int x2, int y2)
57 int dx = Sgn(x2-x1), dy = Sgn(y2-y1);
59 for(x = x1+dx, y = y1+dy; x != x2 || y != y2; x+=dx, y+=dy)
65 static bool BasicMove(Piece board[8][8], int x1, int y1, int x2, int y2)
68 Piece source = board[y1][x1];
69 Player player = source.player;
70 Piece dest = board[y2][x2];
72 if(!dest || player != dest.player)
74 PieceType piece = source.type;
82 int direction = (player == White) ? 1 : -1;
83 if(dy == direction && Abs(dx) == 1 && dest)
88 if( (Abs(dx) == 1 && Abs(dy) == 2) ||
89 (Abs(dy) == 1 && Abs(dx) == 2))
93 if(Abs(dx) == Abs(dy) && FreeWay(board, x1,y1,x2,y2))
97 if((!Abs(dx) || !Abs(dy)) && FreeWay(board, x1,y1,x2,y2))
101 if((!Abs(dx) || !Abs(dy) || Abs(dx) == Abs(dy)) &&
102 FreeWay(board, x1,y1,x2,y2))
106 if(Abs(dx) <= 1 && Abs(dy) <= 1)
114 bool Check(ChessState state, Player player, int kx, int ky)
117 Piece old1 = 0xFF, old2;
118 bool checked = false;
122 kx = state.kings[player].x;
123 ky = state.kings[player].y;
127 old1 = state.board[state.kings[player].y][state.kings[player].x];
128 state.board[state.kings[player].y][state.kings[player].x] = Piece { };
130 old2 = state.board[ky][kx];
131 state.board[ky][kx] = Piece { player, King };
138 Piece atBoard = state.board[y][x];
139 if(atBoard && atBoard.player != player)
141 if(BasicMove(state.board, x, y, kx, ky))
154 state.board[ky][kx] = old2;
155 state.board[state.kings[player].y][state.kings[player].x] = old1;
160 bool IsMoveValid(int x1, int y1, int x2, int y2, ChessState state, Piece endBoard[8][8], bool validate)
163 Piece source = state.board[y1][x1];
164 PieceType piece = source.type;
165 Player player = source.player;
170 if(!validate || (x2 >= 0 && y2 >= 0 && x2<8 && y2<8))
172 if(!(valid = (validate ? BasicMove(state.board, x1,y1,x2,y2) : true)))
174 // Handle special moves (pawn & castle)
179 int direction = (player == White) ? 1 : -1;
180 int start = (player == White) ? 1 : 6;
184 if(x1 == x2 && !state.board[y2][x2])
187 else if(Abs(dx) == 1 &&
188 x2 == state.enPassant.x && y2 == state.enPassant.y + direction)
191 // First 2 Squares Move
192 else if(y2 - y1 == direction * 2 && y1 == start && x1 == x2
193 && !state.board[y1+direction][x1] && !state.board[y2][x1])
199 if(!dy && Abs(dx) == 2)
201 if(!state.kingMoved[player] && !Check(state, player, x1, y1))
204 if(dx == 2 && !state.kRookMoved[player] &&
205 !state.board[y1][5] && !state.board[y1][6] &&
206 !Check(state, player, 5, y1))
209 else if(dx == -2 && !state.qRookMoved[player] &&
210 !state.board[y1][3] && !state.board[y1][2] && !state.board[y1][1] &&
211 !Check(state, player, 3, y1))
222 if(validate || endBoard)
224 ChessState tmpState = state;
226 tmpState.board[y1][x1] = Piece {};
228 // Handle special moves (pawn & castle)
233 int direction = (player == White) ? 1 : -1;
234 int start = (player == White) ? 1 : 6;
238 if(Abs(dx) == 1 && x2 == state.enPassant.x && y2 == state.enPassant.y + direction)
239 tmpState.board[state.enPassant.y][state.enPassant.x] = Piece {};
249 tmpState.board[y1][7] = Piece { };
250 tmpState.board[y1][5] = Piece { player, Rook };
255 tmpState.board[y1][0] = Piece { };
256 tmpState.board[y1][3] = Piece { player, Rook };
259 // Keep Track of King
260 tmpState.kings[player].x = x2;
261 tmpState.kings[player].y = y2;
265 tmpState.board[y2][x2] = state.board[y1][x1];
267 valid = validate ? !Check(tmpState, player, -1, -1) : true;
268 if(valid && endBoard)
269 CopyBytes(endBoard, tmpState.board, 64);
275 bool StateMakeMove(ChessState state, int x1, int y1, int x2, int y2, PieceType promotion, bool validate, int * delta)
278 PieceType type = state.board[y1][x1].type;
279 Player player = state.board[y1][x1].player;
281 PieceType captured = state.board[y2][x2].type;
284 if(x2 == 7 && y2 == ((player == White) ? 7 : 0) && !state.kRookMoved[(Player)!player])
285 state.kRookMoved[(Player)!player] = true;
286 else if(x2 == 0 && y2 == ((player == White) ? 7 : 0) && !state.qRookMoved[(Player)!player])
287 state.qRookMoved[(Player)!player] = true;
289 state.pieceCount[(Player)!player][captured]--;
290 state.materialValue[(Player)!player] -= materialValues[captured];
292 *delta = materialValues[captured];
295 else if(type == Pawn && Abs(x2-x1) == 1)
297 state.pieceCount[(Player)!player][Pawn]--;
298 state.materialValue[(Player)!player] -= materialValues[Pawn];
300 *delta = materialValues[Pawn];
303 if(IsMoveValid(x1,y1,x2,y2, state, state.board, validate))
308 if(type == Pawn && Abs(y2-y1) == 2)
310 state.enPassant.x = x2;
311 state.enPassant.y = y2;
315 state.enPassant.x = -1;
316 state.enPassant.y = -1;
326 state.kRookMoved[player] = true;
327 state.castled[player] = true;
331 state.qRookMoved[player] = true;
332 state.castled[player] = true;
337 // Rook moved (can't castle with it)
338 if(type == Rook && y1 == ((player == White) ? 0 : 7))
340 if(!state.qRookMoved[player] && x1 == 0)
341 state.qRookMoved[player] = true;
342 else if(!state.kRookMoved[player] && x1 == 7)
343 state.kRookMoved[player] = true;
347 if(type == Pawn && y2 == ((player == White) ? 7 : 0))
349 state.board[y2][x2] = Piece { player, promotion };
351 state.pieceCount[player][Pawn]--;
352 state.pieceCount[player][promotion]++;
353 state.materialValue[player] += materialValues[promotion] - materialValues[Pawn];
355 *delta += materialValues[promotion] - materialValues[Pawn];
358 // Keep track of the kings
361 state.kings[player].x = x2;
362 state.kings[player].y = y2;
364 state.kingMoved[player] = true;