C语言 五子棋 博弈树算法 叶子节点的分值是如何计算的
五子棋胜负的判定,一般有一下两种算法:
1.扫描整个棋盘,分别扫描四个方向是否有5个连子。网上找了很多五子棋源码都是用此算法,这意味着每下一个棋子都要扫描一遍19×19的棋盘,复杂而且低效,代码略。
2.每下一字,从该子开始扫描其四个方向(例如:从该子的(x-4,y)坐标开始扫描横向)是否存在5个连子。此算法较为常用,而且不涉及更为复杂的数据结构。
另外,为解决扫描越界的问题,在声明棋盘棋子位置时,可声明一个(4+19+4)×(4+19+4)的棋盘,而让棋子偏移(4,4)个坐标。
算法2源代码如下:
?123456789101112131415161718192021static void IfWin(int x,int y,int color){ TCHAR win[20]; int a,b; if(stone[x][y]==1) wcscpy_s(win,_T("黑棋胜利!")); else wcscpy_s(win,_T("白棋胜利!")); for(a=x-4;a<=x+4;a++)//判断横 if(stone[a][y]==color&&stone[a+1][y]==color&&stone[a+2][y]==color&&stone[a+3][y]==color&&stone[a+4][y]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(b=y-4;b<=y+4;b++)//判断竖 if(stone[x][b]==color&&stone[x][b+1]==color&&stone[x][b+2]==color&&stone[x][b+3]==color&&stone[x][b+4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(a=x-4,b=y-4;a<=x+4;a++,b++)//判断右斜 if(stone[a][b]==color&&stone[a+1][b+1]==color&&stone[a+2][b+2]==color&&stone[a+3][b+3]==color&&stone[a+4][b+4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(a=x-4,b=y+4;a<=x+4;a++,b--)//判断左斜 if(stone[a][b]==color&&stone[a+1][b-1]==color&&stone[a+2][b-2]==color&&stone[a+3][b-3]==color&&stone[a+4][b-4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;}}
#include #include #include #include #include #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 #include #include #include #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=1;i((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=y;i((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=1;r<=5;r++) circle(75+25*x,25+25*y,r); } else { if(a[zy][zx]==1) { setcolor(8); for(r=1;r<=5;r++) circle(75+25*x,25+25*y,r); } else if(a[zy][zx]==-1) { setcolor(WHITE); for(r=1;r<=5;r++) circle(75+25*x,25+25*y,r); } else { setcolor(B); for(r=1;r<=5;r++) 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=1;i<=r;i++) { circle(x,y,i); } } } void map(int a[N+1][N+1]) { int i,j; cleardevice(); setbkcolor(B); setcolor(RED); for(i=0;i<N;i++) { line(100,50+25*i,75+N*25,50+25*i); line(100+25*i,50,100+25*i,25+N*25); } for(i=1;i<=N;i++) for(j=1;j<=N;j++) cbar(a[i][j],75+25*j,25+25*i,10); }
其实这个不是难点的,那个分数是当前落子后所形成的以这个棋子为中心的9x9矩阵中所形成的棋型,计算其他地方的棋型显然没有什么意义,再有就是不是C语言才可以写算法的,对于极大极小原理,博弈树和alpha-beta剪枝算法都是基于这个原理的,如果你是刚学编程不久,而且没有数据结构的基础是写不出来运用博弈树算法的五子棋的,先把基础打好再说。。C语言是一门通用计算机编程语言,应用广泛。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言订定了一套完整的国际标准语法,称为ANSI C,作为C语言最初的标准。
纵姚盐酸: 五子棋的核心算法 五子棋是一种受大众广泛喜爱的游戏,其规则简单,变化多端,非常富有趣味性和消遣性.这里设计和实现了一个人机对下的五子棋程序,采用了博弈树的方法,应用了剪枝和最大最小树原理进行搜索发现最好的下子位置....
乌兰察布盟15597477990: c语言五子棋判断谁赢算法的疑问 - ?
纵姚盐酸: 下一个新的子在weizhi处,然后以这个子为基准来判断,case 0为例,横着判断-》赢得可能性有:这个子是5个子最右边的子……这个子是五个子最左边的子.所以赢得可能性中,那最左边的子的坐标就是weizhi.x-4,weizhi.y 即count=4,然后一次判断左边第三个子,第二个子,……右边第四个子,如果有连续的5个子(通过count2或3的值来判断)就算赢了.
乌兰察布盟15597477990: c语言中如何获取树中所有叶子节点的路径 - ?
纵姚盐酸: 遍历树,你从根节点开始,然后访问子节点,并保存路径,如果是叶子节点就输出.
乌兰察布盟15597477990: C语言求树中的叶子结点数 - ?
纵姚盐酸: 有从上至下和从下至上两种方式可以统计树的节点数. 设叶子节点(度为0的节点)数为x: 从上至下时,度为n的节点有n个子节点,再加上根节点,总结点数量为1+4*1+3*2+2*3+1*4+0*n=21 从下至上时,节点数为度为0~4的所有节点数相加,总节点数量为1+2+3+4+n=10+n 所以有21=10+n,得n=11.
乌兰察布盟15597477990: C语言求叶子节点个数?
纵姚盐酸: 这是我学数据结构那年的程序,其中包括了二叉树的各种操作,希望对你有所帮助.(你的程序能不能整理下吗,才好改啊!!) #include<stdio.h> #include<stdlib.h> typedef struct BiTNode /*二叉树结点类型说明*/ { int data; struct BiTNode *...
乌兰察布盟15597477990: 二叉树的叶子节点数如何计算? - ?
纵姚盐酸: 二叉树的叶子节点数:没有子树的结点是叶子结点.结点的度是指,该结点的子树的个数,在二叉树中,不存在度大于2的结点. 计算公式:n0=n2+1 n0 是叶子节点的个数 n2 是度为2的结点的个数 n0=n2+1=5+1=6 故二叉树有5个度为2的结点,则该二叉树中的叶子结点数为6.
乌兰察布盟15597477990: 怎么计算C语言的二叉树中的叶子节点数? - ?
纵姚盐酸: 二叉树中叶子节点的度为0,即它的左右儿子都为空 在数学中,两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为X * Y,是其第一个对象是X的成员而第二个对象是Y的一个成员的所有可能的有序对 这是在网络上找的定义. 比...
乌兰察布盟15597477990: 3.3 C语言,某二叉树有5个度为2的节点,则该二叉树中的叶子节点是? - ?
纵姚盐酸: 如果某个二叉树有n2个度为2的结点,则该二叉树的叶子节点有(n2+1)个 设n为总节点数,n0是度为0的节点数(即叶子节点),n1是度为1的节点数,n2是度为2的节点数,那么有n=n0+n1+n2,n-1=n1+2*n2=分支总数,由这2个方程可得:n0=n2+1. n2=5的话,那么叶子有6个.
乌兰察布盟15597477990: C语言 简单的 五子棋?
纵姚盐酸: #include <graphics.h> #include <conio.h> #include <time.h> #include <stdio.h> #define KEY_UP 0x48 #define KEY_LEFT 0x4B #define KEY_RIGHT 0x4D #define KEY_DOWN 0x50 #define XIAZI 32 int x=320,y=230; int who=2; int zuobiao[10][10]...
乌兰察布盟15597477990: C语言五子棋算法 - ?
纵姚盐酸: 任何一种棋类游戏其关键是对当前棋局是否有正确的评分,评分越准确则电脑的AI越高.五子棋游戏也是如此,但在打分之前,我们先扫描 整个棋盘,把每个空位从八个方向上的棋型填入数组gStyle(2, 15, 15, 8, 2),其中第一个下标为1时表示黑...