
1.5 Reversi黑白棋游戏

1.5 Reversi黑白棋游戏
在本节的内容中,将详细介绍实现Reversi黑白棋游戏的方法,并详细讲解实现代码的功能。
1.5.1 笛卡儿坐标系
笛卡儿坐标系是直角坐标系和斜坐标系的统称,将两条数轴互相垂直的笛卡儿坐标系称为笛卡儿直角坐标系,否则称为笛卡儿斜角坐标系。
(1)2D笛卡儿坐标系
2D笛卡儿坐标系是指处于同一个平面的坐标系,每个2D笛卡儿坐标系都有一个特殊的点,称为原点,是坐标系的中心。每个2D笛卡儿坐标系都有两条过原点的直线并向两边无限延伸,称为轴。
在2D笛卡儿坐标系中,习惯将水平的轴称为X轴,向右为X轴的正方向。将垂直的轴称为Y轴,向上为Y轴正方向。读者可以根据需要来决定坐标轴的指向,也可以决定轴的正方向。
在2D笛卡儿坐标系中有8种可能的轴的指向,如图1-1所示。无论如何选择X轴和Y轴的方向,总能通过旋转使得X轴向右为正,Y轴向上为正,所以所有的2D坐标系都是“等价”的。

图1-1 2D笛卡儿坐标系中有8种可能的轴的指向
为了在坐标系中定位点,引入了笛卡儿坐标的概念。在2D平面中,两个数(x,y)可以定位一个点,坐标的每个分量都表明了该点与原点之间的距离和方位:每个分量都是到相应轴的有符号距离。有符号距离指的是在某个方向上距离为正,在相反方向上为负。
(2)3D笛卡儿坐标系
为了表示三维坐标系,在笛卡儿坐标系中引入第三个轴:Z轴。一般情况下,这三个轴相互垂直,即每个轴垂直于其他两个轴。在2D平面中,通常设置X轴向右为正,Y轴向上为正的标准形式,但是在3D中没有标准形式。在3D中定位一个点需要3个数:X、Y和Z,分别代表该点到YZ、XZ和XY平面的有符号距离,如图1-2所示。

图1-2 3D中的定位点
1.5.2 实例介绍

Reversi黑白棋是一款在棋盘上玩的游戏,将使用带有X和Y轴坐标的2D笛卡儿坐标系实现。有一个8×8的游戏板,一方的棋子是黑色,另一方的棋子是白色(在游戏程序中分别使用O和X来代替这两种颜色)。开始的时候,棋盘界面如图1-3所示。

图1-3 棋盘中最初分别有两个黑子和两个白子
1.5.3 具体实现
实例文件Reversi.py的主要实现代码如下所示。




在上述代码中,虽然函数drawBoard()会在屏幕上显示一个游戏板数据结构,但是还需要一种创建这些游戏板数据结构的方式。函数getNewBoard()创建了一个新的游戏板数据结构,并返回8个列表的一列,其中的每一个列表包含了8个用单引号括起来的空字符串,它们用来表示没有落子的一个空白游戏板。
当给定了一个游戏板数据结构、玩家的棋子以及玩家落子的X、Y坐标后,如果Reversi游戏规则允许在该坐标上落子,则isValidMove()函数应该返回True,否则返回False。对于一次有效的移动,它必须位于游戏板之上,并且还要至少能够反转对手的一个棋子。这个函数使用了游戏板上的几个X坐标和Y坐标,因此变量xstart和变量ystart记录了最初移动的X坐标和Y坐标。
函数getScoreOfBoard()使用嵌套for循环检查游戏板上的所有64个格子(8行乘以每行的8列,一共是64个格子),并且看看哪些棋子在上面(如果有棋子的话)。
执行后会输出:

在本项目中,游戏板数据板结构只是一个Python列表值,但是,我们需要一种在屏幕上展示它的更好方法。通过使用函数drawBoard()根据board中的数据结构来打印输出当前游戏板。
函数isOnBoard()用于检查X坐标和Y坐标是否在游戏板之上,以及空格是否为空。通过这个函数确保了坐标X和坐标Y都在0和游戏板的WIDTH或HEIGHT减去1之间。
函数getValidMoves()返回了包含两元素列表的一个列表。这些列表保存了给定的tile可以在参数board中的游戏板数据结构中进行的所有的有效移动的X、Y坐标。
在函数getScoreOfBoard()中,对于每个X棋子,通过代码“xscore+=1”将xscore值加1。对于每个O棋子,通过代码“oscore+=1”将oscore值加1。然后,该函数将xcore和oscore的值返回到一个字典中。