代码语言
.
CSharp
.
JS
Java
Asp.Net
C
MSSQL
PHP
Css
PLSQL
Python
Shell
EBS
ASP
Perl
ObjC
VB.Net
VBS
MYSQL
GO
Delphi
AS
DB2
Domino
Rails
ActionScript
Scala
代码分类
文件
系统
字符串
数据库
网络相关
图形/GUI
多媒体
算法
游戏
Jquery
Extjs
Android
HTML5
菜单
网页交互
WinForm
控件
企业应用
安全与加密
脚本/批处理
开放平台
其它
【
C
】
一字棋
作者:
MusketeerL
/ 发布于
2014/6/17
/
514
一字棋
#include<iostream> using namespace std; int num=0; //记录棋盘上棋子的个数 int p,q; //判断是否平局 int tmpQP[3][3]; //表示棋盘数据的临时数组,其中的元素0表示该格为空, int now[3][3]; //存储当前棋盘的状态 const int depth=3; //搜索树的最大深度 void Init() //初始化棋盘状态 { for(int i=0;i<3;i++) for(int j=0;j<3;j++) { now[i][j]=0; //将初值均置为0 } } void PrintQP() //打印棋盘当前状态 { for(int i=0;i<3;i++) { for(int j=0;j<3;j++) cout<<now[i][j]<<'\t'; cout<<endl; } } void playerinput() //用户通过此函数来输入落子的位置,比如:用户输入3 1,则表示用户在第3行第1列落子。 { int x,y; L1: cout<<"请输入您的棋子位置(x y):"<<endl; cin>>x>>y; if(x>0&&x<4&&y>0&&y<4&&now[x-1][y-1]==0) { now[x-1][y-1]=-1; //站在电脑一方,玩家落子置为-1 } else { cout<<"非法输入!"<<endl; //提醒输入错误 goto L1; } } int Checkwin() //检查是否有一方赢棋(返回 0:没有任何一方赢;1:计算机赢;-1:人赢) { //该方法没有判断平局 for(int i=0;i<3;i++) { if(now[i][0]==1&&now[i][1]==1&&now[i][2]==1) //正方行连成线 { return 1; } if(now[i][0]==-1&&now[i][1]==-1&&now[i][2]==-1) //反方行连成线 { return -1; } } for(i=0;i<3;i++) { if(now[0][i]==1&&now[1][i]==1&&now[2][i]==1) //正方列连成线 { return 1; } if(now[0][i]==-1&&now[1][i]==-1&&now[2][i]==-1) //反方列连成线 { return -1; } } if((now[0][0]==1&&now[1][1]==1&&now[2][2]==1)||(now[2][0]==1&&now[1][1]==1&&now[0][2]==1)) { return 1; //正方对角线连成线 } if((now[0][0]==-1&&now[1][1]==-1&&now[2][2]==-1)||(now[2][0]==-1&&now[1][1]==-1&&now[0][2]==-1)) { return -1; //反方对角线连成线 } return 0; } int value() //评估当前棋盘状态的值(同时可以用p或q判断是否平局) { p=0; q=0; for(int i=0;i<3;i++) //计算机一方 { //将棋盘中的空格填满自己的棋子,既将棋盘数组中的0变为1 for(int j=0;j<3;j++) { if(now[i][j]==0) { tmpQP[i][j]=1; } else { tmpQP[i][j]=now[i][j]; } } } for(i=0;i<3;i++) //计算共有多少连成3个1的行 { p+=(tmpQP[i][0]+tmpQP[i][1]+tmpQP[i][2])/3; } for(i=0;i<3;i++) //计算共有多少连成3个1的列 { p+=(tmpQP[0][i]+tmpQP[1][i]+tmpQP[2][i])/3; } p+=(tmpQP[0][0]+tmpQP[1][1]+tmpQP[2][2])/3; //计算共有多少连成3个1的对角线 p+=(tmpQP[2][0]+tmpQP[1][1]+tmpQP[0][2])/3; for(i=0;i<3;i++) //人一方 { //将棋盘中的空格填满自己的棋子,既将棋盘数组中的0变为-1 for(int j=0;j<3;j++) { if(now[i][j]==0) { tmpQP[i][j]=-1; } else { tmpQP[i][j]=now[i][j]; } } } for(i=0;i<3;i++) //计算共有多少连成3个-1的行 { q+=(tmpQP[i][0]+tmpQP[i][1]+tmpQP[i][2])/3; } for(i=0;i<3;i++) //计算共有多少连成3个1的列 { q+=(tmpQP[0][i]+tmpQP[1][i]+tmpQP[2][i])/3; } q+=(tmpQP[0][0]+tmpQP[1][1]+tmpQP[2][2])/3; //计算共有多少连成3个1的对角线 q+=(tmpQP[2][0]+tmpQP[1][1]+tmpQP[0][2])/3; return p+q; //返回评估出的棋盘状态的值 } int cut(int &val,int dep,bool max) //主算法部分,实现a-B剪枝的算法,val为上一个结点的估计值,dep为搜索深度,max记录上一个结点是否为上确界 { if(dep==depth||dep+num==9) //如果搜索深度达到最大深度,或者深度加上当前棋子数已经达到9,就直接调用估计函数 { return value(); } int i,j,flag,temp; //flag记录本层的极值,temp记录下层求得的估计值 bool out=false; //out记录是否剪枝,初始为false if(max) //如果上一个结点是上确界,本层则需要是下确界,记录flag为无穷大;反之,则为记录为负无穷大 { flag=10000; //flag记录本层节点的极值 } else { flag=-10000; } for(i=0;i<3 && !out;i++) //双重循环,遍历棋盘所有位置 { for(j=0;j<3 && !out;j++) { if(now[i][j]==0) //如果该位置上没有棋子 { if(max) //并且上一个结点为上确界,即本层为下确界,轮到用户玩家走了。 { now[i][j]=-1; //该位置填上用户玩家棋子 if(Checkwin()==-1) //如果用户玩家赢了 { temp=-10000; //置棋盘估计值为负无穷 } else { temp=cut(flag,dep+1,!max); //否则继续调用a-B剪枝函数 } if(temp<flag) //如果下一步棋盘的估计值小于本层节点的极值,则置本层极值为更小者 { flag=temp; } if(flag<=val) //如果本层的极值已经小于上一个结点的估计值,则不需要搜索下去,剪枝 { out=true; } } else //如果上一个结点为下确界,即本层为上确界,轮到计算机走了。 { now[i][j]=1; //该位置填上计算机棋子 if(Checkwin()==1) //如果计算机赢了 { temp=10000; //置棋盘估计值为无穷 } else { temp=cut(flag,dep+1,!max);//否则继续调用a-B剪枝函数 } if(temp>flag) { flag=temp; } if(flag>=val) { out=true; } } now[i][j]=0; //把模拟下的一步棋还原,回溯 } } } if(max) //根据上一个结点是否为上确界,用本层的极值修改上一个结点的估计值 { if(flag>val) { val=flag; } } else { if(flag<val) { val=flag; } } return flag; //函数返回的是本层的极值 } int computer() { int m=-10000,val=-10000,dep=1; //m用来存放最大的val int x_pos,y_pos; //记录最佳走步的坐标 char ch; cout<<"您希望先走还是后走?(y/n)"; cin>>ch; while(ch!='y'&&ch!='n') { cout<<"非法输入!"<<"您希望先走还是后走?(y/n)"<<endl; cin>>ch; } system("cls"); Init(); cout<<"棋盘如下: "<<endl; PrintQP(); if(ch=='n') //计算机先走 { L5: for(int x=0;x<3;x++) { for(int y=0;y<3;y++) { if(now[x][y]==0) { now[x][y]=1; // cut(val,dep,1); //计算机试探的走一步棋,棋盘状态改变了,在该状态下计算出深度为dep-1的棋盘状态估计值val if(Checkwin()==1) { cout<<"电脑将棋子放在:"<<x+1<<y+1<<endl; PrintQP(); cout<<"电脑获胜! 游戏结束."<<endl; return 0; } if(val>m) //m要记录通过试探求得的棋盘状态的最大估计值 { m=val; x_pos=x;y_pos=y; } val=-10000; now[x][y]=0; } } } now[x_pos][y_pos]=1; val=-10000; m=-10000; dep=1; cout<<"电脑将棋子放在:"<<x_pos+1<<y_pos+1<<endl; PrintQP(); cout<<endl; num++; value(); if(p==0) { cout<<"平局!"<<endl; return 0; } playerinput(); //玩家走一步棋 PrintQP(); cout<<endl; num++; value(); if(p==0) { cout<<"平局!"<<endl; return 0; } if(Checkwin()==-1) { cout<<"您获胜! 游戏结束."<<endl; return 0; } goto L5; } else //人先走 { L4: playerinput(); PrintQP(); cout<<endl; num++; value(); if(q==0) { cout<<"平局!"<<endl; return 0; } if (Checkwin()==-1) { cout<<"您获胜! 游戏结束."<<endl; return 0; } for(int x=0;x<3;x++) { for(int y=0;y<3;y++) { if(now[x][y]==0) { now[x][y]=1; cut(val,dep,1); if(Checkwin()==1) { cout<<"电脑将棋子放在:"<<x+1<<y+1<<endl; PrintQP(); cout<<"电脑获胜! 游戏结束."<<endl; return 0; } if(val>m) { m=val; x_pos=x;y_pos=y; } val=-10000; now[x][y]=0; } } } now[x_pos][y_pos]=1; val=-10000; m=-10000; dep=1; cout<<"电脑将棋子放在:"<<x_pos+1<<y_pos+1<<endl; PrintQP(); cout<<endl; num++; value(); if(q==0) { cout<<"平局!"<<endl; return 0; } goto L4; } return 0; } void main() //主程序 { //记录选择游戏方式 cout<<"**************************"<<endl; cout<<" 一字棋游戏"<<endl; cout<<"**************************"<<endl; system("pause"); system("cls"); computer(); }
试试其它关键字
一字棋
同语言下
.
获取手机通讯录 iOS去除数字以外的所有字符
.
异步加载音乐等资源
.
交通罚单管理系统
.
freemark实现,简单的替换
.
计算斐波那契数列
.
base64解码 包括解码长度
.
图像显示
.
冒泡排序
.
输入十进制数,输出指定进制
.
链式栈
可能有用的
.
C#实现的html内容截取
.
List 切割成几份 工具类
.
SQL查询 多列合并成一行用逗号隔开
.
一行一行读取txt的内容
.
C#动态修改文件夹名称(FSO实现,不移动文件)
.
c# 移动文件或文件夹
.
c#图片添加水印
.
Java PDF转换成图片并输出给前台展示
.
网站后台修改图片尺寸代码
.
处理大图片在缩略图时的展示
MusketeerL
贡献的其它代码
(
5
)
.
进程工具类
.
一字棋
.
自运行时钟
.
Java util.Date 转成 sql.Date
.
使用NIO进行快速的文件拷贝
Copyright © 2004 - 2024 dezai.cn. All Rights Reserved
站长博客
粤ICP备13059550号-3