Merge branch 'release-2.1.0'
[purplehaze.git] / test / unit / test_transpositions.cpp
blob4ea0181a1d549d7abe81d4240ff6d0978fc2245c
1 #include <climits>
3 #include "../../src/tt.h"
4 #include "../../src/game.h"
5 #include "gtest/gtest.h"
7 static const Bound BOUNDS[] = { EXACT, LOWER, UPPER };
9 TEST(TranspositionTest, Size)
11 int size = sizeof(int16_t) + // 2 bytes
12 sizeof(Move) + // 2 bytes
13 sizeof(unsigned char) + // 1 byte
14 sizeof(Bound); // 1 byte
15 EXPECT_EQ(6, size);
16 EXPECT_EQ(size, sizeof(Transposition));
19 TEST(TranspositionTest, Constructor)
21 Transposition t1;
22 EXPECT_TRUE(t1.is_empty());
23 EXPECT_EQ(0, t1.value());
24 EXPECT_EQ(0, t1.depth());
25 EXPECT_EQ(Move(), t1.best_move());
26 EXPECT_EQ(UNDEF_BOUND, t1.bound());
28 for (int v = SHRT_MIN; v <= SHRT_MAX; v += 1000) {
29 for (int d = 0; d <= UCHAR_MAX; ++d) {
30 for (const Bound &b : BOUNDS) {
31 Move m(E2, E3, QUIET_MOVE);
32 Transposition t2(v, b, d, m);
33 EXPECT_FALSE(t2.is_empty());
34 EXPECT_EQ(v, t2.value());
35 EXPECT_EQ(d, t2.depth());
36 EXPECT_EQ(m, t2.best_move());
37 EXPECT_EQ(b, t2.bound());
39 Transposition t3(v, b, d, m);
40 Transposition t4(v + 1, b, d, m);
41 Transposition t5(v, UNDEF_BOUND, d, m);
42 Transposition t6(v, b, d + 1, m);
43 Transposition t7(v, b, d, Move(F2, F3, QUIET_MOVE));
45 EXPECT_EQ(t3, t2);
46 EXPECT_NE(t4, t2);
47 EXPECT_NE(t5, t2);
48 EXPECT_NE(t6, t2);
49 EXPECT_NE(t7, t2);
55 class TranspositionsTest : public testing::Test
57 protected:
58 Transpositions tt;
60 Hash hash_from_index(int i) const {
61 return static_cast<Hash>(i & (tt.size() - 1));
65 TEST_F(TranspositionsTest, Size)
67 HashTable<Transposition> ht(TT_SIZE);
68 EXPECT_EQ(sizeof(ht), sizeof(tt));
69 int entry_size = sizeof(Hash) + // 8 bytes
70 sizeof(Transposition) + // 6 bytes
71 2; // 2 bytes (padding)
72 int size = TT_SIZE / entry_size;
74 // TODO Internal array size should not be a power of two?
75 //EXPECT_NE(0, TT_SIZE & (TT_SIZE - 1));
77 // 'size' must be a power of two for Transpositions::lookup()
78 EXPECT_EQ(0, size & (size - 1));
80 EXPECT_EQ(size, tt.size());
83 TEST_F(TranspositionsTest, Constructor)
85 tt.clear();
86 int n = tt.size();
87 for (int i = 0; i < n; ++i) {
88 EXPECT_TRUE(tt.value_at(i).is_empty());
89 EXPECT_EQ(0, tt.hash_at(i));
93 TEST_F(TranspositionsTest, ConstructorWithoutClear)
95 int n = tt.size();
96 for (int i = 0; i < n; ++i) {
97 EXPECT_TRUE(tt.value_at(i).is_empty());
98 EXPECT_EQ(0, tt.hash_at(i));
102 TEST_F(TranspositionsTest, Lookup)
104 tt.clear();
105 int n = tt.size();
106 for (int i = 0; i < n; ++i) {
107 Hash h = hash_from_index(i);
108 bool is_empty;
109 Transposition trans = tt.lookup(h, &is_empty);
110 if (i == 0) {
111 // FIXME
112 EXPECT_FALSE(is_empty);
113 EXPECT_EQ(UNDEF_BOUND, trans.bound());
114 } else {
115 EXPECT_TRUE(is_empty);
118 for (int i = -1; i < n; ++i) {
119 for (int s = SHRT_MIN; s <= SHRT_MAX; s += 1000) {
120 for (int d = 0; d <= UCHAR_MAX; ++d) {
121 for (const Bound &b : BOUNDS) {
122 if (++i >= n) break;
123 // Create transposition
124 Move m(E2, E4, QUIET_MOVE);
125 int v = s + i;
126 Hash h = hash_from_index(i);
127 Transposition trans_sent(v, b, d, m);
129 // Save transposition
130 tt.save(h, v, b, d, m);
132 // Check transposition
133 EXPECT_FALSE(tt.value_at(i).is_empty());
134 EXPECT_EQ(trans_sent, tt.value_at(i));
135 EXPECT_EQ(h, tt.hash_at(i));
140 for (int i = -1; i < n; ++i) {
141 for (int s = SHRT_MIN; s <= SHRT_MAX; s += 1000) {
142 for (int d = 0; d <= UCHAR_MAX; ++d) {
143 for (const Bound &b : BOUNDS) {
144 if (++i >= n) break;
145 // Create transposition
146 Move m(E2, E4, QUIET_MOVE);
147 int v = s + i;
148 Hash h = hash_from_index(i);
149 Transposition trans_sent(v, b, d, m);
151 // Lookup transposition
152 bool is_empty;
153 Transposition trans_received = tt.lookup(h, &is_empty);
154 EXPECT_FALSE(is_empty);
155 EXPECT_EQ(trans_sent, trans_received);
163 * Test case for retrieving the best move from TT after a search
165 TEST(TTTest, LookupAfterSearch)
167 Game game;
168 game.tt.clear();
169 game.clear_killers();
170 game.search_moves.clear();
172 game.init("7K/8/k1P5/7p/8/8/8/8 w - -");
173 game.time = Time(1, 200); // Search 1 move in 200 ms
174 Move m1 = game.root(MAX_PLY);
175 EXPECT_NE("c7", game.output_move(m1)); // BM at depth <= 3
176 EXPECT_NE("Kh7", game.output_move(m1)); // BM at depth <= 13
177 EXPECT_EQ("Kg7", game.output_move(m1)); // BM at depth >= 13
179 bool is_empty;
180 Position &pos = game.current_position();
181 Move m2 = game.tt.lookup(pos.hash(), &is_empty).best_move();
182 EXPECT_EQ(m1, m2);