99#include < cstring>
1010
1111#include " board.h"
12- #include " testing/catch.hpp"
1312#include " move.h"
1413#include " hash.h"
1514
1615void board_t::move (move_t move) {
17- // Copy the record
18- memcpy (&record[now + 1 ], &record[now], sizeof (game_record_t ));
19- now += 1 ;
20- record[now].prev_move = move;
16+ // Insert a new record
17+ record.push_back (record.back ());
18+ record.back ().prev_move = move;
2119
2220 // Update side hash
23- record[now]. next_move = (Team) !record[now] .next_move ;
24- record[now] .hash ^= zobrist::side;
21+ record. back (). next_move = (Team) !record. back () .next_move ;
22+ record. back () .hash ^= zobrist::side;
2523
2624 // Update ep hash
27- if (record[now - 1 ].ep_square != 0 ) {
28- record[now] .ep_square = 0 ;
29- record[now]. hash ^= zobrist::ep[record[now - 1 ].ep_square ];
25+ if (record. crbegin ()[ 1 ].ep_square != 0 ) {
26+ record. back () .ep_square = 0 ;
27+ record. back (). hash ^= zobrist::ep[record. crbegin ()[ 1 ].ep_square ];
3028 }
3129
3230 if (move != EMPTY_MOVE) {
@@ -35,18 +33,18 @@ void board_t::move(move_t move) {
3533
3634 // Update halfmove clock
3735 if (move.info .piece == PAWN || move.info .is_capture ) {
38- record[now] .halfmove_clock = 0 ;
36+ record. back () .halfmove_clock = 0 ;
3937 } else {
40- record[now] .halfmove_clock ++;
38+ record. back () .halfmove_clock ++;
4139 }
4240
4341 if (move.info .is_capture && move.info .captured_type == ROOK) {
44- if (move.info .to == (x_team ? H8 : H1) && record[now] .castle [x_team][0 ]) {
45- record[now] .castle [x_team][0 ] = false ;
46- record[now] .hash ^= zobrist::castle[x_team][0 ];
47- } else if (move.info .to == (x_team ? A8 : A1) && record[now] .castle [x_team][1 ]) {
48- record[now] .castle [x_team][1 ] = false ;
49- record[now] .hash ^= zobrist::castle[x_team][1 ];
42+ if (move.info .to == (x_team ? H8 : H1) && record. back () .castle [x_team][0 ]) {
43+ record. back () .castle [x_team][0 ] = false ;
44+ record. back () .hash ^= zobrist::castle[x_team][0 ];
45+ } else if (move.info .to == (x_team ? A8 : A1) && record. back () .castle [x_team][1 ]) {
46+ record. back () .castle [x_team][1 ] = false ;
47+ record. back () .hash ^= zobrist::castle[x_team][1 ];
5048 }
5149 }
5250
@@ -68,38 +66,38 @@ void board_t::move(move_t move) {
6866
6967 // Update en-passant square
7068 if (team ? move.info .to - move.info .from == -16 : move.info .to - move.info .from == 16 ) {
71- record[now] .ep_square = team ? move.info .to + uint8_t (8 ) : move.info .to - uint8_t (8 );
72- record[now]. hash ^= zobrist::ep[record[now] .ep_square ];
69+ record. back () .ep_square = team ? move.info .to + uint8_t (8 ) : move.info .to - uint8_t (8 );
70+ record. back (). hash ^= zobrist::ep[record. back () .ep_square ];
7371 }
7472 } else {
7573 // Update castling hashes for moving rook
7674 if (move.info .piece == ROOK) {
7775 if (team) {
78- if (move.info .from == H8 && record[now] .castle [team][0 ]) {
79- record[now] .hash ^= zobrist::castle[team][0 ];
80- record[now] .castle [team][0 ] = false ;
81- } else if (move.info .from == A8 && record[now] .castle [team][1 ]) {
82- record[now] .hash ^= zobrist::castle[team][1 ];
83- record[now] .castle [team][1 ] = false ;
76+ if (move.info .from == H8 && record. back () .castle [team][0 ]) {
77+ record. back () .hash ^= zobrist::castle[team][0 ];
78+ record. back () .castle [team][0 ] = false ;
79+ } else if (move.info .from == A8 && record. back () .castle [team][1 ]) {
80+ record. back () .hash ^= zobrist::castle[team][1 ];
81+ record. back () .castle [team][1 ] = false ;
8482 }
8583 } else {
86- if (move.info .from == H1 && record[now] .castle [team][0 ]) {
87- record[now] .hash ^= zobrist::castle[team][0 ];
88- record[now] .castle [team][0 ] = false ;
89- } else if (move.info .from == A1 && record[now] .castle [team][1 ]) {
90- record[now] .hash ^= zobrist::castle[team][1 ];
91- record[now] .castle [team][1 ] = false ;
84+ if (move.info .from == H1 && record. back () .castle [team][0 ]) {
85+ record. back () .hash ^= zobrist::castle[team][0 ];
86+ record. back () .castle [team][0 ] = false ;
87+ } else if (move.info .from == A1 && record. back () .castle [team][1 ]) {
88+ record. back () .hash ^= zobrist::castle[team][1 ];
89+ record. back () .castle [team][1 ] = false ;
9290 }
9391 }
9492 } else if (move.info .piece == KING) {
9593 // Update castling hashes
96- if (record[now] .castle [team][0 ]) {
97- record[now] .hash ^= zobrist::castle[team][0 ];
98- record[now] .castle [team][0 ] = false ;
94+ if (record. back () .castle [team][0 ]) {
95+ record. back () .hash ^= zobrist::castle[team][0 ];
96+ record. back () .castle [team][0 ] = false ;
9997 }
100- if (record[now] .castle [team][1 ]) {
101- record[now] .hash ^= zobrist::castle[team][1 ];
102- record[now] .castle [team][1 ] = false ;
98+ if (record. back () .castle [team][1 ]) {
99+ record. back () .hash ^= zobrist::castle[team][1 ];
100+ record. back () .castle [team][1 ] = false ;
103101 }
104102
105103 if (move.info .castle ) {
@@ -121,8 +119,8 @@ void board_t::move(move_t move) {
121119}
122120
123121void board_t::unmove () {
124- move_t move = record[now] .prev_move ;
125- now -= 1 ;
122+ move_t move = record. back () .prev_move ;
123+ record. pop_back () ;
126124
127125 if (move != EMPTY_MOVE) {
128126 if (move.info .piece == PAWN) {
@@ -169,6 +167,8 @@ board_t::board_t(const std::string &fen) {
169167 std::string (" FEN: " ) + std::to_string (split.size ()) + std::string (" components, 4-6 expected" ));
170168 }
171169
170+ record.emplace_back ();
171+
172172 // Parse board
173173 uint8_t file = 0 , rank = 7 ;
174174 for (char ch : split[0 ]) {
@@ -348,23 +348,23 @@ move_t board_t::to_move(packed_move_t packed_move) const {
348348 }
349349
350350 // EP
351- move.info .is_capture |= move.info .is_ep = static_cast <uint16_t >(record[now] .ep_square != 0
351+ move.info .is_capture |= move.info .is_ep = static_cast <uint16_t >(record. back () .ep_square != 0
352352 && move.info .piece == PAWN
353- && move.info .to == record[now] .ep_square );
353+ && move.info .to == record. back () .ep_square );
354354
355355 return move;
356356}
357357
358358bool board_t::is_illegal () const {
359- Team side = record[now] .next_move ;
359+ Team side = record. back () .next_move ;
360360 uint8_t king_square = bit_scan (bb_pieces[!side][KING]);
361361
362362 return is_attacked (king_square, side);
363363}
364364
365365
366366bool board_t::is_incheck () const {
367- Team side = record[now] .next_move ;
367+ Team side = record. back () .next_move ;
368368 uint8_t king_square = bit_scan (bb_pieces[side][KING]);
369369
370370 return is_attacked (king_square, Team (!side));
@@ -388,10 +388,10 @@ void board_t::switch_piece(Team side, Piece piece, uint8_t sq) {
388388
389389 if (HASH) { // Update hash
390390 U64 square_hash = zobrist::squares[sq][side][piece];
391- record[now] .hash ^= square_hash;
392- if (piece == PAWN || piece == KING) record[now] .kp_hash ^= square_hash;
393- if (sq_data[sq].occupied ) record[now] .material .info .inc (side, piece);
394- else record[now] .material .info .dec (side, piece);
391+ record. back () .hash ^= square_hash;
392+ if (piece == PAWN || piece == KING) record. back () .kp_hash ^= square_hash;
393+ if (sq_data[sq].occupied ) record. back () .material .info .inc (side, piece);
394+ else record. back () .material .info .dec (side, piece);
395395 }
396396}
397397
@@ -430,10 +430,10 @@ bool board_t::is_pseudo_legal(move_t move) const {
430430 auto team = Team (move.info .team );
431431 auto x_team = Team (!move.info .team );
432432
433- if (record[now] .next_move != team) return false ;
433+ if (record. back () .next_move != team) return false ;
434434
435435 if (move.info .castle ) {
436- if (record[now] .castle [move.info .team ][move.info .castle_side ] == 0 ) return false ;
436+ if (record. back () .castle [move.info .team ][move.info .castle_side ] == 0 ) return false ;
437437 if (move.info .castle_side == 0 ) {
438438 return (bb_all & bits_between (team ? E8 : E1 , team ? H8 : H1)) == 0 &&
439439 !is_attacked (team ? E8 : E1 , x_team) &&
@@ -454,7 +454,7 @@ bool board_t::is_pseudo_legal(move_t move) const {
454454 }
455455
456456 if (move.info .is_ep ) {
457- if (record[now]. ep_square == 0 || move.info .to != record[now] .ep_square ) {
457+ if (record. back (). ep_square == 0 || move.info .to != record. back () .ep_square ) {
458458 return false ;
459459 }
460460 } else {
@@ -559,10 +559,10 @@ bool board_t::gives_check(move_t move) const {
559559bool board_t::is_repetition_draw (int search_ply) const {
560560 int rep = 1 ;
561561
562- int max = record[now] .halfmove_clock ;
562+ int max = record. back () .halfmove_clock ;
563563
564564 for (int i = 2 ; i <= max; i += 2 ) {
565- if (record[now - i].hash == record[now] .hash ) rep++;
565+ if (record. crbegin ()[ i].hash == record. back () .hash ) rep++;
566566 if (rep >= 3 ) return true ;
567567 if (rep >= 2 && i < search_ply) return true ;
568568 }
@@ -571,38 +571,38 @@ bool board_t::is_repetition_draw(int search_ply) const {
571571}
572572
573573bool board_t::is_material_draw () const {
574- if (record[now]. material .info .w_pawns || record[now] .material .info .b_pawns ||
575- record[now]. material .info .w_queens || record[now] .material .info .b_queens ||
576- record[now]. material .info .w_rooks || record[now] .material .info .b_rooks ) {
574+ if (record. back (). material .info .w_pawns || record. back () .material .info .b_pawns ||
575+ record. back (). material .info .w_queens || record. back () .material .info .b_queens ||
576+ record. back (). material .info .w_rooks || record. back () .material .info .b_rooks ) {
577577 return false ;
578578 } else {
579- return record[now]. material .info .w_bishops + record[now] .material .info .b_bishops
580- + record[now]. material .info .w_knights + record[now] .material .info .b_knights <= 1 ;
579+ return record. back (). material .info .w_bishops + record. back () .material .info .b_bishops
580+ + record. back (). material .info .w_knights + record. back () .material .info .b_knights <= 1 ;
581581 }
582582}
583583
584584void board_t::mirror () {
585585 // Mirror side
586- record[now]. next_move = (Team) !record[now] .next_move ;
587- record[now] .hash ^= zobrist::side;
586+ record. back (). next_move = (Team) !record. back () .next_move ;
587+ record. back () .hash ^= zobrist::side;
588588
589589 // Mirror en-passant
590- if (record[now] .ep_square != 0 ) {
591- record[now]. hash ^= zobrist::ep[record[now] .ep_square ];
592- record[now]. ep_square = MIRROR_TABLE[record[now] .ep_square ];
593- record[now]. hash ^= zobrist::ep[record[now] .ep_square ];
590+ if (record. back () .ep_square != 0 ) {
591+ record. back (). hash ^= zobrist::ep[record. back () .ep_square ];
592+ record. back (). ep_square = MIRROR_TABLE[record. back () .ep_square ];
593+ record. back (). hash ^= zobrist::ep[record. back () .ep_square ];
594594 }
595595
596596 // Mirror castling rights
597- if (record[now]. castle [0 ][0 ] != record[now] .castle [1 ][0 ]) {
598- record[now] .hash ^= zobrist::castle[0 ][0 ];
599- record[now] .hash ^= zobrist::castle[1 ][0 ];
600- std::swap (record[now]. castle [0 ][0 ], record[now] .castle [1 ][0 ]);
597+ if (record. back (). castle [0 ][0 ] != record. back () .castle [1 ][0 ]) {
598+ record. back () .hash ^= zobrist::castle[0 ][0 ];
599+ record. back () .hash ^= zobrist::castle[1 ][0 ];
600+ std::swap (record. back (). castle [0 ][0 ], record. back () .castle [1 ][0 ]);
601601 }
602- if (record[now]. castle [0 ][1 ] != record[now] .castle [1 ][1 ]) {
603- record[now] .hash ^= zobrist::castle[0 ][1 ];
604- record[now] .hash ^= zobrist::castle[1 ][1 ];
605- std::swap (record[now]. castle [0 ][1 ], record[now] .castle [1 ][1 ]);
602+ if (record. back (). castle [0 ][1 ] != record. back () .castle [1 ][1 ]) {
603+ record. back () .hash ^= zobrist::castle[0 ][1 ];
604+ record. back () .hash ^= zobrist::castle[1 ][1 ];
605+ std::swap (record. back (). castle [0 ][1 ], record. back () .castle [1 ][1 ]);
606606 }
607607
608608 // Mirror pieces
@@ -710,3 +710,7 @@ int board_t::see(move_t move) const {
710710U64 board_t::non_pawn_material (Team side) const {
711711 return (bb_side[side] ^ bb_pieces[side][PAWN] ^ bb_pieces[side][KING]);
712712}
713+
714+ void board_t::print () {
715+ std::cout << *this ;
716+ }
0 commit comments