+ Move get(Key key) const {
+ return expectedPosKey == key ? pv[2] : MOVE_NONE;
+ }
+
+ void update(Position& pos, const std::vector<Move>& newPv) {
+
+ assert(newPv.size() >= 3);
+
+ // Keep track of how many times in a row the 3rd ply remains stable
+ stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
+
+ if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
+ {
+ std::copy(newPv.begin(), newPv.begin() + 3, pv);
+
+ StateInfo st[2];
+ pos.do_move(newPv[0], st[0], pos.gives_check(newPv[0]));
+ pos.do_move(newPv[1], st[1], pos.gives_check(newPv[1]));
+ expectedPosKey = pos.key();
+ pos.undo_move(newPv[1]);
+ pos.undo_move(newPv[0]);
+ }
+ }
+
+ int stableCnt;
+ Key expectedPosKey;
+ Move pv[3];
+ };
+
+ // Set of rows with half bits set to 1 and half to 0. It is used to allocate
+ // the search depths across the threads.
+ typedef std::vector<int> Row;
+
+ const Row HalfDensity[] = {
+ {0, 1},
+ {1, 0},
+ {0, 0, 1, 1},
+ {0, 1, 1, 0},
+ {1, 1, 0, 0},
+ {1, 0, 0, 1},
+ {0, 0, 0, 1, 1, 1},
+ {0, 0, 1, 1, 1, 0},
+ {0, 1, 1, 1, 0, 0},
+ {1, 1, 1, 0, 0, 0},
+ {1, 1, 0, 0, 0, 1},
+ {1, 0, 0, 0, 1, 1},
+ {0, 0, 0, 0, 1, 1, 1, 1},
+ {0, 0, 0, 1, 1, 1, 1, 0},
+ {0, 0, 1, 1, 1, 1, 0 ,0},
+ {0, 1, 1, 1, 1, 0, 0 ,0},
+ {1, 1, 1, 1, 0, 0, 0 ,0},
+ {1, 1, 1, 0, 0, 0, 0 ,1},
+ {1, 1, 0, 0, 0, 0, 1 ,1},
+ {1, 0, 0, 0, 0, 1, 1 ,1},
+ };
+
+ const size_t HalfDensitySize = std::extent<decltype(HalfDensity)>::value;
+
+ EasyMoveManager EasyMove;