博鱼体育- 博鱼体育官方网站- APP下载从零开始开发一个小游戏——五子棋AI⑨Zobrist哈希
栏目:哈希游戏 发布时间:2025-08-15
  博鱼体育,博鱼体育官方网站,博鱼体育APP下载/博鱼体育官方网站[永久网址:363050.com]拥有亚洲市场最大的线上娱乐服务,博鱼,博鱼体育,博鱼官方网站,博鱼boyu,博鱼体育登录入口,博鱼体育,博鱼体育官方平台,boyu博鱼中国官方网站,博鱼官网,博鱼体育登录入口,博鱼体育官网,博鱼体育下载,博鱼体育平台,博鱼体育改名,博鱼app下载,博鱼注册网址,博鱼官方网站,并且博鱼体育有

  博鱼体育,博鱼体育官方网站,博鱼体育APP下载/博鱼体育官方网站[永久网址:363050.com]拥有亚洲市场最大的线上娱乐服务,博鱼,博鱼体育,博鱼官方网站,博鱼boyu,博鱼体育登录入口,博鱼体育,博鱼体育官方平台,boyu博鱼中国官方网站,博鱼官网,博鱼体育登录入口,博鱼体育官网,博鱼体育下载,博鱼体育平台,博鱼体育改名,博鱼app下载,博鱼注册网址,博鱼官方网站,并且博鱼体育有这业界最优质的服务本文是从零开始开发一个小游戏系列文章的第二个项目——五子棋AI的第八篇,本系列文章将详细介绍几种五子棋ai算法的实现方法以及优化方案,并会在最后介绍这些算法如何延伸到其他类型的游戏。 源代码地址为:GitHub - EdmundTheRadiance/gobang: A minigame demo to show gobang game AI.

  在之前的文章中,我们介绍了极大极小算法结合alpha-beta剪枝的五子棋ai,他是事先定义每种序列的得分,再经过算法找到得分最大的下法,而在运行过程中,会频繁地计算各种可能局面的得分,并且重复计算相同局面的可能性比较高,那么我们有没有方法能缓存已计算的局面来减少重复计算?

  在讲解极大极小算法时我们提到过,在进行模拟落子时,我们需要假设一方在某处(记作a)落子之后,计算另一方所有落子的可能,并对每一种落子的局面计算分数,来得到a的可能的最大或最小分数,那么在这个过程中,就很有可能会计算到重复局面的分数(比如对称的落子情况、不同的走子顺序导致的同一局面等)。

  一般而言对于这类避免重复计算的问题,比较通用的解决方案是对当前的局面计算一个hash,并且保证:

  这样我们就可以通过hashmap来缓存不同局面的得分,并且在计算新局面时,先计算hash,看有没有命中缓存,若无缓存再继续计算分数。

  除了缓存局面的得分,如果我们使用了棋谱,希望局面与棋谱一致时,直接使用棋谱的下法,同样也可以通过hash的方法来实现。我们可以先将棋谱中每一步走棋所形成的局面都计算出hash,再记录这个局面下一步在哪里落子,在游戏过程中,若当前局面命中了棋谱中的局面,就直接使用棋谱中的下法。

  我们可以使用Zobrist哈希来对某个局面进行hash计算,他的实现过程是:

  1.首先对棋盘每个位置的每种可能(黑、白、无)都生成一个很大的随机数2.游戏开始时,将未落子棋盘的hash记为03.每次落子时,根据落子位置和颜色,找到这次落子对应的随机数4.将上一局面的hash异或这个随机数,得到新的hash5.看看缓存中是否已有这个hash的得分,有则直接使用6.若无缓存,则计算这个局面的得分,并记录到缓存中

  由于我们刚才提到,希望在棋谱匹配时也能通过hash匹配,那么我们这个随机数表只需要生成一次,后面不管是棋谱的预处理,还是游戏中计算局面的hash,都使用同一份随机数表,这样相同局面计算的hash都是一致的。

  transpositionTable是置换表,可以理解为缓存,开始时将其初始化,之后就是遍历当前棋盘,若某个位置有棋子,则异或对应的随机数,若整个棋盘无棋子默认值为0

  首先调用lookupInTranspositionTable函数,在置换表中寻找是否当前hash已计算过分数,有则直接返回

  找到所有可能的下法,对每种下法,模拟落子后调用updateHash计算新局面的hash值,递归调用zobristHash,传入新hash

  使用zobristHash算法进行ai之间的对弈,共对局100局,我们使用了迭代两步的alpha-beta算法,一共调用了评分函数2289280次,使用缓存294936次,也就是差不多能节省10%左右的计算量

  我们上面提到了如果我们想使用棋谱,那是非常适合使用zobristHash算法的,我们可以将棋谱中的每一步走棋后的局面,都计算一次hash,在游戏过程中,如果匹配到了棋谱的局面就可以直接使用棋谱的下法

  首先我们需要找到一些棋谱,我这里使用了爬取的方式,具体细节比较简单就不展开了,可以找到一个有棋谱记录的五子棋网站,通过爬取他的数据记录下棋谱。

  之后对每一步走棋调用updateHash,计算出每个局面的hash,再将hash和下一步落子的位置记录下来,保存到文件里。

  代码也比较简单,引入棋谱后,在计算当前局面的hash后,就在棋谱中寻找,有则直接使用棋谱的下法

  利用hash算法来缓存是一个比较常用的优化思路,对复杂的运算或者很耗资源的操作,通过空间换时间的方法,将结果缓存来提高运行性能,但这里还需要注意两个点:

  1.hash映射一般而言都会出现不同的原数据映射到同一个hash的情况,对于五子棋而言,就是两个不同的局面hash却是一样的,这会对算法产生很大的影响,因此zobristHash算法使用了异或一个很大的随机数来减小冲突的情况,如果大家之后在使用类似的方法进行优化的时候,也要充分考虑降低冲突的概率以及冲突出现的影响

  2.缓存率是这种优化方法最核心的指标,因此如何提高缓存率是关键,对于五子棋,其实会出现对称或旋转的情况,比如一个局面a和转90度之后的局面b应该能使用到同一份缓存,但目前介绍的zobristHash算法还没有考虑到这一点,大家可以考虑下如何兼容这种情况,这样缓存率也能进一步提升。