6 主要算法 五子棋游戏中,有相当的篇幅是算法的部分。无论是人机对弈,还是网络对弈,都需要合理算法的支持,本节中将详细介绍五子棋中使用的算法。[13] 6.1 判断胜负 五子棋的胜负,在于判断棋盘上是否有一个点,从这个点开始的右、下、右下、左下四个方向是否有连续的五个同色棋子出现,如图6.1: 图6.1 判断胜负方向 这个算法也就是CTable的Win成员函数。从设计的思想上,需要它接受一个棋子颜色的参数,然后返回一个布尔值,这个值来指示是否胜利,代码如下: BOOL CTable::Win( int color ) const { int x, y; // 判断横向 for ( y = 0; y < 15; y++ ) { for ( x = 0; x < 11; x++ ) { if ( color == m_data[x][y] && color == m_data[x + 1][y] && color == m_data[x + 2][y] && color == m_data[x + 3][y] && color == m_data[x + 4][y] ) { return TRUE; } } } // 判断纵向 for ( y = 0; y < 11; y++ ) { for ( x = 0; x < 15; x++ ) { if ( color == m_data[x][y] && color == m_data[x][y + 1] && color == m_data[x][y + 2] && color == m_data[x][y + 3] && color == m_data[x][y + 4] ) { return TRUE; } } } // 判断“\”方向 for ( y = 0; y < 11; y++ ) { for ( x = 0; x < 11; x++ ) { if ( color == m_data[x][y] && color == m_data[x + 1][y + 1] && color == m_data[x + 2][y + 2] && color == m_data[x + 3][y + 3] && color == m_data[x + 4][y + 4] ) { return TRUE; } } } // 判断“/”方向 for ( y = 0; y < 11; y++ ) { for ( x = 4; x < 15; x++ ) { if ( color == m_data[x][y] && color == m_data[x - 1][y + 1] && color == m_data[x - 2][y + 2] && color == m_data[x - 3][y + 3] && color == m_data[x - 4][y + 4] ) { return TRUE; } } } // 不满足胜利条件 return FALSE; } 需要说明的一点是,由于这个算法所遵循的搜索顺序是从左到右、自上而下,因此在每次循环的时候,都有一些坐标无需纳入考虑范围。例如对于横向判断而言,由于右边界所限,因而所有横坐标大于等于11的点,都构不成达到五子连的条件,所以横坐标的循环上界也就定为11,这样也就提高了搜索的速度。 6.2 人机对弈算法 人机对弈算法完全按照CGame基类定义的接口标准,封装在了COneGame派生类之中。下面将对这个算法进行详细地介绍。[14] 6.2.1 获胜组合 获胜组合是一个三维数组,它记录了所有取胜的情况。也就是说,参考于CTable::Win中的情况,对于每一个落子坐标,获胜的组合一共有 15 * 11 * 2 + 11 * 11 * 2 = 572种。 而对于每个坐标的获胜组合,应该设置一个[15][15][572]大小的三维数组。 在拥有了这些获胜组合之后,就可以参照每个坐标的572种组合给自己的局面和玩家的局面进行打分,也就是根据当前盘面中某一方所拥有的获胜组合多少进行权值的估算,给出最有利于自己的一步落子坐标。 由于是双方对弈,所以游戏的双方都需要一份获胜组合,也就是: bool m_Computer[15][15][572]; // 电脑获胜组合 bool m_Player[15][15][572]; // 玩家获胜组合 在每次游戏初始化(COneGame::Init)的时候,需要将每个坐标下可能的获胜组合都置为true。 此外,还需要设置计算机和玩家在各个获胜组合中所填入的棋子数: int m_Win[2][572]; 在初始化的时候,将每个棋子数置为0。 6.2.2 落子后处理 每当一方落子后,都需要作如下处理: 如果己方此坐标的获胜组合仍为true,且仍有可能在此获胜组合处添加棋子,则将此获胜组合添加棋子数加1; 如果对方此坐标的获胜组合仍为true,则将对方此坐标的获胜组合置为false,并将对方此获胜组合添加棋子数置为-1(不可能靠此组合获胜)。 以玩家落子为例,代码为:
|