【alpha-bet剪枝】五子棋AI
2014-06-01 15:48
615 查看
//五子棋AI算法 //加入alpha-bet剪枝 //------------------------------------------------------ //头文件包含 #include "stdio.h" //------------------------------------------------------ //定义黑白棋手 #define white 1 #define black -1 //------------------------------------------------------ //定义数据类型 struct Space//位置 { int row; int list; }; struct Reaction { Space space; int power; }; struct Limit { int up; int down; int left; int right; }; //------------------------------------------------------ //函数声明 int max(int x1,int x2); int min(int x1,int x2); bool line_win(int player,int a[],int n=9);//单线五子判断 bool win(int x[15][15],int row,int list);//五子判断 int get_line_power(int player,int a[],int n=9);//单线势分析 int get_leaf_power(int x[15][15],int row,int list);//计算叶子的势 Limit get_limit(int x[15][15],int width);//划定搜索范围 Reaction ai(int x[15][15],int player,int depth=4/*搜索深度*/,int width=1/*搜索宽度*/,int uncle_power=1000);//分析棋盘,返回最优势的下棋位置和势 //------------------------------------------------------ //函数定义 int max(int x1,int x2){return x1>x2?x1:x2;} int min(int x1,int x2){return x1>x2?x2:x1;} //单线五子判断 bool line_win(int player,int a[],int n) { int num=0; for(int i=0;i<n-(5-1);i++) { num=0; for(int j=0;j<5;j++) if(a[i+j]==player)num++; if(num==5)return true; } return false; } //五子判断 bool win(int x[15][15],int row,int list) { int line[9]={0}; int player=x[row][list]; // │ 从上到下赋值 int begin=max(0,row-4);//对应所选取数组的横坐标的开始 int end=min(14,row+4);//对应所选取数组的横坐标的结束 for(int i=begin,j=0/*数组下标*/;i<=end;i++,j++) line[j]=x[i][list]; if(line_win(player,line,end-begin+1))return true; // ╲ 从左上到右下赋值 begin=max(max(list-4,0),max(list-row,0)); end=min(min(list+4,14),min(list+(14-row),14)); for(int i=begin,j=0;i<=end;i++,j++) line[j]=x[row-(list-begin)+j][i]; if(line_win(player,line,end-begin+1))return true; // ─ 从左到右赋值 begin=max(0,list-4); end=min(14,list+4); for(int i=begin,j=0;i<=end;i++,j++) line[j]=x[row][i]; if(line_win(player,line,end-begin+1))return true; // ╱ 从左下到右上赋值 begin=max(max(list-4,0),max(list-(14-row),0)); end=min(min(list+4,14),min(list+row,14)); for(int i=begin,j=0;i<=end;i++,j++) line[j]=x[row+(list-begin)-j][i]; if(line_win(player,line,end-begin+1))return true; return false; } //单线势分析 int get_line_power(int player,int a[],int n/*数组长度*/) { int num=0; int num2=0; //***** 绝对优势:5 for(int i=0;i<n-(5-1);i++) { num=0; for(int j=0;j<5;j++) if(a[i+j]==player)num++; if(num==5)return 5; } //_****_ 大优势:4 for(int i=0;i<n-(6-1);i++) { num=0; for(int j=0;j<6;j++) if(a[i+j]==player)num++; if(num==4&&(a[i]==0&&a[i+5]==0))return 4; } //****_、**_** 优势:3 for(int i=0;i<n-(5-1);i++) { num=0; num2=0; for(int j=0;j<5;j++) { if(a[i+j]==player)num++; if(a[i+j]==0)num2++; } if(num==4&&num2==1)return 3; } //_*_**_、__***_ 优势:2 for(int i=0;i<n-(6-1);i++) { num=0; num2=0; for(int j=0;j<6;j++) { if(a[i+j]==player)num++; if(a[i+j]==0)num2++; } if(num==3&&num2==3&&a[i]==0&&a[i+5]==0)return 2; } //***_ 小优势:1 for(int i=0;i<n-(4-1);i++) { num=0; num2=0; for(int j=0;j<4;j++) { if(a[i+j]==player)num++; if(a[i+j]==0)num2++; } if(num==3&&num2==1)return 1; } //_*_*_ 小优势:1 for(int i=0;i<n-(5-1);i++) { num=0; for(int j=0;j<5;j++) if(a[i+j]==player)num++; if(num==2&&(a[i]==0&&a[i+4]==0)&&a[i+2]==0)return 1; } //_**_ 小优势:1 for(int i=0;i<n-(4-1);i++) if(a[i]==0&&a[i+1]==player&&a[i+2]==player&&a[i+3]==0)return 1; return 0; } //计算叶子的势 int get_leaf_power(int x[15][15],int row,int list) { int power; int a[4]={0};//多线势记录 int line[9]={0}; int player=x[row][list]; int begin=max(0,row-4); int end=min(14,row+4); for(int i=begin,j=0;i<=end;i++,j++)// │ line[j]=x[i][list]; a[0]=get_line_power(player,line,end-begin+1); begin=max(max(list-4,0),max(list-row,0)); end=min(min(list+4,14),min(list+(14-row),14)); for(int i=begin,j=0;i<=end;i++,j++)// ╲ line[j]=x[row-(list-begin)+j][i]; a[1]=get_line_power(player,line,end-begin+1); begin=max(0,list-4); end=min(14,list+4); for(int i=begin,j=0;i<=end;i++,j++)// ─ line[j]=x[row][i]; a[2]=get_line_power(player,line,end-begin+1); begin=begin=max(max(list-4,0),max(list-(14-row),0)); end=min(min(list+4,14),min(list+row,14)); for(int i=begin,j=0;i<=end;i++,j++)// ╱ line[j]=x[row+(list-begin)-j][i]; a[3]=get_line_power(player,line,end-begin+1); for(int i=0;i<3;i++)//从大到小冒泡排序 for(int j=0;j<3-i;j++) if(a[j]<a[j+1]) { a[j]=a[j]^a[j+1]; a[j+1]=a[j]^a[j+1]; a[j]=a[j]^a[j+1]; } if(a[0]==5)power=4*(4*4*4); else if(a[0]==4)power=3*(4*4*4)+3*(4*4); else { power=a[0]*4*4*4+a[1]*4*4+a[2]*4+a[3]; if(power>=3*(4*4*4)&&power<3*(4*4*4)+2*(4*4))power=power-4*4*4; } return power; } //划定搜索范围 Limit get_limit(int x[15][15],int width) { Limit limit; //计算limit.up for(int i=0;i<15;i++) for(int j=0;j<15;j++) if(x[i][j]!=0) { limit.up=i; limit.left=j; limit.right=j; limit.down=i; goto out; } out: //计算limit.left\down for(int i=limit.up;i<15;i++) for(int j=0;j<15;j++) if(x[i][j]!=0) { limit.down=i; if(j<limit.left)limit.left=j; break; } //计算limit.right for(int i=limit.up;i<15;i++) for(int j=14;j>=0;j--) if(x[i][j]!=0&&j>limit.right) { limit.right=j; break; } limit.up=max(limit.up-width,0); limit.left=max(limit.left-width,0); limit.right=min(limit.right+width,14); limit.down=min(limit.down+width,14); return limit; } //本质上是一个后序遍历 //分析棋盘,返回最优势的下棋位置和势 //使用到alpha-bet剪枝 Reaction ai(int x[15][15],int player,int depth/*搜索深度*/,int width/*搜索宽度*/,int uncle_power) { Reaction reaction; reaction.space.row=8; reaction.space.list=8; reaction.power=-1000; int n=0; for(int i=0;i<15;i++) for(int j=0;j<15;j++) if(x[i][j]==0)n++; //棋盘为空 if(n==15*15) { reaction.power=0; return reaction; } //棋盘已满 if(n==0) { reaction.space.row=-1; reaction.space.list=-1; return reaction; } //划定搜索范围 Limit limit=get_limit(x,width); //判断己方是否活四 for(int i=limit.up;i<=limit.down;i++) for(int j=limit.left;j<=limit.right;j++) { if(x[i][j]!=0)continue;//检查落点是否为空 x[i][j]=player;//落点假设 if(win(x,i,j)) { reaction.space.row=i; reaction.space.list=j; reaction.power=4*4*4*4;//赋值为绝对优势 x[i][j]=0;//落点还原 return reaction; } x[i][j]=0;//落点还原 } //判断敌方是否活四 for(int i=limit.up;i<=limit.down;i++) for(int j=limit.left;j<=limit.right;j++) { if(x[i][j]!=0)continue;//检查落点是否为空 x[i][j]=player*-1;//敌方落点假设 if(win(x,i,j)) { x[i][j]=player;//己方落点假设 reaction.space.row=i; reaction.space.list=j; reactio 4000 n.power=ai(x,player*-1,depth-1,width,reaction.power*-1).power*-1;//根据计算情况赋值 x[i][j]=0;//落点还原 return reaction; } x[i][j]=0;//落点还原 } //分支节点 if(depth>0) { for(int i=limit.up;i<=limit.down;i++) for(int j=limit.left;j<=limit.right;j++) { if(x[i][j]!=0)continue;//检查落点是否为空 x[i][j]=player;//落点假设 int node_power=ai(x,player*-1,depth-1,width,reaction.power*-1).power*-1; if(node_power>=uncle_power)//alpha-bet剪枝 { reaction.space.row=i; reaction.space.list=j; reaction.power=node_power; x[i][j]=0;//落点还原 return reaction; } if(node_power==4*4*4*4)//判断是否形成绝对优势:如果是,剪除所有兄弟节点 { reaction.space.row=i; reaction.space.list=j; reaction.power=node_power; x[i][j]=0;//落点还原 return reaction; } if(reaction.power<node_power) { reaction.space.row=i; reaction.space.list=j; reaction.power=node_power; } x[i][j]=0;//落点还原 } return reaction; } //叶子节点 for(int i=limit.up;i<=limit.down;i++) for(int j=limit.left;j<=limit.right;j++) { if(x[i][j]!=0)continue;//检查落点是否为空 x[i][j]=player;//落点假设 int node_power=get_leaf_power(x,i,j); if(node_power>=uncle_power)//alpha-bet剪枝 { reaction.space.row=i; reaction.space.list=j; reaction.power=node_power; x[i][j]=0;//落点还原 return reaction; } if(reaction.power<node_power) { reaction.space.row=i; reaction.space.list=j; reaction.power=node_power; } x[i][j]=0;//落点还原 } return reaction; } //测试 int main() { int a[15][15]= { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }; Reaction b=ai(a,black); printf("(%d,%d)%d\n",b.space.row,b.space.list,b.power);//(4,6)80 return 0; }
相关文章推荐
- 【随机】【加壳】【alpha-bet剪枝】五子棋AI
- 五子棋AI博弈树之带Alpha-Beta剪枝的极大极小过程函数
- 五子棋AI算法第三篇-Alpha Beta剪枝
- QT五子棋项目详解之五:AI人机对战Alpha-Beta剪枝算法
- 基于Alphabet剪枝的五子棋AI
- 五子棋AI循序渐进【3】基石——超出边界的alpha-beta剪裁
- 【机器学习实战】制作五子棋AI之一:图片预处理(尺寸变换和增加alpha通道)
- 为何谷歌围棋AI AlphaGo可能会把李世石击溃
- 博弈(alpha-beta 剪枝)POJ —— 1085 Triangle War
- Android Gomoku五子棋简析(AI 人工智能 GirdView实现,浅显易懂)
- js 五子棋(无ai,仅判断胜负)
- 五子棋的简单AI
- POJ - 3317 Stake Your Claim 极大极小搜索+alpha-beta剪枝+记忆化搜索
- alpha-beta剪枝算法解决 486. Predict the Winner
- 本人用 C 和 WinAPI 写的一个 带AI的五子棋
- Alpha_Beta 剪枝
- [深度学习]实现一个博弈型的AI,从五子棋开始(2)
- Qt小游戏开发:五子棋(带AI功能)
- 五子棋AI循序渐进【5】重点问题重点分析——静态搜索
- 极小极大值方法以及alpha-Beta剪枝