1
2 // move_do.cpp
3
4 // includes
5
6 #include "attack.h"
7 #include "board.h"
8 #include "colour.h"
9 #include "hash.h"
10 #include "move.h"
11 #include "move_do.h"
12 #include "pawn.h" // TODO: bit.h
13 #include "piece.h"
14 #include "pst.h"
15 #include "random.h"
16 #include "util.h"
17 #include "value.h"
18
19 // variables
20
21 static int CastleMask[SquareNb];
22
23 // prototypes
24
25 static void square_clear (board_t * board, int square, int piece, bool update);
26 static void square_set (board_t * board, int square, int piece, int pos, bool update);
27 static void square_move (board_t * board, int from, int to, int piece, bool update);
28
29 // functions
30
31 // move_do_init()
32
move_do_init()33 void move_do_init() {
34
35 int sq;
36
37 for (sq = 0; sq < SquareNb; sq++) CastleMask[sq] = 0xF;
38
39 CastleMask[E1] &= ~FlagsWhiteKingCastle;
40 CastleMask[H1] &= ~FlagsWhiteKingCastle;
41
42 CastleMask[E1] &= ~FlagsWhiteQueenCastle;
43 CastleMask[A1] &= ~FlagsWhiteQueenCastle;
44
45 CastleMask[E8] &= ~FlagsBlackKingCastle;
46 CastleMask[H8] &= ~FlagsBlackKingCastle;
47
48 CastleMask[E8] &= ~FlagsBlackQueenCastle;
49 CastleMask[A8] &= ~FlagsBlackQueenCastle;
50 }
51
52 // move_do()
53
move_do(board_t * board,int move,undo_t * undo)54 void move_do(board_t * board, int move, undo_t * undo) {
55
56 int me, opp;
57 int from, to;
58 int piece, pos, capture;
59 int old_flags, new_flags;
60 int delta;
61 int sq;
62 int pawn, rook;
63
64 ASSERT(board!=NULL);
65 ASSERT(move_is_ok(move));
66 ASSERT(undo!=NULL);
67
68 ASSERT(board_is_legal(board));
69
70 // initialise undo
71
72 undo->capture = false;
73
74 undo->turn = board->turn;
75 undo->flags = board->flags;
76 undo->ep_square = board->ep_square;
77 undo->ply_nb = board->ply_nb;
78
79 undo->cap_sq = board->cap_sq;
80
81 undo->opening = board->opening;
82 undo->endgame = board->endgame;
83
84 undo->key = board->key;
85 undo->pawn_key = board->pawn_key;
86 undo->material_key = board->material_key;
87
88 // init
89
90 me = board->turn;
91 opp = COLOUR_OPP(me);
92
93 from = MOVE_FROM(move);
94 to = MOVE_TO(move);
95
96 piece = board->square[from];
97 ASSERT(COLOUR_IS(piece,me));
98
99 // update key stack
100
101 ASSERT(board->sp<StackSize);
102 board->stack[board->sp++] = board->key;
103
104 // update turn
105
106 board->turn = opp;
107 board->key ^= RANDOM_64(RandomTurn);
108
109 // update castling rights
110
111 old_flags = board->flags;
112 new_flags = old_flags & CastleMask[from] & CastleMask[to];
113
114 board->flags = new_flags;
115 board->key ^= Castle64[new_flags^old_flags]; // HACK
116
117 // update en-passant square
118
119 if ((sq=board->ep_square) != SquareNone) {
120 board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA);
121 board->ep_square = SquareNone;
122 }
123
124 if (PIECE_IS_PAWN(piece)) {
125
126 delta = to - from;
127
128 if (delta == +32 || delta == -32) {
129 pawn = PAWN_MAKE(opp);
130 if (board->square[to-1] == pawn || board->square[to+1] == pawn) {
131 board->ep_square = (from + to) / 2;
132 board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(to)-FileA);
133 }
134 }
135 }
136
137 // update move number (captures are handled later)
138
139 board->ply_nb++;
140 if (PIECE_IS_PAWN(piece)) board->ply_nb = 0; // conversion
141
142 // update last square
143
144 board->cap_sq = SquareNone;
145
146 // remove the captured piece
147
148 sq = to;
149 if (MOVE_IS_EN_PASSANT(move)) sq = SQUARE_EP_DUAL(sq);
150
151 if ((capture=board->square[sq]) != Empty) {
152
153 ASSERT(COLOUR_IS(capture,opp));
154 ASSERT(!PIECE_IS_KING(capture));
155
156 undo->capture = true;
157 undo->capture_square = sq;
158 undo->capture_piece = capture;
159 undo->capture_pos = board->pos[sq];
160
161 square_clear(board,sq,capture,true);
162
163 board->ply_nb = 0; // conversion
164 board->cap_sq = to;
165 }
166
167 // move the piece
168
169 if (MOVE_IS_PROMOTE(move)) {
170
171 // promote
172
173 undo->pawn_pos = board->pos[from];
174
175 square_clear(board,from,piece,true);
176
177 piece = move_promote(move);
178
179 // insert the promote piece in MV order
180
181 for (pos = board->piece_size[me]; pos > 0 && piece > board->square[board->piece[me][pos-1]]; pos--) // HACK
182 ;
183
184 square_set(board,to,piece,pos,true);
185
186 board->cap_sq = to;
187
188 } else {
189
190 // normal move
191
192 square_move(board,from,to,piece,true);
193 }
194
195 // move the rook in case of castling
196
197 if (MOVE_IS_CASTLE(move)) {
198
199 rook = Rook64 | COLOUR_FLAG(me); // HACK
200
201 if (to == G1) {
202 square_move(board,H1,F1,rook,true);
203 } else if (to == C1) {
204 square_move(board,A1,D1,rook,true);
205 } else if (to == G8) {
206 square_move(board,H8,F8,rook,true);
207 } else if (to == C8) {
208 square_move(board,A8,D8,rook,true);
209 } else {
210 ASSERT(false);
211 }
212 }
213
214 // debug
215
216 ASSERT(board_is_ok(board));
217 }
218
219 // move_undo()
220
move_undo(board_t * board,int move,const undo_t * undo)221 void move_undo(board_t * board, int move, const undo_t * undo) {
222
223 int me;
224 int from, to;
225 int piece, pos;
226 int rook;
227
228 ASSERT(board!=NULL);
229 ASSERT(move_is_ok(move));
230 ASSERT(undo!=NULL);
231
232 // init
233
234 me = undo->turn;
235
236 from = MOVE_FROM(move);
237 to = MOVE_TO(move);
238
239 piece = board->square[to];
240 ASSERT(COLOUR_IS(piece,me));
241
242 // castle
243
244 if (MOVE_IS_CASTLE(move)) {
245
246 rook = Rook64 | COLOUR_FLAG(me); // HACK
247
248 if (to == G1) {
249 square_move(board,F1,H1,rook,false);
250 } else if (to == C1) {
251 square_move(board,D1,A1,rook,false);
252 } else if (to == G8) {
253 square_move(board,F8,H8,rook,false);
254 } else if (to == C8) {
255 square_move(board,D8,A8,rook,false);
256 } else {
257 ASSERT(false);
258 }
259 }
260
261 // move the piece backward
262
263 if (MOVE_IS_PROMOTE(move)) {
264
265 // promote
266
267 ASSERT(piece==move_promote(move));
268 square_clear(board,to,piece,false);
269
270 piece = PAWN_MAKE(me);
271 pos = undo->pawn_pos;
272
273 square_set(board,from,piece,pos,false);
274
275 } else {
276
277 // normal move
278
279 square_move(board,to,from,piece,false);
280 }
281
282 // put the captured piece back
283
284 if (undo->capture) {
285 square_set(board,undo->capture_square,undo->capture_piece,undo->capture_pos,false);
286 }
287
288 // update board info
289
290 board->turn = undo->turn;
291 board->flags = undo->flags;
292 board->ep_square = undo->ep_square;
293 board->ply_nb = undo->ply_nb;
294
295 board->cap_sq = undo->cap_sq;
296
297 board->opening = undo->opening;
298 board->endgame = undo->endgame;
299
300 board->key = undo->key;
301 board->pawn_key = undo->pawn_key;
302 board->material_key = undo->material_key;
303
304 // update key stack
305
306 ASSERT(board->sp>0);
307 board->sp--;
308
309 // debug
310
311 ASSERT(board_is_ok(board));
312 ASSERT(board_is_legal(board));
313 }
314
315 // move_do_null()
316
move_do_null(board_t * board,undo_t * undo)317 void move_do_null(board_t * board, undo_t * undo) {
318
319 int sq;
320
321 ASSERT(board!=NULL);
322 ASSERT(undo!=NULL);
323
324 ASSERT(board_is_legal(board));
325 ASSERT(!board_is_check(board));
326
327 // initialise undo
328
329 undo->turn = board->turn;
330 undo->ep_square = board->ep_square;
331 undo->ply_nb = board->ply_nb;
332 undo->cap_sq = board->cap_sq;
333 undo->key = board->key;
334
335 // update key stack
336
337 ASSERT(board->sp<StackSize);
338 board->stack[board->sp++] = board->key;
339
340 // update turn
341
342 board->turn = COLOUR_OPP(board->turn);
343 board->key ^= RANDOM_64(RandomTurn);
344
345 // update en-passant square
346
347 sq = board->ep_square;
348 if (sq != SquareNone) {
349 board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA);
350 board->ep_square = SquareNone;
351 }
352
353 // update move number
354
355 board->ply_nb = 0; // HACK: null move is considered as a conversion
356
357 // update last square
358
359 board->cap_sq = SquareNone;
360
361 // debug
362
363 ASSERT(board_is_ok(board));
364 }
365
366 // move_undo_null()
367
move_undo_null(board_t * board,const undo_t * undo)368 void move_undo_null(board_t * board, const undo_t * undo) {
369
370 ASSERT(board!=NULL);
371 ASSERT(undo!=NULL);
372
373 ASSERT(board_is_legal(board));
374 ASSERT(!board_is_check(board));
375
376 // update board info
377
378 board->turn = undo->turn;
379 board->ep_square = undo->ep_square;
380 board->ply_nb = undo->ply_nb;
381 board->cap_sq = undo->cap_sq;
382 board->key = undo->key;
383
384 // update key stack
385
386 ASSERT(board->sp>0);
387 board->sp--;
388
389 // debug
390
391 ASSERT(board_is_ok(board));
392 }
393
394 // square_clear()
395
square_clear(board_t * board,int square,int piece,bool update)396 static void square_clear(board_t * board, int square, int piece, bool update) {
397
398 int pos, piece_12, colour;
399 int sq;
400 int i, size;
401 int sq_64;
402 uint64 hash_xor;
403
404 ASSERT(board!=NULL);
405 ASSERT(SQUARE_IS_OK(square));
406 ASSERT(piece_is_ok(piece));
407 ASSERT(update==true||update==false);
408
409 // init
410
411 pos = board->pos[square];
412 ASSERT(pos>=0);
413
414 piece_12 = PIECE_TO_12(piece);
415 colour = PIECE_COLOUR(piece);
416
417 // square
418
419 ASSERT(board->square[square]==piece);
420 board->square[square] = Empty;
421
422 // piece list
423
424 if (!PIECE_IS_PAWN(piece)) {
425
426 // init
427
428 size = board->piece_size[colour];
429 ASSERT(size>=1);
430
431 // stable swap
432
433 ASSERT(pos>=0&&pos<size);
434
435 ASSERT(board->pos[square]==pos);
436 board->pos[square] = -1;
437
438 for (i = pos; i < size-1; i++) {
439
440 sq = board->piece[colour][i+1];
441
442 board->piece[colour][i] = sq;
443
444 ASSERT(board->pos[sq]==i+1);
445 board->pos[sq] = i;
446 }
447
448 // size
449
450 size--;
451
452 board->piece[colour][size] = SquareNone;
453 board->piece_size[colour] = size;
454
455 } else {
456
457 // init
458
459 size = board->pawn_size[colour];
460 ASSERT(size>=1);
461
462 // stable swap
463
464 ASSERT(pos>=0&&pos<size);
465
466 ASSERT(board->pos[square]==pos);
467 board->pos[square] = -1;
468
469 for (i = pos; i < size-1; i++) {
470
471 sq = board->pawn[colour][i+1];
472
473 board->pawn[colour][i] = sq;
474
475 ASSERT(board->pos[sq]==i+1);
476 board->pos[sq] = i;
477 }
478
479 // size
480
481 size--;
482
483 board->pawn[colour][size] = SquareNone;
484 board->pawn_size[colour] = size;
485
486 // pawn "bitboard"
487
488 board->pawn_file[colour][SQUARE_FILE(square)] ^= BIT(PAWN_RANK(square,colour));
489 }
490
491 // material
492
493 ASSERT(board->piece_nb>0);
494 board->piece_nb--;
495
496 ASSERT(board->number[piece_12]>0);
497 board->number[piece_12]--;
498
499 board->piece_material[colour] -= VALUE_PIECE(piece); // Thomas
500
501 // update
502
503 if (update) {
504
505 // init
506
507 sq_64 = SQUARE_TO_64(square);
508
509 // PST
510
511 board->opening -= PST(piece_12,sq_64,Opening);
512 board->endgame -= PST(piece_12,sq_64,Endgame);
513
514 // hash key
515
516 hash_xor = RANDOM_64(RandomPiece+(piece_12^1)*64+sq_64); // HACK: ^1 for PolyGlot book
517
518 board->key ^= hash_xor;
519 if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor;
520
521 // material key
522
523 board->material_key ^= RANDOM_64(piece_12*16+board->number[piece_12]);
524 }
525 }
526
527 // square_set()
528
square_set(board_t * board,int square,int piece,int pos,bool update)529 static void square_set(board_t * board, int square, int piece, int pos, bool update) {
530
531 int piece_12, colour;
532 int sq;
533 int i, size;
534 int sq_64;
535 uint64 hash_xor;
536
537 ASSERT(board!=NULL);
538 ASSERT(SQUARE_IS_OK(square));
539 ASSERT(piece_is_ok(piece));
540 ASSERT(pos>=0);
541 ASSERT(update==true||update==false);
542
543 // init
544
545 piece_12 = PIECE_TO_12(piece);
546 colour = PIECE_COLOUR(piece);
547
548 // square
549
550 ASSERT(board->square[square]==Empty);
551 board->square[square] = piece;
552
553 // piece list
554
555 if (!PIECE_IS_PAWN(piece)) {
556
557 // init
558
559 size = board->piece_size[colour];
560 ASSERT(size>=0);
561
562 // size
563
564 size++;
565
566 board->piece[colour][size] = SquareNone;
567 board->piece_size[colour] = size;
568
569 // stable swap
570
571 ASSERT(pos>=0&&pos<size);
572
573 for (i = size-1; i > pos; i--) {
574
575 sq = board->piece[colour][i-1];
576
577 board->piece[colour][i] = sq;
578
579 ASSERT(board->pos[sq]==i-1);
580 board->pos[sq] = i;
581 }
582
583 board->piece[colour][pos] = square;
584
585 ASSERT(board->pos[square]==-1);
586 board->pos[square] = pos;
587
588 } else {
589
590 // init
591
592 size = board->pawn_size[colour];
593 ASSERT(size>=0);
594
595 // size
596
597 size++;
598
599 board->pawn[colour][size] = SquareNone;
600 board->pawn_size[colour] = size;
601
602 // stable swap
603
604 ASSERT(pos>=0&&pos<size);
605
606 for (i = size-1; i > pos; i--) {
607
608 sq = board->pawn[colour][i-1];
609
610 board->pawn[colour][i] = sq;
611
612 ASSERT(board->pos[sq]==i-1);
613 board->pos[sq] = i;
614 }
615
616 board->pawn[colour][pos] = square;
617
618 ASSERT(board->pos[square]==-1);
619 board->pos[square] = pos;
620
621 // pawn "bitboard"
622
623 board->pawn_file[colour][SQUARE_FILE(square)] ^= BIT(PAWN_RANK(square,colour));
624 }
625
626 // material
627
628 ASSERT(board->piece_nb<32);
629 board->piece_nb++;;
630
631 ASSERT(board->number[piece_12]<9);
632 board->number[piece_12]++;
633
634 board->piece_material[colour] += VALUE_PIECE(piece); // Thomas
635
636 // update
637
638 if (update) {
639
640 // init
641
642 sq_64 = SQUARE_TO_64(square);
643
644 // PST
645
646 board->opening += PST(piece_12,sq_64,Opening);
647 board->endgame += PST(piece_12,sq_64,Endgame);
648
649 // hash key
650
651 hash_xor = RANDOM_64(RandomPiece+(piece_12^1)*64+sq_64); // HACK: ^1 for PolyGlot book
652
653 board->key ^= hash_xor;
654 if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor;
655
656 // material key
657
658 board->material_key ^= RANDOM_64(piece_12*16+(board->number[piece_12]-1));
659 }
660 }
661
662 // square_move()
663
square_move(board_t * board,int from,int to,int piece,bool update)664 static void square_move(board_t * board, int from, int to, int piece, bool update) {
665
666 int colour;
667 int pos;
668 int from_64, to_64;
669 int piece_12;
670 int piece_index;
671 uint64 hash_xor;
672
673 ASSERT(board!=NULL);
674 ASSERT(SQUARE_IS_OK(from));
675 ASSERT(SQUARE_IS_OK(to));
676 ASSERT(piece_is_ok(piece));
677 ASSERT(update==true||update==false);
678
679 // init
680
681 colour = PIECE_COLOUR(piece);
682
683 pos = board->pos[from];
684 ASSERT(pos>=0);
685
686 // from
687
688 ASSERT(board->square[from]==piece);
689 board->square[from] = Empty;
690
691 ASSERT(board->pos[from]==pos);
692 board->pos[from] = -1; // not needed
693
694 // to
695
696 ASSERT(board->square[to]==Empty);
697 board->square[to] = piece;
698
699 ASSERT(board->pos[to]==-1);
700 board->pos[to] = pos;
701
702 // piece list
703
704 if (!PIECE_IS_PAWN(piece)) {
705
706 ASSERT(board->piece[colour][pos]==from);
707 board->piece[colour][pos] = to;
708
709 } else {
710
711 ASSERT(board->pawn[colour][pos]==from);
712 board->pawn[colour][pos] = to;
713
714 // pawn "bitboard"
715
716 board->pawn_file[colour][SQUARE_FILE(from)] ^= BIT(PAWN_RANK(from,colour));
717 board->pawn_file[colour][SQUARE_FILE(to)] ^= BIT(PAWN_RANK(to,colour));
718 }
719
720 // update
721
722 if (update) {
723
724 // init
725
726 from_64 = SQUARE_TO_64(from);
727 to_64 = SQUARE_TO_64(to);
728 piece_12 = PIECE_TO_12(piece);
729
730 // PST
731
732 board->opening += PST(piece_12,to_64,Opening) - PST(piece_12,from_64,Opening);
733 board->endgame += PST(piece_12,to_64,Endgame) - PST(piece_12,from_64,Endgame);
734
735 // hash key
736
737 piece_index = RandomPiece + (piece_12^1) * 64; // HACK: ^1 for PolyGlot book
738
739 hash_xor = RANDOM_64(piece_index+to_64) ^ RANDOM_64(piece_index+from_64);
740
741 board->key ^= hash_xor;
742 if (PIECE_IS_PAWN(piece)) board->pawn_key ^= hash_xor;
743 }
744 }
745
746 // end of move_do.cpp
747
748