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