7 void place_piece(struct position *pos, unsigned file, unsigned rank, unsigned char piece)
9 struct piece *ptr = IS_WHITE(piece) ? pos->white_pieces : pos->black_pieces;
12 for (i = 0; i < 16; ++i) {
13 if (ptr[i].type == PIECE_EMPTY) {
14 ptr[i].type = MAKE_COLORLESS(piece);
15 ptr[i].square = SQUARE_TO_NUM(file, rank);
17 pos->board[ptr[i].square] = piece | (i << 4);
26 void init_position(struct position *pos)
31 for (i = 0; i < NUM_SQUARES; ++i) {
32 pos->board[i] = PIECE_EMPTY;
34 for (i = 0; i < 16; ++i) {
35 pos->white_pieces[i].type = pos->black_pieces[i].type = PIECE_EMPTY;
38 // mark off the invalid squares
39 for (x = 0; x < 10; ++x) {
40 pos->board[x + 0 * 10] = PIECE_INVALID;
41 pos->board[x + 1 * 10] = PIECE_INVALID;
42 pos->board[x + 10 * 10] = PIECE_INVALID;
43 pos->board[x + 11 * 10] = PIECE_INVALID;
45 for (y = 2; y < 10; ++y) {
46 pos->board[0 + y * 10] = PIECE_INVALID;
47 pos->board[9 + y * 10] = PIECE_INVALID;
51 place_piece(pos, 4, 0, MAKE_WHITE(PIECE_KING));
52 place_piece(pos, 4, 7, MAKE_BLACK(PIECE_KING));
55 place_piece(pos, 3, 0, MAKE_WHITE(PIECE_QUEEN));
56 place_piece(pos, 3, 7, MAKE_BLACK(PIECE_QUEEN));
59 place_piece(pos, 0, 0, MAKE_WHITE(PIECE_ROOK));
60 place_piece(pos, 7, 0, MAKE_WHITE(PIECE_ROOK));
61 place_piece(pos, 0, 7, MAKE_BLACK(PIECE_ROOK));
62 place_piece(pos, 7, 7, MAKE_BLACK(PIECE_ROOK));
65 place_piece(pos, 2, 0, MAKE_WHITE(PIECE_BISHOP));
66 place_piece(pos, 5, 0, MAKE_WHITE(PIECE_BISHOP));
67 place_piece(pos, 2, 7, MAKE_BLACK(PIECE_BISHOP));
68 place_piece(pos, 5, 7, MAKE_BLACK(PIECE_BISHOP));
71 place_piece(pos, 1, 0, MAKE_WHITE(PIECE_KNIGHT));
72 place_piece(pos, 6, 0, MAKE_WHITE(PIECE_KNIGHT));
73 place_piece(pos, 1, 7, MAKE_BLACK(PIECE_KNIGHT));
74 place_piece(pos, 6, 7, MAKE_BLACK(PIECE_KNIGHT));
77 for (x = 0; x < 8; ++x) {
78 place_piece(pos, x, 1, MAKE_WHITE(PIECE_PAWN));
79 place_piece(pos, x, 6, MAKE_BLACK(PIECE_PAWN));
82 // non-piece information
83 pos->wc_short = pos->wc_long = pos->bc_short = pos->bc_long = true;
85 pos->white_to_move = true;
88 // checks various internal structures -- not a complete check, but useful
89 // to safeguard against corruption
90 void validate_position(const struct position * const pos)
95 // both sides need kings
96 assert(pos->white_pieces[0].type == PIECE_KING);
97 assert(pos->black_pieces[0].type == PIECE_KING);
100 // check that all material is on the board, with correct indexes
101 for (i = 0; i < 2; ++i) {
102 bool white = (i == 0);
103 const struct piece * const pieces = (white ? pos->white_pieces : pos->black_pieces);
105 for (j = 0; j < 16; ++j) {
106 if (pieces[j].type == PIECE_EMPTY)
110 assert(pieces[j].type >= PIECE_PAWN);
111 assert(pieces[j].type <= PIECE_QUEEN);
112 assert(pieces[j].type != PIECE_INVALID);
115 assert(pieces[j].square >= SQUARE_TO_NUM(0, 0));
116 assert(pieces[j].square <= SQUARE_TO_NUM(7, 7));
117 assert(NUM_TO_FILE(pieces[j].square) >= 0);
118 assert(NUM_TO_FILE(pieces[j].square) <= 7);
119 assert(NUM_TO_RANK(pieces[j].square) >= 0);
120 assert(NUM_TO_RANK(pieces[j].square) <= 7);
123 assert(MAKE_COLORLESS(pos->board[pieces[j].square]) == pieces[j].type);
126 assert(IS_WHITE(pos->board[pieces[j].square]));
128 assert(IS_BLACK(pos->board[pieces[j].square]));
130 assert(FIND_INDEX(pos->board[pieces[j].square]) == j);
134 // check that there's no phantom material
135 for (i = 0; i < 8; ++i) {
136 for (j = 0; j < 8; ++j) {
137 unsigned square = SQUARE_TO_NUM(i, j);
139 if (MAKE_COLORLESS(pos->board[square]) == PIECE_EMPTY)
142 if (IS_WHITE(pos->board[square])) {
143 assert(pos->white_pieces[FIND_INDEX(pos->board[square])].type == MAKE_COLORLESS(pos->board[square]));
144 assert(pos->white_pieces[FIND_INDEX(pos->board[square])].square == square);
146 assert(pos->black_pieces[FIND_INDEX(pos->board[square])].type == MAKE_COLORLESS(pos->board[square]));
147 assert(pos->black_pieces[FIND_INDEX(pos->board[square])].square == square);
152 // TODO: check castling sanity
155 char piece_to_char(int piece)
157 switch (piece & 0x0f) {
160 case MAKE_WHITE(PIECE_PAWN):
162 case MAKE_BLACK(PIECE_PAWN):
164 case MAKE_WHITE(PIECE_ROOK):
166 case MAKE_BLACK(PIECE_ROOK):
168 case MAKE_WHITE(PIECE_KNIGHT):
170 case MAKE_BLACK(PIECE_KNIGHT):
172 case MAKE_WHITE(PIECE_BISHOP):
174 case MAKE_BLACK(PIECE_BISHOP):
176 case MAKE_WHITE(PIECE_QUEEN):
178 case MAKE_BLACK(PIECE_QUEEN):
180 case MAKE_WHITE(PIECE_KING):
182 case MAKE_BLACK(PIECE_KING):
189 void print_position(struct position *pos)
193 printf("Position:\n\n");
195 for (y = 8; y --> 0; ) {
197 for (x = 0; x < 8; ++x) {
198 int piece = pos->board[SQUARE_TO_NUM(x, y)];
200 if (piece == PIECE_EMPTY) {
201 if (SQUARE_TO_NUM(x, y) == pos->ep_square) {
207 putchar(piece_to_char(pos->board[SQUARE_TO_NUM(x, y)]));
213 if (pos->white_to_move) {
214 printf("White to move\n");
216 printf("Black to move\n");
222 printf("Black pieces:");
223 for (i = 0; i < 16; ++i) {
224 int type = pos->black_pieces[i].type;
225 int square = pos->black_pieces[i].square;
226 if (type != PIECE_EMPTY)
227 printf(" %c%u(%c)", "abcdefgh"[NUM_TO_FILE(square)], NUM_TO_RANK(square) + 1, piece_to_char(type));
233 printf("\nStatic evaluation: %.2f\n", 0.01f * evaluate(pos));
236 void real_make_move(struct position *pos, unsigned from, unsigned to, struct piece *from_ptr, struct piece *to_ptr)
238 unsigned piece = pos->board[from];
239 unsigned new_ep_square = 0;
241 validate_position(pos);
243 if (pos->board[to] != PIECE_EMPTY) {
245 to_ptr = &to_ptr[FIND_INDEX(pos->board[to])];
246 to_ptr->type = PIECE_EMPTY;
249 // see if the rook was captured
251 pos->wc_short = false;
253 pos->wc_long = false;
255 pos->bc_short = false;
257 pos->bc_long = false;
260 // update castling, and possibly castle
261 if (MAKE_COLORLESS(piece) == PIECE_KING) {
262 if (IS_WHITE(piece)) {
263 // whoa, hardcoded =)
264 if (from == 25 && to == 27) {
265 assert(from_ptr[3].square == 28);
266 from_ptr[3].square = 26;
267 pos->board[26] = pos->board[28];
268 pos->board[28] = PIECE_EMPTY;
269 } else if (from == 25 && to == 23) {
270 assert(from_ptr[2].square == 21);
271 from_ptr[2].square = 24;
272 pos->board[24] = pos->board[21];
273 pos->board[21] = PIECE_EMPTY;
276 pos->wc_short = pos->wc_long = false;
278 if (from == 95 && to == 97) {
279 assert(from_ptr[3].square == 98);
280 from_ptr[3].square = 96;
281 pos->board[96] = pos->board[98];
282 pos->board[98] = PIECE_EMPTY;
283 } else if (from == 95 && to == 93) {
284 assert(from_ptr[2].square == 91);
285 from_ptr[2].square = 94;
286 pos->board[94] = pos->board[91];
287 pos->board[91] = PIECE_EMPTY;
290 pos->bc_short = pos->bc_long = false;
292 } else if (MAKE_COLORLESS(piece) == PIECE_ROOK) {
293 if (IS_WHITE(piece)) {
295 pos->wc_short = false;
297 pos->wc_long = false;
300 pos->bc_short = false;
302 pos->bc_long = false;
306 // en passant and promotion handling
307 if (MAKE_COLORLESS(piece) == PIECE_PAWN) {
308 if (to == pos->ep_square) {
309 // en passant capture
310 if (IS_WHITE(piece)) {
311 to_ptr = &to_ptr[FIND_INDEX(pos->board[to - 10])];
312 pos->board[to - 10] = PIECE_EMPTY;
314 to_ptr = &to_ptr[FIND_INDEX(pos->board[to + 10])];
315 pos->board[to + 10] = PIECE_EMPTY;
317 to_ptr->type = PIECE_EMPTY;
319 } else if (abs(to - from) == 20) {
321 if (IS_WHITE(piece)) {
322 new_ep_square = to - 10;
324 new_ep_square = to + 10;
326 } else if (NUM_TO_RANK(to) == 0 || NUM_TO_RANK(to) == 7) {
328 from_ptr->type = PIECE_QUEEN;
329 piece = (piece & 0xf8) | PIECE_QUEEN;
334 from_ptr->square = to;
336 // and update the board
337 pos->board[to] = piece;
338 pos->board[from] = PIECE_EMPTY;
339 pos->ep_square = new_ep_square;
341 pos->white_to_move = !pos->white_to_move;
343 validate_position(pos);
346 // not used in the move generator, real_make_move() is what's used there
347 void make_move(struct position *pos, unsigned from, unsigned to)
349 struct piece *from_ptr, *to_ptr;
351 validate_position(pos);
353 if (IS_WHITE(pos->board[from])) {
354 from_ptr = pos->white_pieces;
355 to_ptr = pos->black_pieces;
357 from_ptr = pos->black_pieces;
358 to_ptr = pos->white_pieces;
361 from_ptr = &from_ptr[FIND_INDEX(pos->board[from])];
362 real_make_move(pos, from, to, from_ptr, to_ptr);