编过或思考过五子棋程序的请进,回答满意给300分。

natrium11 2001-06-01 12:41:00
我想知道某一位置的分值应如何打??
我现在采用的系统很不理想,搜索深度一高,误差很大,所以经常下出匪夷所思的棋。
请给出一种方案。(如活三给多少分?防住对方活三又给多少分?等等)

另外,我原来的方法是取我的这一位置的分,再减去对方下一位置的最高得分来获得我这个位置的最高得分。(对方下一位置的最高得分也如是递归得到,直到达到最大深度)
即用深优(外加A-B剪枝)

现在我采用取我的这一个位置的最高的5个得分,再求对方下一位置的最高5个得分并相减,这样共25个分数,取最高的5个得分,再求我下一位置的最高5个得分并相加,这样又有25个分数,再取最高的5个得分。。。。。。重复这一过程直至达到最大深度。即用广优。

现请教,用深优好还是广优好?另外我上面的相应方法可如何改进??
...全文
589 18 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
moocher 2001-07-10
  • 打赏
  • 举报
回复
五子棋是一种受大众广泛喜爱的游戏,其规则简单,变化多端,非常富有趣味性和消遣性。这里设计和实现了一个人机对下的五子棋程序,采用了博弈树的方法,应用了剪枝和最大最小树原理进行搜索发现最好的下子位置。介绍五子棋程序的数据结构、评分规则、胜负判断方法和搜索算法过程。

一、相关的数据结构
关于盘面情况的表示,以链表形式表示当前盘面的情况,目的是可以允许用户进行悔棋、回退等操作。
CList StepList;
其中Step结构的表示为:

struct Step
{
int m; //m,n表示两个坐标值
int n;
char side; //side表示下子方
};
以数组形式保存当前盘面的情况,
目的是为了在显示当前盘面情况时使用:
char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];

其中FIVE_MAX_LINE表示盘面最大的行数。

同时由于需要在递归搜索的过程中考虑时间和空间有效性,只找出就当前情况来说相对比较好的几个盘面,而不是对所有的可下子的位置都进行搜索,这里用变量CountList来表示当前搜索中可以选择的所有新的盘面情况对象的集合:

CList CountList;
其中类CBoardSituiton为:
class CBoardSituation
{
CList StepList; //每一步的列表
char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];
struct Step machineStep; //机器所下的那一步
double value; //该种盘面状态所得到的分数
}

二、评分规则
对于下子的重要性评分,需要从六个位置来考虑当前棋局的情况,分别为:-,|,/,\,//,\\


实际上需要考虑在这六个位置上某一方所形成的子的布局的情况,对于在还没有子的地方落子以后的当前局面的评分,主要是为了说明在这个地方下子的重要性程度,设定了一个简单的规则来表示当前棋面对机器方的分数。

基本的规则如下:

判断是否能成5, 如果是机器方的话给予100000分,如果是人方的话给予-100000 分;
判断是否能成活4或者是双死4或者是死4活3,如果是机器方的话给予10000分,如果是人方的话给予-10000分;
判断是否已成双活3,如果是机器方的话给予5000分,如果是人方的话给予-5000 分;
判断是否成死3活3,如果是机器方的话给予1000分,如果是人方的话给予-1000 分;
判断是否能成死4,如果是机器方的话给予500分,如果是人方的话给予-500分;
判断是否能成单活3,如果是机器方的话给予200分,如果是人方的话给予-200分;
判断是否已成双活2,如果是机器方的话给予100分,如果是人方的话给予-100分;
判断是否能成死3,如果是机器方的话给予50分,如果是人方的话给予-50分;
判断是否能成双活2,如果是机器方的话给予10分,如果是人方的话给予-10分;
判断是否能成活2,如果是机器方的话给予5分,如果是人方的话给予-5分;
判断是否能成死2,如果是机器方的话给予3分,如果是人方的话给予-3分。

实际上对当前的局面按照上面的规则的顺序进行比较,如果满足某一条规则的话,就给该局面打分并保存,然后退出规则的匹配。注意这里的规则是根据一般的下棋规律的一个总结,在实际运行的时候,用户可以添加规则和对评分机制加以修正。

三、胜负判断
实际上,是根据当前最后一个落子的情况来判断胜负的。实际上需要从四个位置判断,以该子为出发点的水平,竖直和两条分别为 45度角和135度角的线,目的是看在这四个方向是否最后落子的一方构成连续五个的棋子,如果是的话,就表示该盘棋局已经分出胜负。具体见下面的图示:


四、搜索算法实现描述
注意下面的核心的算法中的变量currentBoardSituation,表示当前机器最新的盘面情况, CountList表示第一层子节点可以选择的较好的盘面的集合。核心的算法如下:
void MainDealFunction()
{
value=-MAXINT; //对初始根节点的value赋值
CalSeveralGoodPlace(currentBoardSituation,CountList);
//该函数是根据当前的盘面情况来比较得到比较好的可以考虑的几个盘面的情况,可以根据实际的得分情况选取分数比较高的几个盘面,也就是说在第一层节点选择的时候采用贪婪算法,直接找出相对分数比较高的几个形成第一层节点,目的是为了提高搜索速度和防止堆栈溢出。
pos=CountList.GetHeadPosition();
CBoardSituation* pBoard;
for(i=0;ivalue=Search(pBoard,min,value,0);
Value=Select(value,pBoard->value,max);
//取value和pBoard->value中大的赋给根节点
}
for(i=0;ivalue)
//找出那一个得到最高分的盘面
{
currentBoardSituation=pBoard;
PlayerMode=min; //当前下子方改为人
Break;
}
}

其中对于Search函数的表示如下:实际上核心的算法是一个剪枝过程,其中在这个搜索过程中相关的四个参数为:(1)当前棋局情况;(2)当前的下子方,可以是机器(max)或者是人(min);(3)父节点的值oldValue;(4)当前的搜索深度depth。

double Search(CBoardSituation&
board,int mode,double oldvalue,int depth)
{
CList m_DeepList;
if(deptholdvalue))== TRUE)
{
if(mode==max)
value=select(value,search(successor
Board,min,value,depth+1),max);
else
value=select(value,search(successor
Board,max,value,depth+1),min);
}
return value;
}
else
{
if ( goal(board)<>0)
//这里goal(board)<>0表示已经可以分出胜负
return goal(board);
else
return evlation(board);
}
}

注意这里的goal(board)函数是用来判断当前盘面是否可以分出胜负,而evlation(board)是对当前的盘面从机器的角度进行打分。

下面是Select函数的介绍,这个函数的主要目的是根据 PlayerMode情况,即是机器还是用户来返回节点的应有的值。

double Select(double a,double b,int mode)
{
if(a>b && mode==max)|| (a< b && mode==min)
return a;
else
return b;
}

五、小结
在Windows操作系统下,用VC++实现了这个人机对战的五子棋程序。和国内许多只是采用规则或者只是采用简单递归而没有剪枝的那些程序相比,在智力上和时间有效性上都要好于这些程序。同时所讨论的方法和设计过程为用户设计其他的游戏(如象棋和围棋等)提供了一个参考。
zyj_vc 2001-06-07
  • 打赏
  • 举报
回复
zyj_vc 2001-06-07
  • 打赏
  • 举报
回复
我觉得子节点的选择不要限定数目,要根据分数定,例如说敌人已经冲四了,你没有连成五个的就只能下一个点,所以子节点有一个就够了,但是有时候就要考虑很多点,通过搜索来确定哪一个好,你不要指望通过打分来确定各点的绝对优劣,其实可以按一些优先级给分,不用太精确,因为以后还要搜索。其实有的棋单从当前棋局是看不出好坏的,例如说敌人活三了,而你有四可冲,是先冲四,还是堵敌人的?恐怕很难说。我的五子棋的打分规则很简单,主要是能判断那些绝对应该先下的,与其说打分,还不如说是分级。现在我最大的问题就是程序速度太慢,判断那些定势速度太慢,要十几毫秒,所以搜索深度有限,棋力就差了。
natrium11 2001-06-07
  • 打赏
  • 举报
回复
但是我觉得主要因素还是分值,因为我把防守分打的很高,这样等于告诉程序,要多让对手进攻,以便得到更多的防守分!!
但是不把防守打高一些,他又不知道防守了。
zyj_vc 2001-06-07
  • 打赏
  • 举报
回复
我觉得取五个最高分太少,后面下出匪夷所思的棋和这个有关系,可以考虑多选几个点,反正太差的点会被剪枝,不过那些点最好按分数排好序,这样剪枝的效率会高一点。我觉得直接用alpha-beta剪枝算法就可以了,据文献,这个算法可以搜索16-18步,我想这样应该很厉害了,如果还想好一点,可以考虑MPC,就是所谓的多重概率剪枝算法,据说可以搜索26-28步,要的话我可以给你发一份,我也在编五子棋的程序,我们多交流吧。我的程序有个最大的问题,匹配这些规则都很慢,愿意听听你的高见。
zsj2001year 2001-06-03
  • 打赏
  • 举报
回复
将连棋的美中可能赋予分值即可有空位的分低连位的分值高
2^n(n空格数)
natrium11 2001-06-03
  • 打赏
  • 举报
回复
对对,用深优确实如此(exactly),但用我上面说的广优,每次取最高的几个分数往下作,十几层也是很快的。
NowCan 2001-06-03
  • 打赏
  • 举报
回复
写五子棋的难度很大的。我曾经想写的,但是没写完。
NowCan 2001-06-03
  • 打赏
  • 举报
回复
深度3层已经可以了,4层的话速度难以忍受。
natrium11 2001-06-03
  • 打赏
  • 举报
回复
To zsj2001year(杰):
两连、三连、四连、五连各赋多少?不考虑防守吗?
natrium11 2001-06-02
  • 打赏
  • 举报
回复
呜呼,哀哉!!
natrium11 2001-06-01
  • 打赏
  • 举报
回复
另外搜索深度取几层比较好?
广优的话取最高的几个分值?
natrium11 2001-06-01
  • 打赏
  • 举报
回复
我推,没人知道吗??
natrium11 2001-06-01
  • 打赏
  • 举报
回复
我推,没人知道吗??
natrium11 2001-06-01
  • 打赏
  • 举报
回复
natrium11 2001-06-01
  • 打赏
  • 举报
回复
To tpu:
对棋型如何打分呢?深度又视什么情况而定呢?时间吗?
tpu 2001-06-01
  • 打赏
  • 举报
回复
我的方法是,给棋盘上的每一个棋型一个分值,其中黑棋为正数,白棋为负数,然后将它们加起来,作为当前棋局的估值.这个值大,对黑棋就有利。反之,对白棋有利。搜索时就依此为依据。
关于搜索的深度,我有个想法,深度可以不固定,完全视情况而定。
gzpbx 2001-06-01
  • 打赏
  • 举报
回复
多试试就知道了!

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧