总述:五子棋问题可以化为一个博弈问题。从开始落子到最后赢,输或和的每一步落子构成了一个解,而解空间就是一个树。解就是这个树中的一条路径,只不过这个解空间的是由电脑和人的共同选择构成的。我们可以使用极大极小值搜索来解决这个博弈问题,假设每一步人和电脑都落子在最优上。但是搜索整个树是不现实的,16*16!的指数级,所以我们只回溯3步。
将棋盘的棋子存储在Pos[16][16]的数组上
对于电脑来说每下一步棋,就是找到对自己最有利,即评价函数最大的一步,下一层根据博弈的基础,对电脑越不利即是对人越有利,即找到评价函数最小的一步。
16*16的棋盘上有一些位置是不会去落子的,我们可以通过一个getpoint()得到需要下的点,即以该点为中心,7*7的范围内有子的位置,通过这种方法可以减少运算量。
评价函数即为下完一步之后,电脑与人形成的连成三个,四个,五个等等的评分和之差。评分时,需要对棋盘进行扫描,我采用的是将二维的棋盘转化至一维的数组上,通过简单的函数就可以对横边,竖边,斜边进行计分操作。每一层之间的积分我为它们增加了一个权重,加强了下面几层的对于这一层的影响,通过这种方法可以使一些我们熟悉的定式及对于空格的判断更加准确。
主要数据结构:
pos[16][16]一个16*16的棋盘,用于记录当前情况下,棋盘的情况
~~~用于存储每一个需要用到的点,包括可进行落子的位置,当前评分最高的位置。最后进行落子时,可通过随机进行取结果。
~~存储具体的某一个点。
主要函数:
1.bool judge(int i1,int i2);判断下完当前步骤之后,是否赢得了胜利。
bool judge(int i1,int i2){
//横排
for(int i=(i1-4>0?i1-4:0);i<=(i1+4>16?11:i1);i++){
if(pos[i][i2]==pos[i+1][i2]&&pos[i+1][i2]==pos[i+2][i2]&&pos[i+2][i2]==pos[i+3][i2]&&pos[i+3][i2]==pos[i+4][i2])
return true;
}
//竖排
for(int j=(i2-4>0?i2-4:0);j<=(i2+4>16?11:i2);j++){
if(pos[i1][j]==pos[i1][j+1]&&pos[i1][j+1]==pos[i1][j+2]&&pos[i1][j+2]==pos[i1][j+3]&&pos[i1][j+3]==pos[i1][j+4])
return true;
}
//正斜线
int i=i1-4;
int j=i2-4;
while(i<0||j<0){
i++;
j++;
}
for(;i<=(i1+4>16?11:i1)&&j<=(i2+4>16?11:i2);i++,j++){
if(pos[i][j]==pos[i+1][j+1]&&pos[i+1][j+1]==pos[i+2][j+2]&&pos[i+2][j+2]==pos[i+3][j+3]&&pos[i+3][j+3]==pos[i+4][j+4])
return true;
}
//反斜线
i=i1+4;
j=i2-4;
while(j<0||i>15){
j++;
i--;
}
for(;i>=0&&j<=(i2+4>16?11:i2);i--,j++){
if(pos[i][j]==pos[i-1][j+1]&&pos[i-1][j+1]==pos[i-2][j+2]&&pos[i-2][j+2]==pos[i-3][j+3]&&pos[i-3][j+3]==pos[i-4][j+4])
return true;
}
return false;
}
2. int scoretable(int number,int empty);计分板详细情况如下
连成五个 100000
连成四个,没有端点被堵 10000
连成四个,一个端点被堵 2000
连成三个,没有端点被堵 1500(可以使连成两个没有被堵的三个比连成被堵的四个更有优势)
连成三个,一个端点被堵 100
连成两个,没有端点被堵 100
连成