免费论文设计VC++五子棋 第5页
图5.7 认输
5.2.9 聊天消息——MSG_CHAT
表明对方发送了一条聊天信息,szMsg表示对方的信息,其余成员无效。接到这个信息后,会将对方聊天的内容显示在主对话框的聊天记录窗口内。
5.2.10 对方信息消息——MSG_INFORMATION
用来获取对方玩家的姓名,szMsg表示对方的姓名,其余成员无效。在开始游戏的时候,由客户端向服务端发送这条消息,服务端接到后设置对方的姓名,并将自己的姓名同样用这条消息回发给客户端。
5.2.11 再次开局消息——MSG_PLAYAGAIN
表明对方希望开始一局新的棋局,除uMsg成员外其余成员皆无效。接到这个消息后,会弹出MessageBox询问是否接受对方的请求(如图5.8所示),并根据玩家的选择回返MSG_AGREEAGAIN消息或直接断开网络。
图5.8 再次开局
5.2.12 同意再次开局消息——MSG_AGREEAGAIN
表明对方同意了再次开局的请求,除uMsg成员外其余成员皆无效。接到这个消息后,将开启一局新游戏。
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++ )
{
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] &&
// 不满足胜利条件
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 落子后处理
每当一方落子后,都需要作如下处理:
l 如果己方此坐标的获胜组合仍为true,且仍有可能在此获胜组合处添加棋子,则将此获胜组合添加棋子数加1;
l 如果对方此坐标的获胜组合仍为true,则将对方此坐标的获胜组合置为false,并将对方此获胜组合添加棋子数置为-1(不可能靠此组合获胜)。
以玩家落子为例,代码为:
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ... 下一页 >>