随笔分类 -  围棋博弈系列

摘要:随着对FoolGo优化的进行,每次落子时重复计算棋盘的zobrist哈希值成为眼见的性能热点之一,须要修改成增量计算。 需要一个结构来表示落子前后,棋盘状态的变化:class BrdChange{public: template <typename T> struct Change { T origin_, now_; }; struct Pair { PointIndex indx_; Change<Point> pnt_; ... }; ...private: Change<Point... 阅读全文
posted @ 2012-12-23 15:50 chncwang 阅读(2046) 评论(0) 推荐(0)
摘要:这几天把围棋A.I.最后的部分写好了,9路小棋盘上看上去运行得还不错,更名为FoolGo。先讲一下UCT博弈树的实现。 鉴于FoolGo的MC模拟速度和棋盘对象的大小,如果直接用树结构实现,用不了几分钟,我的MBP的4G内存就会被棋盘挤爆。所以要通过置换表实现博弈树。 哈希算法当然是zobrist哈希。如果哈希值的类型是uint32_t的话,不同棋局哈希冲突的概率就是1 / ~(uint32_t)0——可以认为不同的哈希值意味着不同的棋局。不用自己写哈希表,C++11新增有标准容器unordered_map,很含蓄的名字,就是哈希表。 zobrist哈希值可以增量计算,不过实现起来有... 阅读全文
posted @ 2012-12-15 01:07 chncwang 阅读(7326) 评论(1) 推荐(0)
摘要:有了棋串的数据结构后,落子就变得很高效了,接下来要生成随机棋步。 以9x9棋盘为例,直接生成0~80的随机数进行模拟会很低效,因为它们并不都是合法落子点——有3类落子点是非法的:1. 非空点 2. 劫争点 3. 自杀点。 自然想在模拟过程中增量维护这3类点集,前两类很容易维护,难点在于自杀点的增量维护。 着手写自杀点的维护后,才发现问题出乎意料的复杂。我先写了个IsSuiside函数,通过试下作为最终的裁决,而这又涉及到对象的拷贝,太过昂贵。于是想尽量少用,通过位运算来判定多数情况。然后随着测试的进行,陆续发现多处的位运算判定不可靠,不得不用IsSuiside函数替代…… 最后的效... 阅读全文
posted @ 2012-12-13 02:08 chncwang 阅读(2164) 评论(0) 推荐(1)
摘要:Monte Carlo局面评估+UCT博弈树搜索是现代计算机围棋的主流。这种方法对算法的效率有很高要求,因此须要在Mone Carlo模拟过程中保存棋串(直线相连的同色棋子集合)信息,提高落子效率。 棋串须要满足以下需求:频繁查询某棋子所在的“棋串”。频繁创建棋串。频繁查询棋串的“气”。频繁合并两棋串。移除棋串,并枚举其中的棋子。 因此用链表实现的并查集是很合适的数据结构:struct Node { PointIndex next_, list_head_;};struct List { PointIndex tail_, len_; AirSet air_set_;... 阅读全文
posted @ 2012-12-04 18:10 chncwang 阅读(1789) 评论(4) 推荐(2)