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;
230 brd
.hash_key
^= hash_side
;
232 if (IS_CHECKED(1 ^ brd
.wtm
)) {
238 counters
.searched_nodes
++;
243 /* used for sanity check */
245 move_is_legal(int move
)
247 int from
= GET_FROM(move
);
248 int to
= GET_TO(move
);
253 int piece_from
= square64
[from
];
254 int piece_to
= square64
[to
];
259 if ((BIT(from
) & piece_boards
[brd
.wtm
][piece_from
]) == 0)
263 if (BIT(to
) & side_boards
[brd
.wtm
])
265 if (piece_to
== KING
)
272 /* return internal binary move representation from coordinate */
274 parse_move_coord(char *move
)
278 struct moves_t moves
;
280 gen_legal_moves(&moves
);
282 /* generate pseudolegal moves and find target move */
283 for (i
= 0; i
< moves
.count
; i
++) {
284 if (!strcmp(move
, coord_move(moves
.move
[i
], buf
)))
285 return moves
.move
[i
];
290 /* return internal binary move representation from SAN */
292 parse_move_san(char *move
)
295 char buf
[MAX_STRING
];
296 struct moves_t moves
;
298 gen_legal_moves(&moves
);
300 /* generate pseudolegal moves and find target move */
301 for (i
= 0; i
< moves
.count
; i
++) {
302 if (!strncmp(move
, san_move(moves
.move
[i
], buf
), 6))
303 return moves
.move
[i
];
310 print_move_coord(int move
)
313 printf("%s\n", coord_move(move
, buf
));
317 print_moves_coord(struct moves_t
*moves
)
322 for (i
= 0; i
< moves
->count
; i
++)
323 printf("%s ", coord_move(moves
->move
[i
], buf
));
328 print_moves_san(struct moves_t
*moves
)
333 for (i
= 0; i
< moves
->count
; i
++) {
334 if (make_move(moves
->move
[i
], TRUE
))
335 printf("%s ", san_move(moves
->move
[i
], buf
));
351 assert(board_is_legal(&brd
));
353 c
= --game_history
.count
;
354 cap_piece
= game_history
.board
[c
].cap_piece
;
355 move
= game_history
.board
[c
].move
;
357 brd
.castle_mask
= game_history
.board
[c
].castle_mask
;
358 brd
.ep
= game_history
.board
[c
].ep
;
360 /* do the following if move is not 'NULL move' */
362 from
= GET_FROM(move
);
364 type
= GET_TYPE(move
);
365 to_piece
= square64
[to
];
368 remove_piece(to
, to_piece
, xwtm
);
371 /* restore captured piece */
372 add_piece(to
, cap_piece
, brd
.wtm
);
373 add_piece(from
, (type
& TYPE_PROMOTE
)? PAWN
: to_piece
, xwtm
);
374 } else if (type
& TYPE_ENPASSANT
) {
375 /* restore captured by enpassant pawn */
376 add_piece(brd
.wtm
? to
- 8 : to
+ 8, PAWN
, brd
.wtm
);
377 add_piece(from
, PAWN
, xwtm
);
378 } else if (type
& TYPE_PROMOTE
)
379 add_piece(from
, PAWN
, xwtm
);
381 add_piece(from
, to_piece
, xwtm
);
384 if (type
& TYPE_CASTLE
) {
386 add_piece(H1
, ROOK
, xwtm
);
387 remove_piece(F1
, ROOK
, xwtm
);
388 castled
[WHITE
] = FALSE
;
389 } else if (to
== C1
) {
390 add_piece(A1
, ROOK
, xwtm
);
391 remove_piece(D1
, ROOK
, xwtm
);
392 castled
[WHITE
] = FALSE
;
393 } else if (to
== G8
) {
394 add_piece(H8
, ROOK
, xwtm
);
395 remove_piece(F8
, ROOK
, xwtm
);
396 castled
[BLACK
] = FALSE
;
397 } else if (to
== C8
) {
398 add_piece(A8
, ROOK
, xwtm
);
399 remove_piece(D8
, ROOK
, xwtm
);
400 castled
[BLACK
] = FALSE
;
404 brd
.wtm
= 1 ^ brd
.wtm
;
405 brd
.hash_key
= game_history
.board
[c
].hash_key
;
406 brd
.hash_pawn_key
= game_history
.board
[c
].hash_pawn_key
;
407 brd
.fifty_rule
= game_history
.board
[c
].fifty_rule
;