zobrist哈希的增量更新
随着对FoolGo优化的进行,每次落子时重复计算棋盘的zobrist哈希值成为眼见的性能热点之一,须要修改成增量计算。
需要一个结构来表示落子前后,棋盘状态的变化:
class BrdChange { public: template <typename T> struct Change { T origin_, now_; }; struct Pair { PointIndex indx_; Change<Point> pnt_; ... }; ... private: Change<PointIndex> ko_indx_; Change<PlayerColor> last_player_; std::vector<Pair> indxs_; };
则可为Zobhasher类增加接口:
HashKey GetHash(HashKey hash, const BrdChange &chng) const;
计算每单位变化的哈希增量的函数:
template <typename T, typename GetHash> inline static HashKey HashChange(const BrdChange::Change<T> &chng, const GetHash &get) { return get(chng.origin_) ^ get(chng.now_); }
则易实现新增的GetHash接口:
template <BoardLen BOARD_LEN> HashKey ZobHasher<BOARD_LEN>::GetHash(HashKey hash, const BrdChange &chng) const { auto getko = [this](PointIndex ko_indx) { return (ko_indx == BoardInGm<BOARD_LEN>::NONE) ? noko_hash_ : ko_hash_[ko_indx]; }; auto getplayer = [this](PlayerColor color) { return player_hash_[color]; }; HashKey r = hash ^ HashChange(chng.KoChng(), getko) ^ HashChange(chng.LastPlayerChng(), getplayer); for (auto pair : chng.PointsChng()) { PointIndex pair_indx = pair.indx_; auto getpnt = [this, pair_indx](Point pnt) { return board_hash_[pair_indx][pnt]; }; r ^= HashChange(pair.pnt_, getpnt); } return r; }
优化后的哈希计算开销小了很多:
PS:依然在杭州找工作中……