BUPT 14级新生训练赛第10场
写了一个不是很厉害的五子棋AI设计
其中有两个估价函数,主要的那个其实写得不太好,有能力预判眠三,跳三,跳四等等,有一定能力能够判断连三冲四局
第二个作为辅助的其实优化之后更加厉害(只是我写得比较龊),各位可以去自行百度关于第二个估价函数的估价表
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define ll long long
using namespace std;
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1;
char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
//-----------------------------------------------------------------------
const int MAXN=2014;
int chess[16][16],tot=0;
int FF,SS;
struct win_kind
{
bool ok; // 初始化为false,有些点下了往后就是不会赢
int x[6],y[6]; // 神奇的落子地点
bool is_used[5]; // 胜利的五个神奇的点,初始化为false
} first[MAXN],second[MAXN]; // 把棋盘展开成为直线,笑尿人工计算的策略
int panfen[16][16] =
{
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
{ 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0 },
{ 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0 },
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
int com[16][16];
inline bool in(int x,int y)
{
return x>=0 && x<15 && y>=0 && y<15;
}
void init()
{
tot=0;
for(int i=0;i<15;i++)
for(int j=0;j<=10;j++) // 从i,j落子,横五个
{
if(chess[i][j]==FF)
{
first[tot+11*i+j].ok=true;
second[tot+11*i+j].ok=false;
}
else if(chess[i][j]==SS)
{
first[tot+11*i+j].ok=false;
second[tot+11*i+j].ok=true;
}
for(int k=0; k<5; k++)
{
first[tot+11*i+j].is_used[k]=false;
first[tot+11*i+j].x[k]=i;
first[tot+11*i+j].y[k]=j+k;
second[tot+11*i+j].is_used[k]=false;
second[tot+11*i+j].x[k]=i;
second[tot+11*i+j].y[k]=j+k;
}
}
tot+=165; //共计165个可能落子点
for(int i=0;i<=10;i++) // 竖五个
for(int j=0;j<15;j++)
{
if(chess[i][j]==FF)
{
first[tot+15*i+j].ok=true;
second[tot+15*i+j].ok=false;
}
else if(chess[i][j]==SS)
{
first[tot+15*i+j].ok=false;
second[tot+15*i+j].ok=true;
}
for(int k=0;k<5;k++)
{
first[tot+15*i+j].is_used[k]=false;
first[tot+15*i+j].x[k]=i+k;
first[tot+15*i+j].y[k]=j;
second[tot+15*i+j].is_used[k]=false;
second[tot+15*i+j].x[k]=i+k;
second[tot+15*i+j].y[k]=j;
}
}
tot+=165;
for(int i=0;i<=10;i++) //向右下斜↘
for(int j=0;j<=10;j++)
{
if(chess[i][j]==FF)
{
first[tot+11*i+j].ok=true;
second[tot+11*i+j].ok=false;
}
else if(chess[i][j]==SS)
{
first[tot+11*i+j].ok=false;
second[tot+11*i+j].ok=true;
}
for(int k=0; k<5; k++)
{
first[tot+11*i+j].is_used[k]=false;
first[tot+11*i+j].x[k]=i+k;
first[tot+11*i+j].y[k]=j+k;
second[tot+11*i+j].is_used[k]=false;
second[tot+11*i+j].x[k]=i+k;
second[tot+11*i+j].y[k]=j+k;
}
}
tot+=121;
for(int i=4;i<15;i++) //向右上斜↗
for(int j=0;j<=10;j++)
{
if(chess[i][j]==FF)
{
first[tot+11*(i-4)+j].ok=true;
second[tot+11*(i-4)+j].ok=false;
}
else if(chess[i][j]==SS)
{
first[tot+11*(i-4)+j].ok=false;
second[tot+11*(i-4)+j].ok=true;
}
for(int k=0;k<5;k++)
{
first[tot+11*(i-4)+j].is_used[k]=false;
first[tot+11*(i-4)+j].x[k]=i-k;
first[tot+11*(i-4)+j].y[k]=j+k;
second[tot+11*(i-4)+j].is_used[k]=false;
second[tot+11*(i-4)+j].x[k]=i-k;
second[tot+11*(i-4)+j].y[k]=j+k;
}
}
tot+=121;
for(int i=0; i<tot; i++)
second[i]=first[i]; //说好的人和电脑的输赢应该是一样的呢?
}
void judgehelp(int x,int y,int w)
{
int score=1;
if(w==FF)
{
for(int i=0;i<tot;i++)
{
score=1;
if(first[i].ok==false)
continue;
for(int j=0;j<5;j++)
{
if(first[i].x[j]==x && first[i].y[j]==y)
{
int k=j-1;
while(k>=0 && first[i].is_used[k]==true)
{
k--;
score+=10;
}
k=j+1;
while(k<5 && first[i].is_used[k]==true)
{
k++;
score+=10;
}
break;
}
}
com[x][y]+=score;
}
}
else
{
for(int i=0;i<tot;i++)
{
score=1;
if(second[i].ok==false)
continue;
for(int j=0;j<5;j++)
{
if (second[i].x[j]==x && second[i].y[j]==y)
{
int k=j-1;
while(k>=0 && second[i].is_used[k]==true)
{
k--;
score+=4;
}
k=j+1;
while(k<5 && second[i].is_used[k]==true)
{
k++;
score+=4;
}
break;
}
}
com[x][y]+=score;
}
}
}
/*
bool over(int x,int y,int w)
{
int score;
if(w==FF)
{
for(int i=0;i<tot;i++)
{
score=1;
if(first[i].ok==false)
continue;
for(int j=0;j<5;j++)
{
if(first[i].x[j]==x && first[i].y[j]==y)
{
int k=j-1;
while(k>=0 && first[i].is_used[k]==true)
{
k--;
score++;
}
k=j+1;
while(k<5 && first[i].is_used[k]==true)
{
k++;
score++;
}
if(score==5)
return true; //赢了
break; // 找到了某些点,但是没有赢
}
}
}
}
else
{
for(int i=0;i<tot;i++)
{
score=1;
if(second[i].ok==false)
continue;
for(int j=0;j<5;j++)
{
if(second[i].x[j]==x && second[i].y[j]==y)
{
int k=j-1;
while(k>=0 && second[i].is_used[k]==true)
{
k--;
score++;
}
k=j+1;
while(k<5 && second[i].is_used[k]==true)
{
k++;
score++;
}
if(score==5)
return true;
break;
}
}
}
}
return false; //整个棋盘扫过没有赢
?????写完才发现.....是不是平台就可以自己判断了?
}
*/
void judge() //判断落子,传入当下要下者
{
int lianzi1=0,lianzi2=0,life=0,d=0;
for(int i=0;i<16;i++)
for(int j=0;j<16;j++)
com[i][j]=panfen[i][j];
for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
int lianul=0,lianu=0,lianur=0,lianl=0;
int duishou1=0,duishou2=0;
if(chess[i][j]==0)
{
judgehelp(i,j,SS);
judgehelp(i,j,FF);
for(int m=-1; m<=1; m++)
for(int n=-1; n<=1; n++)
{
if(m!=0 || n!=0) // 八个方向,正向搜4个点,到了空位则退出
{
for(int k=1;k<5;k++)
{
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==SS ) //对手
lianzi1++;
else if(chess[i+k*m][j+k*n]==0)
{
life++;
break;
}
else
break;
}
for(int k=-1;k>-5;k--) //反向搜4个点,到了空位则退出
{
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==SS )
lianzi1++;
else if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==0)
{
life++;
break;
}
else
break;
}
if(lianzi1==1)
com[i][j]+=2;
else if(lianzi1==2)
{
if(life==1)
com[i][j]+=10;
else if(life==2)
com[i][j]+=15;
}
else if(lianzi1==3)
{
if(life==1)
com[i][j]+=20;
else if(life==2)
com[i][j]+=1200;
}
else if(lianzi1==4)
{
com[i][j]+=7000;
}
else if(lianzi1>=5)
{
com[i][j]+=100000;
}
life=0;
for(int k=1;k<5;k++)
{
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==FF )
lianzi2++;
else if( in(i+k*m,j+k*n) && chess[i+k*m][i+k*n]==0)
{
k++;
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==SS)
duishou1++;
life++;
break;
}
else
{
duishou1++;
break;
}
}
for(int k=-1;k>-5;k--)
{
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==FF )
lianzi2++;
else if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==0)
{
k--;
if( in(i+k*m,j+k*n) && chess[i+k*m][j+k*n]==SS)
duishou2++;
life++;
break;
}
else
{
duishou2++;
break;
}
}
if(i<=1||i>=14||j<=1||j>=14)
com[i][j]-=200;
if(lianzi2==1)
{
com[i][j]+=4;
if(lianzi1==1)
com[i][j]+=10;
if(lianzi1>=3)
com[i][j]+=200;
if(lianul||lianu||lianur||lianl)
com[i][j]+=5;
if(duishou1||duishou1)
com[i][j]-=2;
}
else if(lianzi2==2)
{
if(life==1)
com[i][j]+=20;
else if(life==2)
com[i][j]+=40;
if(duishou1||duishou1)
com[i][j]-=15;
if(lianzi1==2)
com[i][j]+=10000;
if(lianul==3||lianu==3||lianur==3||lianl==3)
com[i][j]+=250;
}
else if(lianzi2==3)
{
if(life==1)
com[i][j]+=250;
else if(life==2)
com[i][j]+=1300;
if(duishou2||duishou1)
com[i][j]-=200;
if(!duishou2&&!duishou1&&lianzi1==1)
com[i][j]+=10000;
if(!duishou2&&!duishou1&&lianul>=3||lianu>=3||lianur>=3||lianl>=3)
com[i][j]+=500;
}
else if(lianzi2==4)
{
com[i][j]+=10000;
if(duishou2||duishou1)
com[i][j]-=500;
if(!duishou2&&!duishou1&&lianzi1>=1)
com[i][j]+=10000;
if(!duishou2&&!duishou1&&(lianul>=3||lianu>=3||lianur>=3||lianl>=3))
com[i][j]+=2500;
}
//判断双三等等
if(m==-1&&n==-1)
{
lianul=max(lianzi1,lianzi2);
}
else if(m==-1&&n==0)
{
lianu=max(lianzi1,lianzi2);
}
else if(m==-1&&n==1)
{
lianur=max(lianzi1,lianzi2);
}
else if(m==0)
{
lianl=max(lianzi1,lianzi2);
}
lianzi1=0;
lianzi2=0;
life=0;
}
}
}
}
}
void find() //这是电脑落子的函数
{
int maxn=-1;
int c,d;
judge();
for(int i=0;i<15;i++)
for(int j=0;j<15;j++)
{
if(com[i][j]>maxn)
{
maxn=com[i][j];
c=i;
d=j;
}
}
printf("%d %d\n",c+1,d+1);
}
int main()
{
int sum=0;
char ch;
for(int i=0;i<15;i++)
{
for(int j=0;j<15;j++)
{
ch=getchar();
chess[i][j]=ch-'0';
if(chess[i][j])
sum++;
}
getchar();
}
init();
if(sum&1) //奇数为second
{
FF=2;SS=1;
}
else
{
FF=1;SS=2;
}
find();
return 0;
}