上上周末花了两天时间解决了围棋吃子程序,在上周又赶了一个socket的chatroom,结果数据分析的课的作业就拉下了~_~。今天得空把围棋吃子程序及其思路拿出来与大家分享下。本围棋程序是用processing编写的。
从易到难,我们先进行单个子吃子的分析,吃单个子的程序是很容易实现的,就是判断每个字的上下左右四个位置是否有对手的子或者是到了边缘,如果都是这样就将此子提掉。
换做连续多个子的分析,我们引入“气”这个围棋概念,“气”你可以简单理解成单个子周围是否有空位,没有空位就包括周围是对方子或已到边缘,这也就是成为了是否可以提子的判断依据。由于是多个相同颜色的棋子连在一起,我们把这些连在一起的子称之为“块”。我们定义吃子概念为:如果该“块”无“气”,便可以提去,即吃子。
有了吃子的理论实现方法我们下面来进行代码的实现:
Note:map[][]是储存了棋盘状态的二维数组,0表示该位置无棋子,黑子为-1,白子为1.
简单介绍下框架:
1.声明一维数组block[]作为一个临时变量记录一个块的大小,声明一个整型blockLength记录这个块的长度。
2.kill()为吃子的主函数。
recersion(int i,int j)为遍历周围棋子的函数在kill函数中调用。
hasQi()判断该块是否有气在kill函数中调用。
isInBlock(int neighbor)用来判断在遍历周围棋子中是否已经遍历,在recersion函数中调用。
详细介绍下功能:
kill函数双层for循环里遍历了所有位置,判断如果该位置无棋子,跳过本此循环检测下个位置。如果有棋子,定义一个19*19=361空间的int数组,名为block,并且将对应此block的blockLength更新为1. 将该坐标记录在int型的block[0]里,x坐标值*100+y坐标值。
调用recursion函数,参数i,j为该棋子的坐标值,递归调用直至遍历了所有与坐标(i,j)处的棋子颜色相同的棋子并将他们挨个记录在block的数组里。
recursion函数里if判断语句分别对应:
1.下个位置是否还在棋盘里
2.下个位置是否与自己颜色一致
3.是否该棋子已经存在于block的数组里了即是否已经遍历过了。
(这样做的目的是防治进入左与右或者上与下不断相互判断的无限循环中。eg:两个左右相邻的相同颜色的棋子组成的一个块中,先判断了右边是相同颜色,如果不检测左边这个棋子是否已经在block里,在recursion到右边这个棋子的时候还会判断到左边这个棋子,这样就会进入一种无限的循环之中,这不是我们想看到的。)
hasQi函数在kill函数里调用recursion记录块结束后调用,判断该块是否有气,有气则该函数返回true。如果该块无气,即满足提子要求,则将这些子在map[][]里对应位置的值设0.
在编写的draw函数不断的刷新显示map就可以啦。至此已成功实现围棋吃子功能。
下面是参考代码:
public void kill(){
for(int i = 0;i < 19; i++){
for(int j = 0;j < 19; j++){
if(map[i][j] == 0)
continue;
else{
block = new int[361];
blockLength = 1;
block[0] = i*100 + j;
recursion(i,j);
if(hasQi())
continue;
else {
for(int t = 0;t < blockLength; t++)
map[block[t]/100][block[t]%100] = 0;
}
}
}
}
}
public void recursion(int i,int j){
//Left
if(i-1 >= 0 && map[i-1][j] == map[i][j] && isInBlock((i-1)*100+j)){
block[blockLength] = (i-1)*100 + j;
blockLength++;
recursion(i-1,j);
}
//Up
if(j-1 >= 0 && map[i][j-1] == map[i][j] && isInBlock(i*100+j-1)){
block[blockLength] = i*100 + j-1;
blockLength++;
recursion(i,j-1);
}
//Right
if(i+1 < 19 && map[i+1][j] == map[i][j] && isInBlock((i+1)*100+j)){
block[blockLength] = (i+1)*100 + j;
blockLength++;
recursion(i+1,j);
}
//Down
if(j+1 < 19 && map[i][j+1] == map[i][j] && isInBlock(i*100+j+1)){
block[blockLength] = i*100 + j+1;
blockLength++;
recursion(i,j+1);
}
}
public boolean hasQi(){
int i,j;
for(int t = 0;t < blockLength; t++){
i = block[t]/100;
j = block[t]%100;
if(i-1 >= 0 && map[i-1][j] == 0) return true;
if(i+1 < 19 && map[i+1][j] == 0) return true;
if(j-1 >= 0 && map[i][j-1] == 0) return true;
if(j+1 < 19 && map[i][j+1] == 0) return true;
}
return false;
}
public boolean isInBlock(int neighbor){
for(int i = 0;i < blockLength; i++)
{
if (block[i] == neighbor) return false;
}
return true;
}
有问题欢迎留言。
原文发于博客:http://blog.csdn.net/u013787595
GMX 2014.4.7 US Eastern Time