📄 tictactoe.cpp
字号:
#include<iostream.h>
#include <stdlib.h>
static double w1=3; //权值1
static double w2=2; //权值2
static double w3=60; //权值3
static int chess[3][3];//棋盘
static int x1,x2,x3; //x1是本方可能连成直线的条数,x2是对方可能连成直线的条数,x3有两个子在一起的直线
static double vp=0; //保存之前一个棋盘状态的值
static int step; //走棋步数
static double win; //胜利局数
static double lose; //失败局数
static double no; //总棋局数
static double vtrain;
//棋盘显示
void showboard()
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
{
cout<<chess[i][j];
if(j==2) cout<<'\n';
else cout<<' ';
}
}
//判定输赢
int judge()
{
int result=0;
if(step!=0)
{
for (int i=0;i<3;i++)
{
if(chess[i][0]==chess[i][1]&&chess[i][0]==chess[i][2]&&chess[i][0]!=0)
result=(chess[i][0]==1?1:2);
if(chess[0][i]==chess[1][i]&&chess[0][i]==chess[2][i]&&chess[0][i]!=0)
result=(chess[0][i]==1?1:2);
}
if(chess[0][0]==chess[1][1]&&chess[0][0]==chess[2][2]&&chess[0][0]!=0)
result=(chess[0][0]==1?1:2);
if(chess[0][2]==chess[1][1]&&chess[1][1]==chess[2][0]&&chess[2][0]!=0)
result=(chess[0][2]==1?1:2);
}
return result;
}
//计算某位置的x1,x2,x3
int *countline(int m, int n , int flag)
{
chess[m][n] = flag; //暂时放入,然后检测是否是最好的位置
int line = 1;
//计算x1,先计算横向线路
for(int i=0;i<3;i++)
{
line = 1;
for(int j=0;j<3;j++)
{
if(chess[i][j]!=flag&&chess[i][j]!=0)
{
line=0; //发现线路被阻止,则退出本次循环
break;
}
}
if(line==1) x1++;
}
//计算纵向线路
for(int j=0;j<3;j++)
{ line = 1;
for(int i=0;i<3;i++)
{
if(chess[i][j]!=flag&&chess[i][j]!=0)
{
line=0;
break;
}
}
if(line==1) x1++;
}
line=1;
//计算斜向线路
for( i=0;i<3;i++)
{
if (chess[i][i]!=flag&&chess[i][i]!=0)
line=0;
break;
}
if (line==1)
x1++;
//计算反斜向线路
line=1;
for( i=0;i<3;i++)
{
if (chess[i][3-i]!=flag&&chess[i][3-i]!=0)
line=0;
break;
}
if (line==1)
x1++;
//计算x2,将身份标志位颠倒
if(flag==1)
flag=2;
else
flag=1;
// 横向
for(i=0;i<3;i++)
{
line=1;
for(j=0;j<3;j++)
{
if(chess[i][j]!=flag&&chess[i][j]!=0)
{
line=0;
break;
}
}
if(line==1) x2++;
}
//纵向
for(j=0;j<3;j++)
{ line = 1;
for(i=0;i<3;i++)
{
if(chess[i][j]!=flag&&chess[i][j]!=0)
{
line=0;
break;
}
}
if(line==1) x2++;
}
//斜向
line=1;
for(i=0;i<3;i++)
{
if (chess[i][i]!=flag&&chess[i][i]!=0)
line=0;
break;
}
if (line==1)
x2++;
//反斜向
line=1;
for(i=0;i<3;i++)
{
if (chess[i][3-i]!=flag&&chess[i][3-i]!=0)
line=0;
break;
}
if (line==1) x2++;
//计算x3
if(judge())
{
x3++;
chess[m][n]=0;
int a[3]={x1,x2,x3};
int* p=&a[0];
return p;
}
else x3=0;
//将之前放入棋盘的点复位,将x1,x2,x3返回,使用vmax()进行计算是否为最优下棋点
chess[m][n]=0;
int a[3]={x1,x2,x3};
int* p=&a[0];
return p;
}
//选择最优下棋位置
bool vmax(double w1,double w2,double w3,int flag)
{
int x=0;
int y=0;
double v=0;
int f=0;
double temp=0;
vp=0;
for (int m=0;m<3;m++)
{
for (int n=0;n<3;n++)
{
if(chess[m][n]==0)//找到空位
{
x1=0;
x2=0;
x3=0;
int *a=countline(m, n,flag); //调用countline函数计算此处x1,x2和x3的值
x1=a[0];
x2=a[1];
x3=a[2];
v=w1*x1-w2*x2+w3*x3+1;
if(flag==2)
{
if(step==1) //第一步
{
vp=v;
x=rand()%3;
y=rand()%3;
chess[x][y]=flag;
return true;
}
else if(v>vp)
{
vp=v;
x=m;
y=n;
f++;
}
else if(f==0) //防止棋局初始,产生的覆盖
{
x=m;
y=n;
}
}
else
{
if(step==2)//相当于对手第一步
{
x=m;
y=n;
chess[x][y]=flag;
return true;
}
else
{
if(v>temp)
{
temp=v; //保存最大值和最大值位置
x=m;
y=n;
f++;
}
else if(f==0) //防止棋局初始,产生的覆盖
{
x=m;
y=n;
}
}
}
}
}
}
chess[x][y]=flag; //在选出的位置下子
return true;
}
void train(int counter)
{
int t=0;
for(int i = 1; i<=counter;i++,no++)
{
step=0;
cout<<"第"<< i <<"次训练"<<endl;
//棋盘初始化,全部清空
for( int l = 0; l < 3; l ++ )
{
for( int s =0; s < 3; s++)
chess[l][s] = 0;
}
showboard();
while(!judge()&&step<=9)
{
step++;
cout<<"************"<<endl;
vmax(w1,w2,w3,2);
if( step>1 ) //第一步棋不调整权值
{
w1=w1+0.03*(vtrain-vp)*x1;
w2=w2+0.03*(vtrain-vp)*x2;
w3=w3+0.03*(vtrain-vp)*x3;
}
vtrain=vp;
showboard();
if(judge()||step==9) break;
cout<<endl;
step++;
vmax(1,1,1,1);
showboard();
}
t=judge();
cout<<"************"<<endl;
if(t==1)
{
cout<<"教练胜"<<endl;
lose++;
}
else if(t==2)
{
cout<<"学生胜"<<endl;
win++;
}
else cout<<"平局"<<endl;
cout<<"************"<<endl;
}
}
//程序入口
void main()
{
int p=1;
while(p)
{
cout<<"====================="<<endl;
cout<<" Tic Tac Toe 学习程序"<<endl;
cout<<" 1.学习训练 "<<endl;
cout<<" 2.统计信息 "<<endl;
cout<<" 3.退出 "<<endl;
cout<<"====================="<<endl;
cout<<"请选择:"<<endl;
int b;
cin>>b;
switch(b)
{
case 1:
{
int c;
cout<<"请输入训练次数:"<<endl;
cin>>c;
train(c);
break;
}
case 2:
{
cout<<"胜:"<<win<<endl;
cout<<"负:"<<lose<<endl;
cout<<"平:"<<(no-win-lose)<<endl;
cout<<"胜率:"<<(win/no)*100<<"%"<<endl;
break;
}
default: p=0;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -