五子棋程序练习

又到一年寒假集训时,看着大一萌新们开始正式写五子棋游戏了,去年我们也是写的五子棋。我的五子棋没有用到AlphaBeta剪枝,就一层估值,虽没能干掉大佬的AI,但也还获得了一个小奖品。那时自己确实实力不够,连AlphaBeta套板都不会,想在想想,要是做个哪怕3层的估值效果应该也会好一点吧,当然没有加算杀优化等实力也不会强到哪里去。我的这个五子棋说起来也惭愧,它的棋型估值部分也是网上找的,虽是一层,我竟然还输过。现将代码(C++)公开以供大家参考交流!

#include<cstdio>
#include<cstring>
#include <conio.h>
#include<algorithm>
# define SPA 0
# define MAN 2
# define COM 1
using namespace std;

struct Chess_xy
{
    int x,y;
};
int trend[4][2][2]={{{1,0},{-1,0}},{{0,1},{0,-1}},{{1,1},{-1,-1}},{{-1,1},{1,-1}}};
int map[16][16]={0};
int map_val[16][16]={0};

struct stepp//用来定义最大价值棋子位置的结构体 
{
    int x,y,val;
};
stepp stpp;



void ChessMap_1()
{
    printf("  ");
    for(int i=1; i<=15; i++)
        if(i<=9) printf(" %d",i);
        else printf("%d",i);
    printf("\n"); 
    for(int i=1; i<=15; i++)
    {
        if(i<=9) printf("%d ",i);
        else printf("%d",i);
        if(i==1)
        {
            for(int j=1; j<=15; j++)
            {
                if(j==1)printf("┏");
                else if(j==15) printf("┓");
                else printf("┯");
            }

        }
        else if(i==15)
        {
            for(int j=1; j<=15; j++)
            {
                if(j==1)printf("┗");
                else if(j==15) printf("┛");
                else printf("┷");
            }
        }
        else
        {

            for(int j=1; j<=15; j++)
            {
                if(j==1)printf("┠");
                else if(j==15) printf("┨");
                else printf("┼");
            }
        }
        printf("\n");
    }
    return ;
} 

void ChessMap_2()
{
    printf("\n\n\n\n\n");
    printf("  ");
    for(int i=1; i<=15; i++)
        if(i<=9) printf(" %d",i);
        else printf("%d",i);
    printf("\n"); 
    for(int i=1; i<=15; i++)
    {
        if(i<=9) printf("%d ",i);
        else printf("%d",i);
        if(i==1)
        {
            for(int j=1; j<=15; j++)
            {
                if(map[i][j]==1) printf("○");
                else if(map[i][j]==2) printf("●");
                else if(j==1)printf("┏");
                else if(j==15)printf("┓");
                else printf("┯");
            }

        }
        else if(i==15)
        {
            for(int j=1; j<=15; j++)
            {
                if(map[i][j]==1) printf("○");
                else if(map[i][j]==2) printf("●");
                else if(j==1)printf("┗");
                else if(j==15)printf("┛");
                else printf("┷");
            }
        }
        else
        {

            for(int j=1; j<=15; j++)
            {
                if(map[i][j]==1) printf("○");
                else if(map[i][j]==2) printf("●");
                else if(j==1) printf("┠");
                else if(j==15) printf("┨");
                else printf("┼");
            }
        }
        printf("\n");
    }
    return;
}

int judge(int i,int j,int groal)//map[i][j]当前落子位置 
{
    Chess_xy chess,ches;
    int count[4]={1,1,1,1};
    for(int k=0; k<4; k++)//横竖两斜四个大方向分别检索 
    {
        chess.x=i+trend[k][0][0]; chess.y=j+trend[k][0][1];//第一个小方向 
        if(  (map[chess.x][chess.y]==groal) && (chess.x>=1) && (chess.y<=15) && (chess.x<=15) && (chess.y>=1) )
        {
            count[k]++;
            if(count[k]>=5) return groal;
            ches.x=chess.x; ches.y=chess.y;
            for(int kk=1; kk<=3; kk++)
            {
                ches.x+=trend[k][0][0]; ches.y+=trend[k][0][1];
                if(  (map[ches.x][ches.y]==groal) && (ches.x>=1) && (ches.y<=15) && (ches.x<=15) && (ches.y>=1) )
                {
                    count[k]++;
                    if(count[k]>=5) return groal;
                }
                else break;
            }

        }
        chess.x=i+trend[k][1][0]; chess.y=j+trend[k][1][1];//第二个小方向 
        if(  (map[chess.x][chess.y]==groal) && (chess.x>=1) && (chess.y<=15) && (chess.x<=15) && (chess.y>=1) )
        {
            count[k]++;
            if(count[k]>=5) return groal;
            ches.x=chess.x; ches.y=chess.y;
            for(int kk=1; kk<=3; kk++)
            {
                ches.x+=trend[k][1][0]; ches.y+=trend[k][1][1];
                if(  (map[ches.x][ches.y]==groal) && (ches.x>=1) && (ches.y<=15) && (ches.x<=15) && (ches.y>=1) )
                {
                    count[k]++;
                    if(count[k]>=5) return groal;
                }
                else break;
            }
        }
    }
    return 0;
} 




void yiwei(int n,int *i,int *j)        /* 在n方向上对坐标 i j 移位 n为1-8方向 从右顺时针开始数 */
{
    switch(n)
    {
        case 1: *i+=1; break;
        case 2: *i+=1; *j+=1; break;
        case 3: *j+=1; break;
        case 4: *i-=1; *j+=1; break;
        case 5: *i-=1; break;
        case 6: *i-=1; *j-=1; break;
        case 7: *j-=1; break;
        case 8: *i+=1; *j-=1; break;
    }
} 
int qixing(int n,int p,int q)            /* 返回空点p q在n方向上的棋型号 n为1-8方向 从右顺时针开始数 */ 
{
    int k,m=0;  /* 棋型号注解:  己活000-003 己冲010-013 对活100-103 对冲110-113 己空活020-023 己空冲030-033 对空活120-123 对空冲130-133 空-1 边界冲-2 边界空冲-3*/
    yiwei(n,&p,&q);
    if(p<1||p>15||q<1||q>15)
        k=-2;                                      /* 边界冲棋型 */
    switch(map[q][p])
    {
        case COM:
                {
                    m++; yiwei(n,&p,&q);
                    if(p<1||p>15||q<1||q>15) 
                    { 
                        k=m+9; 
                        return k; 
                    }
                     while(map[q][p]==COM) 
                    { 
                        m++; 
                        yiwei(n,&p,&q); 
                        if(p<1||p>15||q<1||q>15) 
                        { 
                            k=m+9; 
                            return k; 
                        } 
                    }
                    if(map[q][p]==SPA) 
                        k=m-1;                         /* 己方活棋型 */
                    else 
                        k=m+9;                                         /* 己方冲棋型 */
                }break;
        case MAN:
                {
                        m++; yiwei(n,&p,&q);
                        if(p<1||p>15||q<1||q>15) 
                        { 
                            k=m+109; 
                            return k; 
                        }
                        while(map[q][p]==MAN) 
                        { 
                            m++; 
                            yiwei(n,&p,&q); 
                            if(p<1||p>15||q<1||q>15) 
                            { 
                                k=m+109; 
                                return k; 
                            } 
                        }
                        if(map[q][p]==SPA) 
                            k=m+99;                         /* 对方活棋型 */
                        else 
                            k=m+109;                                        /* 对方冲棋型 */
                }break;
        case SPA:
                {
                    yiwei(n,&p,&q);
                    if(p<1||p>15||q<1||q>15) 
                    { 
                        k=-3; 
                        return k; 
                    }         /* 边界空冲棋型 */
                    switch(map[q][p])
                    {
                        case COM:
                                {
                                    m++; yiwei(n,&p,&q);
                                    if(p<1||p>15||q<1||q>15) 
                                    { 
                                        k=m+29; 
                                        return k; 
                                    }
                                    while(map[q][p]==COM) 
                                    { 
                                        m++; 
                                        yiwei(n,&p,&q); 
                                        if(p<1||p>15||q<1||q>15) 
                                        { 
                                            k=m+29; 
                                            return k; 
                                        } 
                                    }
                                    if(map[q][p]==SPA) k=m+19;                      /* 己方空活棋型 */
                                    else k=m+29;                                      /* 己方空冲棋型 */
                             }break;
                        case MAN:
                                {
                                    m++; yiwei(n,&p,&q);
                                    if(p<1||p>15||q<1||q>15) 
                                    { 
                                        k=m+129; 
                                        return k; 
                                    }
                                    while(map[q][p]==MAN)
                                    { 
                                        m++; 
                                        yiwei(n,&p,&q); 
                                        if(p<1||p>15||q<1||q>15) 
                                        { 
                                            k=m+129; 
                                            return k; 
                                        } 
                                    }           
                                    if(map[q][p]==SPA) 
                                        k=m+119;                     /* 对方空活棋型 */
                                    else 
                                        k=m+129;                                     /* 对方空冲棋型 */ 
                                }break;
                        case SPA: k=-1; break;                                         /* 空棋型 */
                    }
                }break;
    }
    return k;
}

int value(int p,int q) /* 计算空点p q的价值 以k返回 */ 
{
    int n=1,k=0,k1,k2,K1,K2,X1,Y1,Z1,X2,Y2,Z2,temp;  
    int a[2][4][4]={40,400,3000,10000,6,10,600,10000,20,120,200,0,6,10,500,0,30,300,2500,5000,2,8,300,8000,26,160,0,0,4,20,300,0};
           /* 数组a中储存己方和对方共32种棋型的值  己方0对方1    活0冲1空活2空冲3    子数0-3(0表示1个子,3表示4个子) */
    while(n!=5)
    {
        k1=qixing(n,p,q); n+=4;            /* k1,k2为2个反方向的棋型编号 */
        k2=qixing(n,p,q); n-=3;
        if(k1>k2) 
        { 
            temp=k1; 
            k1=k2; 
            k2=temp; 
        }  /* 使编号小的为k1,大的为k2 */
        K1=k1; K2=k2; 
              /* K1 K2储存k1 k2的编号 */
        Z1=k1%10; Z2=k2%10; k1/=10; k2/=10; Y1=k1%10; Y2=k2%10; k1/=10; k2/=10; X1=k1%10; X2=k2%10;
            /* X Y Z分别表示 己方0对方1    活0冲1空活2空冲3    子数0-3(0表示1个子,3表示4个子) */

        if(K1==-1) { if(K2<0) { k+=0; continue; } else k+=a[X2][Y2][Z2]+5; continue;  };    /* 空棋型and其他 */
        if(K1==-2) { if(K2<0) { k+=0; continue; } else k+=a[X2][Y2][Z2]/2; continue; };       /* 边界冲棋型and其他 */ 
        if(K1==-3) { if(K2<0) { k+=0; continue; } else k+=a[X2][Y2][Z2]/3; continue; };    /* 边界空冲棋型and其他 */ 
        if(((K1>-1 && K1<4) && ((K2>-1&&K2<4)|| (K2>9 && K2<14))) || ((K1>99 && K1<104) && ((K2>99 && K2<104) || (K2>109 && K2<114))))
        {
            /* 己活己活 己活己冲 对活对活 对活对冲 的棋型赋值*/
            if(Z1+Z2>=2) 
            { 
                k+=a[X2][Y2][3]; 
                continue; 
            }
            else 
            { 
                k+=a[X2][Y2][Z1+Z2+1]; 
                continue; 
            }
        }
        if(((K1>9 && K1<14) && (K2>9 && K2<14)) || ((K1>109 && K1<114) && (K2>109 && K2<114)))
        {
            /* 己冲己冲 对冲对冲 的棋型赋值*/
            if(Z1+Z2>=2) 
            { 
                k+=10000; 
                continue; 
            }
            else 
            { 
                k+=0; 
                continue; 
            }
        }
        if(((K1>-1 && K1<4) && ((K2>99 && K2<104) || (K2>109 && K2<114))) || ((K1>9 && K1<14) && ((K2>99 && K2<104) || (K2>109 && K2<114))))
        {
            /* 己活对活 己活对冲 己冲对活 己冲对冲 的棋型赋值*/
            if(Z1==3||Z2==3) 
            { 
                k+=10000; 
                continue; 
            }
            else 
            { 
                k+=a[X2][Y2][Z2]+a[X1][Y1][Z1]/4; 
                continue; 
            } 
        }
        else  
        { 
            k+=a[X1][Y1][Z1]+a[X2][Y2][Z2]; 
            continue;  
        }    /* 其他棋型的赋值 */
    }
    return k;
}

void AI()           /* 电脑下子 *p *q返回下子坐标 */
{
    int i,j,k,max=0,I,J;        /* I J为下点坐标 */
    for(j=1;j<=15;j++)
        for(i=1;i<=15;i++)
            if(map[j][i]==SPA)
            {      /* 历遍棋盘,遇到空点则计算价值,取最大价值点下子。 */
                k=value(i,j);
                if(k>=max) { I=i; J=j; max=k; }
            }
   stpp.y=I; stpp.x=J;
}

int main()
{
    int ST,ans,color,xx,yy;
    char YN;
    system("title   Gobang--Made by InspAlgo");
    system("mode con  cols=52 lines=23"); 
    printf("***********Welcome To AI System of Gobang***********\n");
    printf("输入:1 电脑先手\n");//1---black chess
    printf("输入:2 电脑后手\n");//2---white chess
    printf("输入:x y 表示落子点(!!!x为纵坐标,y为横坐标)\n"); 
    memset(map,0,sizeof(map));
    ChessMap_1();
    printf("请选择先后手:"); 
    scanf("%d",&ST);
    printf("\n");
    if(ST==1)
    {
        color=ST;
        map[2][5]=1;
        ChessMap_2();
        bb:;
        printf("请选择落子点:");
        scanf("%d %d",&xx,&yy);
        printf("\n");
        map[xx][yy]=3-color;
        ChessMap_2();
        ans=judge(xx,yy,3-color);
        if(ans==color)
        {
            printf("你输了,哈哈!AI要征服人类!吼吼~\n");
            system("pause");
            return 0;
        }
        if(ans==3-color)
        {
            printf("你赢了,好厉害!我弱,我战五渣!(ˇ^ˇ〉\n");
            system("pause");
            return 0;
        }
        AI();
        map[stpp.x][stpp.y]=color;
        ChessMap_2();
        printf("AI落子:%d %d\n",stpp.x,stpp.y);
        ans=judge(stpp.x,stpp.y,color);
        if(ans==color)
        {
            printf("你输了,哈哈!AI要征服人类!吼吼~\n");
            system("pause");
            return 0;
        }
        if(ans==3-color)
        {
            printf("你赢了,好厉害!我弱,我战五渣!(ˇ^ˇ〉\n");
            system("pause");
            return 0;
        }
        goto bb;

    }
    else
    {
        color=ST;
        aa:;
        printf("请选择落子点:");
        scanf("%d %d",&xx,&yy);
        printf("\n");
        map[xx][yy]=3-color;
        ChessMap_2();

        ans=judge(xx,yy,3-color);
        if(ans==color)
        {
            printf("你输了,哈哈!AI要征服人类!吼吼~\n");
            system("pause");
            return 0;
        }
        if(ans==3-color)
        {
            printf("你赢了,好厉害!我弱,我战五渣!(ˇ^ˇ〉\n");
            system("pause");
            return 0;
        }
        AI();
        map[stpp.x][stpp.y]=color;
        ChessMap_2();
        printf("AI落子:%d %d\n",stpp.x,stpp.y);
        ans=judge(stpp.x,stpp.y,color);
        if(ans==color)
        {
            printf("你输了,哈哈!AI要征服人类!吼吼~\n");
            system("pause");
            return 0;
        }
        if(ans==3-color)
        {
            printf("你赢了,好厉害!我弱,我战五渣!(ˇ^ˇ〉\n");
            system("pause");
            return 0;
        }
        goto aa;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38597315/article/details/79194417