首页 百科知识 棋盘数据结构和主要方法

棋盘数据结构和主要方法

时间:2022-10-01 百科知识 版权反馈
【摘要】:在图15.2中已经介绍了棋盘模块的主体结构,这里我们主要从棋盘和对局的类内实现细节入手,包括参数的选择、函数的实现等。zobrist_hash则是得到以指定点为中心模式的zobrist哈希值,为快速的模式匹配而使用,其具体的哈希值通过在每次在棋盘上落子之后,使用update_zobrist进行更新,更新好的哈希值则放在hash这个数组中,方便直接使用。这几个函数和zobrist_hash函数有一个共同点,就是在调用时并不做任何计算,而是直接从相关参数中取出所需内容返回。

16.1 棋盘数据结构和主要方法

这一节主要关于棋盘和对局的相关伪码,介绍棋盘和对局模块的一些具体细节。

在图15.2中已经介绍了棋盘模块的主体结构,这里我们主要从棋盘和对局的类内实现细节入手,包括参数的选择、函数的实现等。

1.棋盘

我们先从整个模块的基类Board开始介绍,由于在程序设计时,就是本着面向对象的思想,在具体实现上,我们更需要从始至终贯穿这一思想。

棋盘就如真实的棋盘一样,需要具有基本的摆子的功能;但是,只具有这个功能还略显单薄,还需要具有一些额外的功能。所谓这些额外的功能,是指那些非常基础,就是对于初学者也能一眼看出来的东西,如提子、眼、打吃等。尽管这些功能本不是棋盘的职责,而是对弈双方的事情;但是,如果说这些并非棋盘的本身功能,又有些牵强,因为毕竟这些都是从棋盘上可以一眼看出来的;并且,这些东西在任何人眼中都是一样的,与水平高低无关,也并不需任何复杂的分析。另外,在对弈中,要想对棋盘做任何深入的判断分析,都是以这些基本的信息为出发点的。由此,在程序中,如果棋盘本身不具备这些功能,而是让对弈双方每次都不断去计算这些,也会浪费很多计算量。

如果让两个人在一个电子棋盘上下棋,当出现提子这种情况的时候,如果这个棋盘能自动提子,而不是对弈者手工将这些子一个个提下去,这无疑是很让人开心的事情,这样对弈者就能专注于下棋了。

Listing16.1中是棋盘类的具体伪码,我们将函数分为两类,一类是关于基本功能的实现,可以直接供其他函数调用,我们将其设为public;另一类就是完成一些辅助功能,在那些public函数的后面做一些幕后的工作,为private。

Listing16.1 棋盘伪码

img198

在public函数中,play是最基本的函数,实现的是往棋盘上摆子这一功能,而整个棋盘状态则储存在board这个数组变量中。zobrist_hash则是得到以指定点为中心模式的zobrist哈希值,为快速的模式匹配而使用,其具体的哈希值通过在每次在棋盘上落子之后,使用update_zobrist进行更新,更新好的哈希值则放在hash这个数组中,方便直接使用。is_atari、self_atari、playable、is_eye、get_ko也均是查看棋盘基本状态的,依次是判断一个棋子是否处于打吃状态、一个位置是否是自己的自杀的位置、一个位置是否可以落子(空点、不是眼、是否是打劫等)、一个位置是否为眼、哪个位置正在打劫。这几个函数和zobrist_hash函数有一个共同点,就是在调用时并不做任何计算,而是直接从相关参数中取出所需内容返回。而这些参数具体数值的计算也像update_hash一样,是在落子后自动调用,保证参数动态更新的。remove_dead、update_atari_chains、update_ko都是进行相关参数动态更新的,分别是自动提子、更新棋盘上的处于打吃状态的棋子、更新打劫信息。

2.全棋盘

全棋盘作为棋盘的子类,继承了棋盘的全部功能,所不同的则是多了记录落子顺序的信息。

Listing16.2中是相关伪码,在Board类的play函数的基础上增加了记录落子顺序的代码。

Listing16.2 全棋盘伪码

img199

3.对局

对局类作为对棋盘的延伸,给对弈引擎提供了一个对弈的场所,并组织对局。

Listing16.3中是相关伪码,通过构造函数将指向黑白双方的对弈引擎指针指向需要的引擎,step函数是让指定的一方引擎生成落子位置,并对盘面进行评估,将结果返回;play函数是整个对弈进行整体上的控制,让黑白双方轮流落子,直至得到结果。

Listing16.3 对局伪码

img200

img201

前面提到的这些基础部件,都是为了下面要讲到的对弈引擎来服务的。要想让对弈引擎在生成着法时可以在一个尽可能准确和高效的棋盘之上做计算,尽可能少的被其他外界因素所干扰,就需要这些基础部件可以在尽可能准确的实现其基本功能的基础上,还要兼顾性能和效率。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈