2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 const char pieces
[] = {' ', 'p', 'n', 'b', 'r', 'q', 'k'};
24 /* move in coordinate notation */
26 coord_move(int move
, char *buf
)
30 if (GET_PROMOTE(move
))
31 snprintf(buf
, 6, "%s%s%c", char_board
[GET_FROM(move
)], \
32 char_board
[GET_TO(move
)], pieces
[GET_PROMOTE(move
)]);
34 snprintf(buf
, 5, "%s%s", char_board
[GET_FROM(move
)], \
35 char_board
[GET_TO(move
)]);
40 /* PV in coordinate notation */
42 get_pv_string_coord(char *buf
)
48 for (i
= 0; i
< pv_length
[0]; i
++) {
49 strcat(buf
, coord_move(pv
[0][i
], move_buf
));
57 /* PV in SAN notation */
59 get_pv_string_san(char *buf
)
67 sprintf(buf
, "%d. ... ", (game_history
.count
+ 1) / 2 + \
68 (game_history
.count
? 0 : 1));
70 sprintf(buf
, "%d. ", (game_history
.count
+ 1) / 2 + 1);
72 for (i
= 0; i
< pv_length
[0]; i
++) {
74 sprintf(move_buf
, "%d. ", (game_history
.count
+ 1) / 2 + 1);
75 strcat(buf
, move_buf
);
77 sprintf(move_buf
, "%s ", san_move(pv
[0][i
], move_buf2
));
78 strcat(buf
, move_buf
);
80 make_move(pv
[0][i
], FALSE
);
84 for (i
= 0; i
< pv_length
[0]; i
++)
87 assert(0 == 1); /* no PV! */
92 /* make move and update board info */
94 make_move(int move
, int tb
)
98 int cap_piece
, piece_from
, piece_to
;
102 assert(board_is_legal(&brd
));
103 assert(move_is_legal(move
));
105 from
= GET_FROM(move
); /* 'from' coordinate */
106 to
= GET_TO(move
); /* 'to' coordinate */
107 type
= GET_TYPE(move
); /* type flags */
111 if (type
& TYPE_CASTLE
) {
112 /* check if castle move is legal here */
114 if (IS_ATTACKED(E1
, BLACK
) || IS_ATTACKED(F1
, BLACK
) || \
115 IS_ATTACKED(G1
, BLACK
))
117 } else if (to
== C1
) {
118 if (IS_ATTACKED(E1
, BLACK
) || IS_ATTACKED(D1
, BLACK
) || \
119 IS_ATTACKED(C1
, BLACK
))
121 } else if (to
== G8
) {
122 if (IS_ATTACKED(E8
, WHITE
) || IS_ATTACKED(F8
, WHITE
) || \
123 IS_ATTACKED(G8
, WHITE
))
125 } else if (to
== C8
) {
126 if (IS_ATTACKED(E8
, WHITE
) || IS_ATTACKED(D8
, WHITE
) || \
127 IS_ATTACKED(C8
, WHITE
))
133 cap_piece
= brd
.cap_piece
= square64
[to
];
136 /* copy parameters for takeback */
137 memcpy(&game_history
.board
[game_history
.count
++], &brd
, \
138 sizeof(struct board_t
));
140 piece_from
= square64
[from
];
143 brd
.hash_key
^= hash_ep
[_FILE(brd
.ep
)]; /* clear ep hash */
146 /* remove captured piece */
147 remove_piece(to
, cap_piece
, xwtm
);
149 /* handle promote move */
150 piece_to
= (type
& TYPE_PROMOTE
) ? GET_PROMOTE(move
) : piece_from
;
152 remove_piece(from
, piece_from
, brd
.wtm
);
153 add_piece(to
, piece_to
, brd
.wtm
);
155 if (type
& TYPE_ENPASSANT
) {
156 /* remove enpassant victim */
157 ep_square
= to
- (brd
.wtm
? -1 : 1) * 8;
158 remove_piece(ep_square
, PAWN
, xwtm
);
161 brd
.ep
= -1; /* remove ep status by default */
162 if (type
& TYPE_PAWN_TWO
)
163 /* polyglot-compatibility hack! if there is no pawn on enpassant
164 target square skip ep */
165 if ((BIT(to
- 1) & PAWNS(xwtm
)) || (BIT(to
+ 1) & PAWNS(xwtm
))) {
166 brd
.ep
= (to
+ from
) / 2;
167 brd
.hash_key
^= hash_ep
[_FILE(brd
.ep
)];
172 add_piece(F1
, ROOK
, brd
.wtm
);
173 remove_piece(H1
, ROOK
, brd
.wtm
);
174 castled
[WHITE
] = TRUE
;
175 } else if (to
== C1
) {
176 add_piece(D1
, ROOK
, brd
.wtm
);
177 remove_piece(A1
, ROOK
, brd
.wtm
);
178 castled
[WHITE
] = TRUE
;
179 } else if (to
== G8
) {
180 add_piece(F8
, ROOK
, brd
.wtm
);
181 remove_piece(H8
, ROOK
, brd
.wtm
);
182 castled
[BLACK
] = TRUE
;
183 } else if (to
== C8
) {
184 add_piece(D8
, ROOK
, brd
.wtm
);
185 remove_piece(A8
, ROOK
, brd
.wtm
);
186 castled
[BLACK
] = TRUE
;
190 if (brd
.castle_mask
) {
192 if (brd
.castle_mask
& WHITE_CASTLE_KINGSIDE
)
193 brd
.hash_key
^= hash_wck
;
194 if (brd
.castle_mask
& WHITE_CASTLE_QUEENSIDE
)
195 brd
.hash_key
^= hash_wcq
;
196 brd
.castle_mask
&= ~(WHITE_CASTLE_KINGSIDE
| WHITE_CASTLE_QUEENSIDE
);
197 } else if (from
== E8
) {
198 if (brd
.castle_mask
& BLACK_CASTLE_KINGSIDE
)
199 brd
.hash_key
^= hash_bck
;
200 if (brd
.castle_mask
& BLACK_CASTLE_QUEENSIDE
)
201 brd
.hash_key
^= hash_bcq
;
202 brd
.castle_mask
&= ~(BLACK_CASTLE_KINGSIDE
| BLACK_CASTLE_QUEENSIDE
);
204 if (from
== H1
|| to
== H1
) {
205 if (brd
.castle_mask
& WHITE_CASTLE_KINGSIDE
)
206 brd
.hash_key
^= hash_wck
;
207 brd
.castle_mask
&= ~WHITE_CASTLE_KINGSIDE
;
209 if (from
== A1
|| to
== A1
) {
210 if (brd
.castle_mask
& WHITE_CASTLE_QUEENSIDE
)
211 brd
.hash_key
^= hash_wcq
;
212 brd
.castle_mask
&= ~WHITE_CASTLE_QUEENSIDE
;
214 if (from
== H8
|| to
== H8
) {
215 if (brd
.castle_mask
& BLACK_CASTLE_KINGSIDE
)
216 brd
.hash_key
^= hash_bck
;
217 brd
.castle_mask
&= ~BLACK_CASTLE_KINGSIDE
;
219 if (from
== A8
|| to
== A8
) {
220 if (brd
.castle_mask
& BLACK_CASTLE_QUEENSIDE
)
221 brd
.hash_key
^= hash_bcq
;
222 brd
.castle_mask
&= ~BLACK_CASTLE_QUEENSIDE
;
226 /* if the move is not a capture or pawn push, increase fifty_rule */
227 brd
.fifty_rule
= (!type
|| type
== TYPE_CASTLE
)? brd
.fifty_rule
+ 1 : 0;
231 brd
.hash_key
^= hash_side
;
233 if (IS_CHECKED(1 ^ brd
.wtm
)) {
239 counters
.searched_nodes
++;
244 /* used for sanity check */
246 move_is_legal(int move
)
248 int from
= GET_FROM(move
);
249 int to
= GET_TO(move
);
254 int piece_from
= square64
[from
];
255 int piece_to
= square64
[to
];
260 if ((BIT(from
) & piece_boards
[brd
.wtm
][piece_from
]) == 0)
264 if (BIT(to
) & side_boards
[brd
.wtm
])
266 if (piece_to
== KING
)
273 /* return internal binary move representation from coordinate */
275 parse_move_coord(char *move
)
279 struct moves_t moves
;
281 gen_legal_moves(&moves
);
283 /* generate pseudolegal moves and find target move */
284 for (i
= 0; i
< moves
.count
; i
++) {
285 if (!strcmp(move
, coord_move(moves
.move
[i
], buf
)))
286 return moves
.move
[i
];
291 /* return internal binary move representation from SAN */
293 parse_move_san(char *move
)
296 char buf
[MAX_STRING
];
297 struct moves_t moves
;
299 gen_legal_moves(&moves
);
301 /* generate pseudolegal moves and find target move */
302 for (i
= 0; i
< moves
.count
; i
++) {
303 if (!strncmp(move
, san_move(moves
.move
[i
], buf
), 6))
304 return moves
.move
[i
];
311 print_move_coord(int move
)
314 printf("%s\n", coord_move(move
, buf
));
318 print_moves_coord(struct moves_t
*moves
)
323 for (i
= 0; i
< moves
->count
; i
++)
324 printf("%s ", coord_move(moves
->move
[i
], buf
));
329 print_moves_san(struct moves_t
*moves
)
334 for (i
= 0; i
< moves
->count
; i
++) {
335 if (make_move(moves
->move
[i
], TRUE
))
336 printf("%s ", san_move(moves
->move
[i
], buf
));
352 assert(board_is_legal(&brd
));
354 c
= --game_history
.count
;
355 cap_piece
= game_history
.board
[c
].cap_piece
;
356 move
= game_history
.board
[c
].move
;
358 brd
.castle_mask
= game_history
.board
[c
].castle_mask
;
359 brd
.ep
= game_history
.board
[c
].ep
;
361 /* do the following if move is not 'NULL move' */
363 from
= GET_FROM(move
);
365 type
= GET_TYPE(move
);
366 to_piece
= square64
[to
];
369 remove_piece(to
, to_piece
, xwtm
);
372 /* restore captured piece */
373 add_piece(to
, cap_piece
, brd
.wtm
);
374 add_piece(from
, (type
& TYPE_PROMOTE
)? PAWN
: to_piece
, xwtm
);
375 } else if (type
& TYPE_ENPASSANT
) {
376 /* restore captured by enpassant pawn */
377 add_piece(brd
.wtm
? to
- 8 : to
+ 8, PAWN
, brd
.wtm
);
378 add_piece(from
, PAWN
, xwtm
);
379 } else if (type
& TYPE_PROMOTE
)
380 add_piece(from
, PAWN
, xwtm
);
382 add_piece(from
, to_piece
, xwtm
);
385 if (type
& TYPE_CASTLE
) {
387 add_piece(H1
, ROOK
, xwtm
);
388 remove_piece(F1
, ROOK
, xwtm
);
389 castled
[WHITE
] = FALSE
;
390 } else if (to
== C1
) {
391 add_piece(A1
, ROOK
, xwtm
);
392 remove_piece(D1
, ROOK
, xwtm
);
393 castled
[WHITE
] = FALSE
;
394 } else if (to
== G8
) {
395 add_piece(H8
, ROOK
, xwtm
);
396 remove_piece(F8
, ROOK
, xwtm
);
397 castled
[BLACK
] = FALSE
;
398 } else if (to
== C8
) {
399 add_piece(A8
, ROOK
, xwtm
);
400 remove_piece(D8
, ROOK
, xwtm
);
401 castled
[BLACK
] = FALSE
;
407 brd
.wtm
= 1 ^ brd
.wtm
;
408 brd
.hash_key
= game_history
.board
[c
].hash_key
;
409 brd
.hash_pawn_key
= game_history
.board
[c
].hash_pawn_key
;
410 brd
.fifty_rule
= game_history
.board
[c
].fifty_rule
;