
你还要掌握一些 Linux C编程的一些图形函数,
像 画直线,一些的函数,基本都没什么差别,都和
windows 的差不多.
其实鼠标没有控制什么,只是计算机鼠标的位置,然后画图而已.
五子棋的核心算法五子棋是一种受大众广泛喜爱的游戏,其规则简单,变化多端,非常富有趣味性和消遣性。这里设计和实现了一个人机对下的五子棋程序,采用了博弈树的方法,应用了剪枝和最大最小树原理进行搜索发现最好的下子位置。介绍五子棋程序的数据结构、评分规则、胜负判断方法和搜索算法过程。
一、相关的数据结构
关于盘面情况的表示,以链表形式表示当前盘面的情况,目的是可以允许用户进行悔棋、回退等 *** 作。
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=0ivalue=Search(pBoard,min,value,0)
Value=Select(value,pBoard->value,max)
//取value和pBoard->value中大的赋给根节点
}
for(i=0ivalue)
//找出那一个得到最高分的盘面
{
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++实现了这个人机对战的五子棋程序。和国内许多只是采用规则或者只是采用简单递归而没有剪枝的那些程序相比,在智力上和时间有效性上都要好于这些程序。同时所讨论的方法和设计过程为用户设计其他的游戏(如象棋和围棋等)提供了一个参考。
参考资料:http://www.3800hk.com/Article/cxsj/vc/jdsfvc/2005-08-06/Article_33695.html
五子棋C语言代码如下:#include <stdio.h>
#include <bios.h>
#include <ctype.h>
#include <conio.h>
#include <dos.h>
#define CROSSRU 0xbf /*右上角点*/
#define CROSSLU 0xda /*左上角点*/
#define CROSSLD 0xc0 /*左下角点*/
#define CROSSRD 0xd9 /*右下角点*/
#define CROSSL 0xc3 /*左边*/
#define CROSSR 0xb4 /*右边*/
#define CROSSU 0xc2 /*上边*/
#define CROSSD 0xc1 /*下边*/
#define CROSS 0xc5 /*十字交叉点*/
/*定义棋盘左上角点在屏幕上的位置*/
#define MAPXOFT 5
#define MAPYOFT 2
/*定义1号玩家的 *** 作键键码*/
#define PLAY1UP 0x1157/*上移--'W'*/
#define PLAY1DOWN 0x1f53/*下移--'S'*/
#define PLAY1LEFT 0x1e41/*左移--'A'*/
#define PLAY1RIGHT 0x2044/*右移--'D'*/
#define PLAY1DO 0x3920/*落子--空格键*/
/*定义2号玩家的 *** 作键键码*/
#define PLAY2UP 0x4800/*上移--方向键up*/
#define PLAY2DOWN 0x5000/*下移--方向键down*/
#define PLAY2LEFT 0x4b00/*左移--方向键left*/
#define PLAY2RIGHT 0x4d00/*右移--方向键right*/
#define PLAY2DO 0x1c0d/*落子--回车键Enter*/
/*若想在游戏中途退出, 可按 Esc 键*/
#define ESCAPE 0x011b
/*定义棋盘上交叉点的状态, 即该点有无棋子 */
/*若有棋子, 还应能指出是哪个玩家的棋子 */
#define CHESSNULL 0 /*没有棋子*/
#define CHESS1 'O'/*一号玩家的棋子*/
#define CHESS2 'X'/*二号玩家的棋子*/
/*定义按键类别*/
#define KEYEX99v 0/*退出键*/
#define KEYFALLCHESS 1/*落子键*/
#define KEYMOVECURSOR 2/*光标移动键*/
#define KEYINVALID 3/*无效键*/
/*定义符号常量: 真, 假 --- 真为1, 假为0 */
#define TRUE 1
#define FALSE 0
/**********************************************************/
/* 定义数据结构 */
/*棋盘交叉点坐标的数据结构*/
struct point
{
int x,y
}
或者下面这个:
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#define N 15
#define B 7
#define STOP -10000
#define OK 1
#define NO 0
#define UP 328
#define DOWN 336
#define LEFT 331
#define RIGHT 333
int a[N+1][N+1]
int zx,zy
int write=1,biaoji=0
struct zn{
long sum
int y
int x
}w[N+1][N+1],max,max1
void cbar(int i,int x,int y,int r)
void map(int a[][])
int getkey()
int key()
void zuobiao(int x,int y,int i)
int tu(int a[][],int write)
int wtu(int a[][],int write)
int zhineng(int a[][])
int zh5(int y,int x,int a[][])
long zzh5(int b[][],int i)
main()
{
int i,j
int gdriver=DETECT
int gmode
initgraph(&gdriver,&gmode,"")
zx=(N+1)/2
zy=(N+1)/2
for(i=1i<=Ni++)
for(j=1j<=Nj++)
a[i][j]=0
map(a)
i=1
while(i)
{
int k,n
k=wtu(a,write)
if(k==STOP) goto end
map(a)
n=zhineng(a)
if(n==STOP) goto end
map(a)
}
end:
}
int zhineng(int a[N+1][N+1])
{
int i,j
int k
max.sum=-1
for(i=0i<=Ni++)
for(j=0j<+Nj++)
{
w[i][j].sum=0
w[i][j].x=i
w[i][j].y=j
}
for(i=1i<=N-4i++)
for(j=1j<=N-4j++)
{
k=zh5(i,j,a)
if(k==STOP) return (STOP)
}
for(i=1i<=Ni++)
for(j=1j<=Nj++)
{
if(max.sum<w[i][j].sum)
{
max.sum=w[i][j].sum
max.y=i
max.x=j
}
else if(max.sum==w[i][j].sum)
{
if(((max.y-zy)*(max.y-zy)+(max.x-zx)*(max.x-zx))>((i-zy)*(i-zy)+(j-zx)*(j-zx)))
max.sum=w[i][j].sum
max.y=i
max.x=j
}
}
if(a[max.y][max.x]==0)
{
a[max.y][max.x]=-1
zy=max.y
zx=max.x
}
}
int zh5(int y,int x,int a[N+1][N+1])
{
int i,j
int b[6][6]
long c[13]
long d[6][6]
long temp
for(i=yi<=y+4i++)
for(j=xj<=x+4j++)
b[i+1-y][j+1-x]=a[i][j]
c[1]=b[1][1]+b[1][2]+b[1][3]+b[1][4]+b[1][5]
c[2]=b[2][1]+b[2][2]+b[2][3]+b[2][4]+b[2][5]
c[3]=b[3][1]+b[3][2]+b[3][3]+b[3][4]+b[3][5]
c[4]=b[4][1]+b[4][2]+b[4][3]+b[4][4]+b[4][5]
c[5]=b[5][1]+b[5][2]+b[5][3]+b[5][4]+b[5][5]
c[6]=b[1][1]+b[2][1]+b[3][1]+b[4][1]+b[5][1]
c[7]=b[1][2]+b[2][2]+b[3][2]+b[4][2]+b[5][2]
c[8]=b[1][3]+b[2][3]+b[3][3]+b[4][3]+b[5][3]
c[9]=b[1][4]+b[2][4]+b[3][4]+b[4][4]+b[5][4]
c[10]=b[1][5]+b[2][5]+b[3][5]+b[4][5]+b[5][5]
c[11]=b[1][1]+b[2][2]+b[3][3]+b[4][4]+b[5][5]
c[12]=b[1][5]+b[2][4]+b[3][3]+b[4][2]+b[5][1]
for(i=1i<=12i++)
{
switch(c[i])
{
case 5:biaoji=1return(STOP)
case -5:biaoji=-1return(STOP)
case -4:c[i]=100000break
case 4:c[i]=100000break
case -3:c[i]=150break
case 3:c[i]=150break
case -2:c[i]=120break
case 2:c[i]=100break
case -1:c[i]=1break
case 1:c[i]=1break
default: c[i]=0
}
}
for(i=1i<=12i++)
{
if(c[i]==150)
c[i]+=zzh5(b,i)
}
for(i=1i<=5i++)
for(j=1j<=5j++)
d[i][j]=0
for(i=1i<=5i++)
for(j=1j<=5j++)
{
if(i==j) d[i][j]+=c[11]
if((i+j)==6) d[i][j]+=c[12]
d[i][j]+=c[i]+c[j+5]
}
for(i=1i<=5i++)
for(j=1j<=5j++)
{
if(b[i][j]!=0)
d[i][j]=-2
}
max1.sum=-1
max1.y=0
max1.x=0
for(i=1i<=5i++)
for(j=1j<=5j++)
{
if(max1.sum<d[i][j])
{
max1.sum=d[i][j]
max1.y=i
max1.x=j
w[i+y-1][j+x-1].sum+=max1.sum
}
else if(max1.sum==d[i][j])
{
if(((i+y-1-zy)*(i+y-1-zy)+(j+x-1-zx)*(j+x-1-zx))>((max1.y+y-1-zy)*(max1.y+y-1-zy)+(max1.x+x-1-zx)*(max1.x+x-1-zx)))
{
max1.sum=d[i][j]
max1.y=i
max1.x=j
}
}
}
}
long zzh5(int b[6][6],int n)
{
int i,j,k,l,m
switch(n)
{
case 1:i=b[1][1]j=b[1][2]k=b[1][3]l=b[1][4]m=b[1][5]break
case 2:i=b[2][1]j=b[2][2]k=b[2][3]l=b[2][4]m=b[2][5]break
case 3:i=b[3][1]j=b[3][2]k=b[3][3]l=b[3][4]m=b[3][5]break
case 4:i=b[4][1]j=b[4][2]k=b[4][3]l=b[4][4]m=b[4][5]break
case 5:i=b[5][1]j=b[5][2]k=b[5][3]l=b[5][4]m=b[5][5]break
case 6:i=b[1][1]j=b[2][1]k=b[3][1]l=b[4][1]m=b[5][1]break
case 7:i=b[1][2]j=b[2][2]k=b[3][2]l=b[4][2]m=b[5][2]break
case 8:i=b[1][3]j=b[2][3]k=b[3][3]l=b[4][3]m=b[5][3]break
case 9:i=b[1][4]j=b[2][4]k=b[3][4]l=b[4][4]m=b[5][4]break
case 10:i=b[1][5]j=b[2][5]k=b[3][5]l=b[4][5]m=b[5][5]break
case 11:i=b[1][1]j=b[2][2]k=b[3][3]l=b[4][4]m=b[5][5]break
case 12:i=b[1][5]j=b[2][4]k=b[3][3]l=b[4][2]m=b[5][1]break
}
if((i==0&&j==1&&k==1&&l==1&&m==0))
return (900)
if((i==0&&j==-1&&k==-1&&l==-1&&m==0))
return(1000)
if((i==0&&j==0&&k==1&&l==1&&m==1)||(i==1&&j==1&&k==1&&l==0&&m==0))
return(20)
if((i==0&&j==0&&k==-1&&l==-1&&m==-1)||(i==-1&&j==-1&&k==-1&&l==0&&m==0))
return(20)
if((i==-1&&j==1&&k==1&&l==1&&m==1)||(i==1&&j==-1&&k==1&&l==1&&m==1)||(i==1&&j==1&&k==-1&&l==1&&m==1)||(i==1&&j==1&&k==1&&l==-1&&m==1)||(i==1&&j==1&&k==1&&l==1&&m==-1))
return(-60)
if((i==1&&j==-1&&k==-1&&l==-1&&m==-1)||(i==-1&&j==1&&k==-1&&l==-1&&m==-1)||(i==-1&&j==1&&k==-1&&l==-1&&m==-1)||(i==-1&&j==-1&&k==-1&&l==1&&m==-1)||(i==-1&&j==-1&&k==-1&&l==-1&&m==1))
return(-60)
}
int wtu(int a[N+1][N+1],int write)
{
int i=1
map(a)
zuobiao(zx,zy,1)
while(i)
{
int k
k=tu(a,write)
if(k==OK) i=0
if(k==STOP) return (STOP)
}
}
int getkey()
{
int key,lo,hi
key=bioskey(0)
lo=key&0x00ff
hi=(key&0xff00)>>8
return((lo==0) ? hi+256:lo)
}
int key()
{
int k
k=getkey()
switch(k)
{
case 27: return (STOP)
case 13:
case ' ': return (OK)
case 328: return (UP)
case 336: return (DOWN)
case 331: return (LEFT)
case 333: return (RIGHT)
default: return (NO)
}
}
void zuobiao(int x,int y,int i)
{
int r
if(i!=0)
{
setcolor(GREEN)
for(r=1r<=5r++)
circle(75+25*x,25+25*y,r)
}
else
{
if(a[zy][zx]==1)
{
setcolor(8)
for(r=1r<=5r++)
circle(75+25*x,25+25*y,r)
}
else if(a[zy][zx]==-1)
{
setcolor(WHITE)
for(r=1r<=5r++)
circle(75+25*x,25+25*y,r)
}
else
{
setcolor(B)
for(r=1r<=5r++)
circle(75+25*x,25+25*y,r)
setcolor(RED)line(75+25*zx-5,25+25*zy,75+25*x+5,25+25*zy)
line(75+25*zx,25+25*zy-5,75+25*zx,25+25*zy+5)
}
}
}
int tu(int a[N+1][N+1],int write)
{
int k
re:
k=key()
if(k==OK)
{
if(a[zy][zx]==0)
{
a[zy][zx]=write
}
else
goto re
}
if(k==STOP) return(STOP)
if(k==NO) goto re
if(k==UP)
{
int i,j
if(zy==1) j=zy
else j=zy-1
zuobiao(zx,zy,0)
zuobiao(zx,j,1)
zy=j
goto re
}
if(k==DOWN)
{
int i,j
if(zy==N) j=zy
else j=zy+1
zuobiao(zx,zy,0)
zuobiao(zx,j,1)
zy=j
goto re
}
if(k==LEFT)
{
int i,j
if(zx==1) i=zx
else i=zx-1
zuobiao(zx,zy,0)
zuobiao(i,zy,1)
zx=i
goto re
}
if(k==RIGHT)
{
int i,j
if(zx==N) i=zx
else i=zx+1
zuobiao(zx,zy,0)
zuobiao(i,zy,1)
zx=i
goto re
}
}
void cbar(int i,int x,int y,int r)
{
if(i!=0)
{
if(i==1)
setcolor(8)
else if(i==-1)
setcolor(WHITE)
for(i=1i<=ri++)
{
circle(x,y,i)
}
}
}
void map(int a[N+1][N+1])
{
int i,j
cleardevice()
setbkcolor(B)
setcolor(RED)
for(i=0i<Ni++)
{
line(100,50+25*i,75+N*25,50+25*i)
line(100+25*i,50,100+25*i,25+N*25)
}
for(i=1i<=Ni++)
for(j=1j<=Nj++)
cbar(a[i][j],75+25*j,25+25*i,10)
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)