- // EasyMoveManager structure is used to detect an 'easy move'. When the PV is
- // stable across multiple search iterations, we can quickly return the best move.
- struct EasyMoveManager {
-
- void clear() {
- stableCnt = 0;
- expectedPosKey = 0;
- pv[0] = pv[1] = pv[2] = MOVE_NONE;
- }
-
- 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], CheckInfo(pos)));
- pos.do_move(newPv[1], st[1], pos.gives_check(newPv[1], CheckInfo(pos)));
- 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;