⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tictactoe.cpp

📁 机器学习三子棋学习题目
💻 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 + -