五子棋博弈搜索实验报告
一 实验内容
五子棋对弈程序
二 算法、数据结构与函数设计
算法:
由于五子棋比一字棋难,规则多,又有禁手限制,无法采用简单的搜索和加分方式。
为了分清各种情况的轻重缓急,我们采用一次性打分的策略:
对棋盘上的每个空位根据情况的轻重缓急,越重越争分越高,反之越低,然后根据打分找出分值最高的的位置下子。
打分事实根据有:是否赢棋(最高),对方是否要赢棋,是否禁手,可形成四连的个数,和形成三连(包括活三)的个数,对方可可形成四连的个数,和形成三连(包括活三)的个数,等等。
本算法的好处在于,既有攻又有守,而且攻守较严。
数据结构:
根据算法的一般要求以及实际问题需要,为了方便操作,我们用二维数组(int)表示棋盘:
chessBoard [15, 15]
其中1表示黑子,-1表示白子,0表示无子。这样定义方便轮转棋子的颜色。
为了方便悔棋,我们定义了一个专门用于悔棋的内部类:
public class StepPoint//下棋点,用于回溯
{
public int x;
public int y;
public int color;// 其中1表示黑子,-1表示白子,0表示无子。
};
public Stack backStack = new Stack();//悔棋用的。
判断一局棋是不是结束用一个bool变量:bool end;
函数:
根据算法的要求和实际问题的需要,我们定义了以下几个函数:
//求color色棋在(x,y)点的权重
private int pointWeight(int color, int x, int y)
//寻找最好的10个下棋点,如有多个最大值,则采用随机方式给出。找不到就返回false
private bool searchBestPoint(int color,ref int x, ref int y)
//(x,y)处放color色棋后是否能在(x1,y1)和(x2,y2)之间形成活count且不被另一色棋时不被破坏
private bool breakLiveCount(int color, int count, int x, int y, int x1, int y1, int x2, int y2)
//求两点(x1,y1),(x2,y2)间最长的color色连的棋的数目
private int linkCount(int color, int x1, int y1, int x2, int y2)
//判断两点(x1,y1),(x2,y2)间是否存在活的count(0~5)
private bool liveCount(int color, int count, int x1, int y1, int x2, int y2)
//判断点(x,y)放入黑棋后是否形成长连(6连)
private bool hasLongLink(int x, int y)
此外,还有其他界面函数等等。
三 打分(权重)算法设计与实现
在本算法中,最重要的就是打分了。也就是int pointWeight(int color, int x, int y)函数的实现。由于黑棋有禁手而白棋无禁手,故两种棋的打分策略略有不同,当电脑为黑子时,多攻少守,当电脑为白子时,多守少攻。具体如下:
int[] colorLink = new int[6];//下棋方棋连数从0~5(由下标值表示)
int[] colorLive = new int[6];//下棋方活连棋数从0~5(由下标值表示)
int[] fcolorLink = new int[6];//对手方棋连数从0~5(由下标值表示)
int[] fcolorLive = new int[6];//对手方活棋连数从0~5(由下标值表示)
if (color == 1)//如果是下棋方是黑子,有禁手
{
if ( hasLongLink(x, y))//对不起,长连
return -2;//禁手
else if (colorLink[5] > 0)//自己可以形成5
return 150000;
else if (colorLive[3] > 1 || colorLive[4] + colorLink[4] > 1)//四四,活三三,都是禁手
return -1;
else if (fcolorLink[5] > 0)//破坏对方的5
return 140000;
else if (colorLive[4] == 1)//可以形成一个活四
return 130000;
else if (colorLink[4] == 1 && colorLive[3] == 1)//可以形成一个四三
return 120000;
else if (colorLink[4] == 1 && colorLink[3] > 0)
return 110000;
//防守式战略
else if (fcolorLive[4] > 0 || fcolorLink[4] > 1)
return 100000;
else if (fcolorLink[4] == 1 && tempLive3 == 1)
return 90000;
else if (fcolorLive[3] > 1)
return 80000;
else if (fcolorLink[4] == 1 && fcolorLink[3] > 0)
return 70000;
else
{
totalWeight = (colorLink[4] + colorLive[3]) * 6250 + (colorLink[3] + colorLive[2] + fcolorLink[4] + fcolorLive[3]) * 1250+ (colorLink[2] + fcolorLink[3] + fcolorLive[2]) * 250 + colorLive[1] * 50 + (colorLink[1] + fcolorLink[2] + fcolorLive[1]) * 10 + fcolorLink[1] * 2;
return totalWeight;
}
}
else//如果是下棋方是白子,考虑黑子的禁手
{
bool isBlackForbiden = (tempLive3 > 1 || colorLive[4] > 1 || hasLongLink(x, y));//黑棋有禁手
bool isBlackLongLink = hasLongLink(x, y);//黑手有长连禁手
if (colorLink[5] > 0)//自已可以形成5
return 150000;
else if (fcolorLink[5] > 0 && !isBlackLongLink)//对方可以形成5,且没有长连禁手限制
return 140000;
//进攻与防守相结合的战略
else if (colorLive[4] > 0 || fcolorLink[4] > 1)//自己可以形成活四,或者对方可以形成两个四连
return 130000;
else if (colorLink[4] == 1 && fcolorLive[3] > 0)
return 120000;
else if (fcolorLive[4] == 1 && !isBlackForbiden || colorLink[4] > 1 && !isBlackForbiden)
return 110000;
else if (colorLink[4] == 1 && fcolorLink[3] > 0)
return 100000;
else if (fcolorLink[4] > 0 && tempLive3 == 1 && !isBlackForbiden)
return 90000;
else if (colorLive[3] > 1)
return 80000;
else if (fcolorLink[4] > 0 && colorLink[3] > 0 && !isBlackForbiden)
return 70000;
else
{
totalWeight = (colorLink[4] + colorLive[3]) * 6250 + (colorLink[3] + colorLive[2] + fcolorLink[4] + fcolorLive[3]) * 1250+ (colorLink[2] + fcolorLink[3] + fcolorLive[2]) * 250 + colorLive[1] * 50 + (colorLink[1] + fcolorLink[2] + fcolorLive[1]) * 10 + fcolorLink[1] * 2;
return totalWeight;
}
四 测试方法及测试结果
(电脑先走):
第一轮:
第二轮:
从结果可以看出:人一不小心就会输给电脑,但要赢电脑却要精心策算,步数很多。而且电脑采取最高分随机策略,同一棋盘棋形有可能下出不同的步子,人不能猜测。
(玩家先走):
第三轮:
第四轮:
从结果可以看出:当电脑是白子时,电脑采用多守少攻的策略。
六 实验心得
我们在试验中遇到了不少的问题,但是经过大家的努力和仔细分析调试,终于使实验取得成功。整个过程中我们遇到的主要问题以及吸取到的一些经验教训如下:
- 采用打分算法有一个缺点,就是不能进像极大极小和α-β搜索那样进行行更深度的搜索,
因为该点的权重只对当前棋盘的棋形有效,当对方下了一子后,棋盘棋形变了,该点的权重有可能从原来的最好(也就是最急)变成最差的。
总体来说,我们的这次实验还是进行的很成功的,这跟团队合作以及个人能力都是分不开的。实验过程令人受益匪浅。