五子棋AI设计

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;
}


你可能感兴趣的:(五子棋AI设计)