人工智能实习报告(--)
温柔似野鬼°
646次浏览
2021年01月18日 14:55
最佳经验
本文由作者推荐
dhcp服务器配置-放假通知怎么写
人
工
智
能
课
程
设
计
报
告
姓名:
班级:
191092
学号:
2009100
指导老师:
2011
年
10
月
人工智能课程设计
序
言
经过近一周的奋战,我终于初步实现了我的“四子棋”游戏。起初,我选
择这个游戏是因为它很独特、
少有人做,
而且我想当然的认为四子比五子少一子,
实现起来应该相对简单,
但是面对一个个头疼的错误,
遭受一次又一次失败的打
击,我才发现自己想错了,四子棋人机对 战比五子棋更让人纠结。
暑期我和班上两名同学
xxx,xx
一 起完成过五子棋和黑白棋的编程。当时,
五子棋我们是参照别人的模板完成的,
黑白棋是在透彻 研究过五子棋的基础上不
断讨论、优化算法最终完成的。现在,他们一个继续做五子棋一个做黑白棋,将
其完善作为人工智能的课程设计课题。我只得另陌新路,关注起了四子棋。
界面的搭建以及二人对战的实现只用了我两个晚上的时间,当然我的界面
构建的相对简单。二人对战实 现关键一步就是输赢判断函数
judge
()的编写。
人机对战整整折腾了自己四五天 的时间,我本来对于博弈过程中
alpha
—
beta
剪
枝算法很理 解的,
但是具体要自己编程实现时我觉得自己只了解到其皮毛。
所以,
我不断看五子棋 程序、
单步跟踪、
寻问同学,
终于算是把其递归和剪枝过程搞得
明明白白。< br>
花了两天完成了
alpha
—
beta
剪枝算法 我本以为核心都解决了,却不知更让
人头疼的是评估函数的确定还有统计当前棋局状况的函数
C alculate
()的编写。
难题终究是可以被客服的,我花了整整一天写完了我的
Calculate
()函数。
直至
10
月
2 7
日上午我依然没有让机器足够智能,或者说它目前很呆板。
我一直在找原因,
自己的 模块设计算法思路都是对的,
请教过同学她也觉得设计
思路没有错。
现在,
我 整体的想了一下,
觉得应该是我的静态评估函数设计的不
够合理,
或者说目前的设计方 法对于五子棋很合理但是对于规则不同的四子棋就
可能存在缺陷。
既然目前时间不允许没能实现 足够智能,
那就只能把这粗略的程
序提交。我一定会继续完善、改进算法,重新设计评估函数, 争取让机器达到理
想的“智能”
。
2
191092
班—
xx
人工智能课程设计
一、课题选则
1.
题目概述
利用
VC++实现四子棋游戏,
要求提供可视化界面以及二人对战、
人机对战的功能。
四子棋游 戏规则如下:
四子棋的棋盘共有
7
行
7
列,
棋盘 是垂直摆放,
每名玩者只能左右控制落子的位置。
两名玩者轮流每次把一只棋子放进棋盘任何未 全满的一行中,
棋子会佔据一行中最底未
被佔据的位置。
两名玩者任何一方先以四只棋 子在横,
竖或斜方向联成一条直线,
便可
获胜,
游戏亦结束。
假如棋 盘已完全被棋子填满,
但仍未有任何一方成功把四只棋子成
一直线,则成为和局。
2.
选题缘由
四子棋游戏规则独特,所以其规则的设计将有别于五子棋等通常的棋类游戏。
四子棋人机对战功能的实现需要用到博弈树搜索中的核心算法:
。
与五子棋 不同,
因为四子棋的独特性网络中根本没有某某
“热心”
网友的游戏源码,
我 找了很久也只找到一个二人对战的四子棋,他还是用
C
语言在
dos
下实现的 ,一点
也不人性化。
综合以上种种我决定挑战一下自己,用
VC
实现“我的四子棋”游戏。
二、需求分析
1.
功能需求
1.1
提供合理的人机交互界面
1.2
提供二人对战功能
1.3
提供人机对战功能
2.
数据结构
2.1
棋盘数据采用一二维数组
grid[7][7]
存储
三、模块设计
A.
整体思路
通过对需求的分析,
我认为我的设计工作主要可以分为三大块,
第一块是主界面的
搭建和棋盘的绘制,
第 二块是落子和输赢判断的实现,
第三块就是二人对战和人机对战
的实现。
对 于第一块,
因为有图形学和图像处理的上机经验,
我将果断的选择单文档作为界
面窗口 ,用绘制的方式搭建棋盘。
对于第二块,
对于落子其实就是在响应鼠标左键按下的消 息后记录下所需放子的坐
标,然后改变内部存储数据,调用绘图函数
ondraw
() 进行绘制。输赢判断就是对于
每下一颗棋子搜索其横向竖向交叉斜向的棋子,如若有四颗连成一线的就判 为赢。
对于第三模块,
这是整个游戏的核心,
二人对战相对好实现。
人机对战需要用到博
弈树搜索需要用到
alphabeta
剪枝算法,还需要设定以 静态评估函数,这两方面是最困
难也是最重要的部分。
B.
具体设计
1.
主界面设计
1.1
单文档窗口大小的限定
我们知道通过
VC++
工程创建的单文档都有默认的大小,
那个大小太大不适合
作为游戏的界面窗口大小。
所以我希望自定义其大小,
而且在此游戏中不需要用工
具栏,所以我希望通过人为操作去掉工具栏。
具体实现:
在
Frame
框架类里面的
PreCreateWindow( )
创建窗口函数总添加以下代码
3
191092
班—
xx
人工智能课程设计
&=~WS_MAXIMIZEBOX;
//
禁止对文档最大化操作
&=~WS_THICKFRAME;
=700;/
/
自定义文档大小
=500;
cs.y=180;
cs.x=300;
&=~FWS_A DDTOTITLE;//
将
FWS_ADDTOTITLE
去掉
me=
我的四子棋
//
改变文档标题
将
OnCreate(LPCREATESTRUCT lpCreateStruct)
函数中以下代码屏蔽即可去掉工具栏
/*if (!m_Ex(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
{
}*/
TRACE0(
return -1;
// fail to create
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_olBar(IDR_MAINFRAME))
1.2
棋盘绘制
< br>棋盘绘制在
view
类里面的
ondraw
函数里实现,创建画笔蓝色 画笔通过
MoveTo
、
LineTo
函数画出棋格,创建天蓝色画刷绘制棋 格背景色。创建红色、黄
色画刷用于绘制双方棋手棋子。
具体代码如下:
CRect rect;
CBrush *brush,*brush1,*brush2,*brush3;
brush = new CBrush;
brush1 = new CBrush;
brush2 = new CBrush;
brush3 = new CBrush;
brush->CreateSolidBrush(RGB(150, 205 ,205));
brush1->CreateSolidBrush(RGB(255, 0 ,0));//
红色画刷
brush2->CreateSolidBrush(RGB(255, 255 ,0));//
黄色画刷
brush3->CreateSolidBrush(RGB(128, 128 ,28));//bai
色画刷
this->GetClientRect(&rect);
pDC->FillRect(&rect,brush);
CClientDC dc(this);
CPen m_pen(PS_SOLID,1,RGB(0,0,255));
//
将画笔选入设备列表
CPen *pOldPen = Object(&m_pen);
int i;
for(i=0;i<8;i++)
{
(bx,by+width*i);
(bx+width*7,by+width*i);
}
for(i=0;i<8;i++)
{
(bx+width*i,by);
(bx+width*i,by+width*7);
}
for (i=0;i<7;i++)
{
for (int j=0;j<7;j++)
{
4
191092
班—
xx
人工智能课程设计
switch(grid[i][j])
{
case 1:
pDC->SelectObject(brush1);
pDC->E llipse(bx+width*(i+0.5)-r,by+width*(j+0.5)
-r,bx+width*(i+0.5)+r,by+width*(j+0.5)+r);
break;
case 2:
//pDC->SelectStockObject(WHITE_PEN);
pDC->SelectObject(brush2);
pDC->Ellipse(bx+width*(i+0.5)-r,by+w idth*(j+0.5)-r,bx+width*(i+0.5)+r,by+widt
h*(j+ 0.5)+r);
//pDC->SelectStockObject(BLACK_PEN);
break;
case 3:
pDC->SelectObject(brush3);
pDC->Ellipse(bx+width*(i+0 .5)-(r+5),by+width*(j+0.5)-(r+5),bx+width*(i+0.5)+ (
r+5),by+width*(j+0.5)+(r+5));
break;
default:
break;
}
}
}
2.
模式选择设计
2.1
更改菜单按钮
在菜单栏中添加模式按钮“二人对战”和“人机对战”
2.2
响应选择按钮消息
通过
MFC
类向导在
V iew
类中响应“二人对战”和“人机对战”的按钮消息,
实现方式如下:
void CMYSIZIQIView::OnPvsp()
{
// TODO: Add your command handler code here
reset();
pvsp=true;
Invalidate();//
是当前窗口无效,需要重绘
}
void CMYSIZIQIView::OnPvsc()
{
// TODO: Add your command handler code here
reset();
pvsc=true;
RorY=true;
pvsp=false;
Invalidate();//
是当前窗口无效,需要重绘
}
buttondown
()函数设计
3.1
根据鼠标坐标转换出在存储数组中对应的下标
5
191092
班—
xx
人工智能课程设计
int px=(point.x-bx)/width;
int py=(point.y-by)/width;
3.2
限定落子只可以在该列最下面一个空格
for(int j=6;j>=0;j--)
{
if(grid[px][j]==0)
{
py=j;
break;
}
}
3.3
二人对战、人机对战程序响应
if(0<=px&&px<7&&0<=py&&py<7&&grid[px][py]==0)
{
if(!pvsp&&!pvsc) MessageBox(
请选择对战模式
else if(pvsp)
//
二人对战
{
grid[px][py]=c;//
根据该点颜色选择对应的画笔
color=!color;//
换位另一颜色
< br>t(point.x-8*width,point.y-8*width,point.x+8*wid th,point.y+8*width);
InvalidateRect(&r);
judge(c,px,py);//
判断有没有取胜
}
else if (pvsc)
//
人机对战模式
{
color=!color;
if (!judge(c,px,py)) // if player doesn't win
{
alphabeta(LONG_MIN,LONG_MAX,depth,false); //computer puts the
color=!color;
InvalidateRect(&r);
judge(c,bestmove[0],bestmove[1]);
}
}
}
()函数设计
4.0
每一个方向定义一个变量用以记录当前棋子个数:
HWIN
——横方向
SWIN
——竖方向
LRWIN
——左上右下方向
RLWIN
——右上左下方向
4.1
横向判断是否四子连线
int HWIN=1;
for ( i=x-1;i>=0;i--)//&&&&&&&&&
棋子左边
{
//MessageBox(
红赢
if(grid[i][y]==color) HWIN++;
6
191092
班—
xx
人工智能课程设计
if(grid[i][y]!=color) break;
}
if(HWIN>=4&&color==1)//
{
左边可能已经三个棋子
for ( i=x-1;i>=0;i--)//
if(grid[i][y]==color)
一方赢了则改变其颜色
{
grid[i][y]=3;
}
grid[x][y]=3;
MessageBox(
红赢
reset();
Invalidate();
}
return true;
else if (HWIN>=4&&color==2)
{
for ( i=x-1;i>=0;i--)//
if(grid[i][y]==color)
一方赢了则改变其颜色
{
grid[i][y]=3;
grid[x][y]=3;
}
MessageBox(
黄赢
reset();
Invalidate();
t0=HWIN;
}
return true;
for (i=x+1;i<=6;i++)//&&&&&&&&&&&&
{
棋子右边
//MessageBox(
红赢
if(grid[i][y]==color) HWIN++;
}
if(grid[i][y]!=color) break;
if(HWIN>=4&&color==1)
{
for ( i=x+1;i<=6;i++)//
if(grid[i][y]==color)
一方赢了则改变其颜色
{
grid[i][y]=3;
}
grid[x][y]=3;
if(HWIN-t0==2) grid[x-1][y]=3;
if(HWIN-t0==1) {grid[x-1][y]=3;grid[x-2][y]=3;}
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (HWIN>=4&&color==2)
{
for ( i=x+1;i<=6;i++)//
一方赢了则改变其颜色
if(grid[i][y]==color)
{
grid[i][y]=3;
}
grid[x][y]=3;
if(HWIN-t0==2) grid[x-1][y]=3;
if(HWIN-t0==1) {grid[x-1][y]=3;grid[x-2][y]=3;}
7
班—
xx
191092
人工智能课程设计
MessageBox(
黄赢
reset();
Invalidate();
return true;
}
具体判断细节见注释
4.2
竖向判断是否四子连线
//****************** *****
竖向判断
***************************//
int SWIN=1;
for ( j=y+1;j<=6;j++)//&&&&&&&&&
棋子下边
{
//MessageBox(
红赢
if(grid[x][j]==color) SWIN++;
if(grid[x][j]!=color) break;
}
if(SWIN>=4&&color==1)//
下边可能已经三个棋子
{
for (j=y+1;j<=6;j++)//
一方赢了则改变其颜色
if(grid[x][j]==color&&j-y<=3)
{
grid[x][j]=3;
}
grid[x][y]=3;
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (SWIN>=4&&color==2)
{
for (j=y+1;j<=6;j++)//
一方赢了则改变其颜色
if(grid[x][j]==color&&j-y<=3)
{
grid[x][j]=3;
}
grid[x][y]=3;
MessageBox(
黄赢
reset();
Invalidate();
return true;
}
具体判断细节见注释
4.3
左上右下方向判断是否四子连线
//**********************
左上右下方向
*** **********************//
int LRWIN=1;
for (i=x-1,j=y-1;i>=0&&j>=0 ;i--,j--)//&&&&&&&&&
棋子左上方
{
//MessageBox(
红赢
if(grid[i][j]==color) LRWIN++;
if(grid[i][j]!=color) break;
}
if(LRWIN>=4&&color==1)//
左上可能已经三个棋子
{
for (i=x-1,j=y-1;i>=0&&j>=0;i--,j--) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(y-j<=3))
{
grid[i][j]=3;
}
grid[x][y]=3;
8
191092
班—
xx
人工智能课程设计
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (LRWIN>=4&&color==2)
{
for (i=x-1,j=y-1;i>=0&&j>=0;i--,j--) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(y-j<=3))
{
grid[i][j]=3;
}
grid[x][y]=3;
MessageBox(
黄赢
reset();
Invalidate();
return true;
}
t0=LRWIN;
for (i=x+1,j=y+1;i<=6&&j<=6;i++,j++)//&&&&&&&& &&&&
棋子右下边
{
if(grid[i][j]==color) LRWIN++;
if(grid[i][j]!=color) break;
}
if(LRWIN>=4&&color==1)
{
for (i=x+1,j=y+1;i<=6&&j<=6;i++,j++) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(j-y)<=3)
{
grid[i][j]=3;
}
grid[x][y]=3;
if(LRWIN-t0==2) grid[x-1][y-1]=3;
if(LRWIN-t0==1) {grid[x-1][y-1]=3;grid[x-2][y-2]=3;}
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (LRWIN>=4&&color==2)
{
for (i=x+1,j=y+1;i<=6&&j<=6;i++,j++) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(j-y)<=3)
{
grid[i][j]=3;
}
grid[x][y]=3;
if(LRWIN-t0==2) grid[x-1][y-1]=3;
if(LRWIN-t0==1) {grid[x-1][y-1]=3;grid[x-2][y-2]=3;}
MessageBox(
黄赢
reset();
Invalidate();
return true;
}
具体判断细节见注释
4.4
右上左下方向判断是否四子连线
//********* **************
右上左下方向
********************** ****//
int RLWIN=1;
for (i=x+1,j=y-1;i<=6&&j>=0;i++,j--)//&&&&&&&& &
棋子右上方
{
9
191092
班—
xx
人工智能课程设计
if(grid[i][j]==color) RLWIN++;
if(grid[i][j]!=color) break;
}
if(RLWIN>=4&&color==1)//
可能已经三个棋子
{
for (i=x+1,j=y-1;i<=6&&j>=0;i++,j--) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(y-j<=3))
{
grid[i][j]=3;
}
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (RLWIN>=4&&color==2)
{
for (i=x+1,j=y-1;i<=6&&j>=0;i++,j--) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(y-j<=3))
{
grid[i][j]=3;
}
grid[x][y]=3;
MessageBox(
黄赢
reset();
Invalidate();
return true;
}
t0=RLWIN;
for (i=x-1,j=y+1; i>=0&&j<=6;i--,j++)//&&&&&&&&&&&&
棋子左下边
{
if(grid[i][j]==color) RLWIN++;
if(grid[i][j]!=color) break;
}
if(RLWIN>=4&&color==1)
{
for (i=x-1,j=y+1;i>=0&&j<=6;i--,j++) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(j-y<=3))
{
grid[i][j]=3;
}
grid[x][y]=3;
if(RLWIN-t0==2) grid[x+1][y-1]=3;
if(RLWIN-t0==1) {grid[x+1][y-1]=3;grid[x+2][y-2]=3;}
MessageBox(
红赢
reset();
Invalidate();
return true;
}
else if (RLWIN>=4&&color==2)
{
for (i=x-1,j=y+1;i>=0&&j<=6;i--,j++) //
一方赢了则改变其颜色
if(grid[i][j]==color&&(j-y<=3))
{
grid[i][j]=3;
}
grid[x][y]=3;
if(RLWIN-t0==2) grid[x+1][y-1]=3;
if(RLWIN-t0==1) {grid[x+1][y-1]=3;grid[x+2][y-2]=3;}
MessageBox(
黄赢
reset();
Invalidate();
10
191092
班—
xx
人工智能课程设计
return true;
}
具体判断细节见注释
()函数设计
该函数很简单,即是将数组存储空间归零化。
起作用就是让二人对战、
人机对战函
数调用,达到初 始化数据的目的:
for (int i=0;i<7;i++)
for (int j=0;j<7;j++)
grid[i][j]=0;
eta
()函数设计
6.1
极大极小值分析法
6.1.1
其基本思想或算法是:
(1)
设博弈的 双方中一方为
MAX
,另一方为
MIN
。然后为其中的一方
(
例如
MAX)
寻
找一个最优行动方案。
(2)
为了找到当前的最优行动方案,
需要对各个可能的方案所产生的后果进行比较
,
具体地说,就是要考虑每一方案实施后对方可能采取的所有行动,并计算可能得
(3)
为计算得分,
需要根据问题的特性信息定义一个估价函数,
用来估算当前博弈
树端节点的得分。此时估算出来的得分称为静态估值。
(4)
当端节点的估值计算出来后,
再推算出父节点的得分,
推算的方法是:
对“或”
节点,
选其子节点中一个最大的得分作为父节点的得分,
这是为 了使自己在可供选
择的方案中选一个对自己最有利的方案;
对“与”节点,选其子节点中一个最小的
< br>得分作为父节点的得分,
这是为了立足于最坏的情况。
这样计算出的父节点的得分
称为倒推值
(5)
如果一个行动方案能获得较大的倒推值,则它就是当前最好的行动方案。
6.2
α
-
β
剪枝技术
6.2.1
算法思想:
int AlphaBeta(int depth, int alpha, int beta)
{
if (depth == 0)//
叶子节点;
return Evaluate();//
返回当前盘面的估值;
GenerateLegalMoves();//
产生所有合理走法;
while (MovesLeft()) {//
如果还有未分析的走法;
MakeNextMove();//
试走一步;
val = -AlphaBeta(depth - 1, -beta, -alpha);//
返回当前节点
//
的估值,加负号是为了消除双方的差别,使程序简洁;
UnmakeMove();//
退回到没走前的状态;
if (val > = beta)//
剪枝;
return beta;
if (val > alpha)//
存当前值;
alpha = val;
}
return alpha;//
返回当前值;
}
6.2.2
关键点与具体设计:
alphabeta
()函数设计的关键点 包括递归调用、剪枝操作。其中递归的深度由参数
11
191092
班—
xx
人工智能课程设计
depth< br>限定,剪枝操作跟递归返回的
evalue
评估函数值息息相关。
long CMYSIZIQIView::alphabeta(long alpha,long beta,int d,bool m)
{
int i,j;
if(d==0)
//the depth of search is enough
return evalue();
for(i=0;i<7;i++)
//search for the blank
{
for(j=0;j<7;j++)
if(grid[i][j]==0)
break;
if(grid[i][j]==0)
break;
}
if(i==7&&j==7)
//no place to move
return evalue();
long a=alpha,b=beta;
long current,best;
bool first=true,choose=!m;
//choose--to decide the layer,max or min
int set_color;
for(i=0;i<=6;i++)
for (j=6;j>=0;j--)//
怎么限制只找一个
?????????? ?????????????????
{
if(grid[i][j]!=0)
continue;
set_color=(RorY==true&&choose==true||RorY==fal se&&choose==false)?1:2;
grid[i][j]=set_color;
memset(sttblack,0,sizeof(sttblack));
memset(sttwhite,0,sizeof(sttwhite));
Calculate(false,sttblack[0],sttblack[1],sttbla ck[2],sttblack[3],sttblack[4],sttblack[5],sttbl
ack[6]);//
分别计算当前状态
Calculate(true,sttwhite[0],sttwhite[ 1],sttwhite[2],sttwhite[3],sttwhite[4],sttwhite[5] ,sttwhite[6
]);
current=alphabeta(a,b,d-1,choose);
grid[i][j]=0;
memset(sttblack,0,sizeof(sttblack));
memset(sttwhite,0,sizeof(sttwhite));
Calculate(false,sttblack[0],sttblack[1],sttbla ck[2],sttblack[3],sttblack[4],sttblack[5],
sttb lack[6]);//
分别计算当前状态
Cal culate(true,sttwhite[0],sttwhite[1],sttwhite[2],st twhite[3],sttwhite[4],sttwhite[5],sttw
hite[6]) ;
if(first)
{
best=current;
first=false;
if(d==depth)
{
bestmove[0]=i;
bestmove[1]=j;
}
}
if(choose)
//MAX
NODE
{
if(current>=b)
//beta cut
return current;
if(best
{
best=current;
a=current;
if(d==depth)
{
bestmove[0]=i;
12
191092
班—
xx
人工智能课程设计
bestmove[1]=j;
}
}
}else{
//MIN
NODE
if(current<=a)
//alpha cut
return current;
if(best>current)
{
best=current;
b=current;
if(d==depth)
{
bestmove[0]=i;
bestmove[1]=j;
}
}
}
break;
}
if(d==depth)
{
return 1;
}
return best;
}
ate( )
函数设计
7.1
该函数主要是统计当前棋局的状态,包括一个棋子一边被 堵
d1c
、一个棋子两
边都没被堵
a1c
、两个棋子连在一起一边被 堵
d2c
、两个棋子连在一起两边都未堵堵
d2c
„„
7.2
可以从横竖左斜右斜四个方面分析统计
例如横着方向实现如下:
//************************
横着方向
*************************//
for (y=6;y>=0;y--)
{
for(x=0;x<=6;x++)
{
if(grid[x][y]==c)
{
if(x==0)//
左边边界
for (i=x+1;i<=6;i++)
{
if(grid[i][y]==c) continue;
if(grid[i][y]==c0) break;
if(grid[i][y]==0)
{
if(i-x==1) d1c++;
if(i-x==2) d2c++;
if(i-x==3) d3c++;
if(i-x==4) d4c++;
break;
}
}
13
191092
班—
xx
人工智能课程设计
else if(x!=0&&x<6)//
左右都不是边界
{
for (i=x+1;i<=6;i++)
{
if(grid[i][y]==c) continue;
if(grid[i][y]==c0) //
右边为对手
{
if(grid[x-1][y]==0)
{
if(i-x==1) d1c++;
if(i-x==2) d2c++;
if(i-x==3) d3c++;
if(i-x==4) d4c++;
break;
}
else break;
}
if(grid[i][y]==0)//
右边为
0
{
if(grid[x-1][y]==0)//
在右边为
0
左边为
0
{
if(i-x==1) a1c++;
if(i-x==2) a2c++;
if(i-x==3) a3c++;
if(i-x==4) d4c++;
break;
}
else if(grid[x-1][y]==c0)//
在右边为
0
左边为对手
{if(i-x==1) d1c++;
if(i-x==2) d2c++;
if(i-x==3) d3c++;
if(i-x==4) d4c++;
break;
}
}
}
}
else if(x==6)
{
if (grid[x-1][y]==c0)break;
else
d1c++;break;
}
x=i;
14
191092
班—
xx
人工智能课程设计
}
}
}
()函数设计
所谓评估函 数,就是要建立一个函数,对棋盘上每一个空点进行计算,得出哪个点才
是最优的。这是一个看似简单, 其实很难的问题。
参照五子棋评估函数,我将棋局分类如下:活一、死一、活二、死二、活三 、死三、
死四。活二是指当前棋局两个子连在一起且两端都是活路的总数,死二是指当前棋局两个
子连在一起且有一端是死路的总数,以此类推。
然后给每种棋型一个权重,棋型乘以权重加 和的结果就是棋型的分数。我的权重分配
改变过很多次,目前依然没找到最合理的分配。
#define
FOUR
20000000
#define
ALIVE_3
1000000
#define
DEAD_3
10000
#define
ALIVE_2
8000
#define
DEAD_2
50
#define
ALIVE_1
30
#define
DEAD_1
10
评估函数如下:
long CMYSIZIQIView::evalue()
{
long
value=sttblack[0]*FOUR+sttblack[1]* ALIVE_3+sttblack[2]*DEAD_3
+sttblack[3]*ALIVE_2+sttblack[4]*DEAD_2+s ttblack[5]*ALIVE_1
+sttblack[6]*DEAD_1
-sttwhite[0]*FOUR- sttwhite[1]*ALIVE_3-sttwhite[2]*DEAD_3
-sttwhite[3]*ALIVE_2-sttwhite[4 ]*DEAD_2-sttwhite[5]*ALIVE_1
-sttwhite[6]*DEAD_1;
//
if(bkorwt)
value=value*(-1);
return value;
}
四、调试分析
1.
界面调试
1.1
棋盘背景和区域绘制出错
15
191092
班—
xx
人工智能课程设计
分析出错原因:
我在
opaint
函数中画线在
ondraw
函数中画背景,由于
opaint
函数会先
调用
ondraw
函数,所以画完再画棋格原来的背景被刷新了。
棋格绘制出错原因很简单,
范围限制的不正确,
再次计算做了调整棋盘显示正常如
下:
1.2
刷新函数出错
16
191092
班—
xx