五子棋小游戏 C++代码(原创)

昂,第一次写那么大的程序,从有框架的想法到第一次正式运行总共耗时大概12小时吧。

各种新想法,新优化,debug什么的,目前会持续对其更新。

8说了,上代码,欢迎学习和意见。

(6.12今天VC出问题辽,差点代码就残缺了,还好有备份,然后才知道这个复制粘贴过去还得删除行数,太麻烦了,顺便把这里的代码显示行数关了,( •̀ .̫ •́ )✧还行吧。)

-----------------------------------------------------------------------------------------------

#include<bits/stdc++.h>
#include<windows.h>
typedef long double ll; 
int m,n;
char pan[15][15];
ll visx[15][15];
ll viso[15][15];
int f[]={-1,-1,-1, 0};//方向  | / — 
int g[]={-1, 0, 1,-1};
int CMcheck[5],Difficult,PRvis;
int special;
struct point
{
    int x,y;
}p;
//服务区 
void loading(int p);
int menu();
void funny();

//基本函数 
int pd(int x);
void Init();
void PR();
void PM();
void CM(int cn);
void get(int cn);
int check(int x,int y);
void win(char winner);
void CVis();
void Game();

//运算函数 
int CK(int i,int k,int j,int jcn,char x,int cn,int jc);
int ck(int i,int k,int j,char x,int cn);
ll BC(int i,int k,char X);
void jp(int i,int k,int j,int s[],ll &Q,ll &E,int &C,int p,char X);
void sl(int i,int k,int j,int C,int &c,char x); 
void BFS(int x,int y,char X,int key,ll up);


int main()
{
    srand((int)time(0));
    system("color");
    while(1)
    {
        int key=menu();
        system("cls");
        if(key==1)
        {
            loading(4);
            puts("【提示:在落子时输入两个负数坐标可立即开始新的一局嗷】

输入格式为【数字空格数字】

回车键确认 ~( ̄▽ ̄)~
");
            getchar();
            Game();
        }
        else if(key==0)
        {
            puts("
好吧,希望下次能与您切磋  *( ̄︶ ̄)*
");
            break;
        }
        else puts("请按格式输入确认进行游戏~   ~( ̄▽ ̄)~  ");
    }
    return 0;
}

int menu()
{
    int choice;special=0;
    do
    {
        printf("




开发者:弥攸——可以关注公众号:33[32m 代码小帮手 33[0m q(≧▽≦q)

");
        printf("===========================
");
        printf("||                       ||
");
        printf("||      1.开始游戏       ||
");
        printf("||                       ||
");
        printf("||      0.结束游戏       ||
");
        printf("||                       ||
");
        printf("===========================
");
        printf("请输入您的选择:");
        
        scanf("%d",&choice);
        if(choice!=1&&choice!=0)funny();
    }while(choice!=1&&choice!=0);
    if(!choice)return 0;
    do
    {
        system("cls");
        loading(1);
        printf("=========================================
");
        printf("||                                     ||
");
        printf("||   1.以 【左 上】 为(0,0)的棋盘   ||
");
        printf("||        (先纵坐标,再横坐标)        ||
");
        printf("||                                     ||
");
        printf("||   2.以 【左 下】 为(0,0)的棋盘   ||
");
        printf("||        (先横坐标,再纵坐标)        ||
");
        printf("||                                     ||
");
        printf("=========================================
");
        printf("请您选择更习惯的棋盘:");
        scanf("%d",&PRvis);
        if(PRvis!=1&&PRvis!=2)funny();
    }while(PRvis!=1&&PRvis!=2);
    
    do
    {
        system("cls");
        loading(2);
        printf("请您继续选择棋盘规格N 【5<=N<=15】:");
        scanf("%d",&m);n=m;
        if(m>15||m<5)
        {
            puts("
不符合规格嗷,请重新输入 ~( ̄▽ ̄)~ ");
            Sleep(2000);
            system("cls");
        }
    }while(m>15||m<5);
    
    do
    {
        system("cls");
        loading(3);
        printf("=================================
");
        printf("||                             ||
");
        printf("||       1.无心插柳柳成荫      ||
");
        printf("||                             ||
");
        printf("||       2.简单套路你能行      ||
");
        printf("||                             ||
");
        printf("||       3.唯有套路得我心      ||
");
        printf("||                             ||
");
        printf("||       4.人家叫我分水岭      ||
");
        printf("||                             ||
");
        printf("||       5.我若先手我无敌      ||
");
        printf("||                             ||
");
        printf("||       6.我就先手试试看      ||
");
        printf("||                             ||
");
        printf("=================================
");
        printf("请选择难度:");
        scanf("%d",&Difficult);
        getchar();
        if(Difficult<1||Difficult>6)funny();
    }while(Difficult<1||Difficult>6);
    return 1;
}

void funny()
{
    puts("");
    char s[99]={"看不见没有那个选项嘛? 不要对我有其他想法  我只是个没有感情的杀手"};
    for(int i=0;s[i];++i)
    {
        printf("%c",s[i]);
        Sleep(50);
        if(i==21)Sleep(400);
        if(i==40)Sleep(400);
    }
    Sleep(600);
    puts("   ( ̄へ ̄) ");
    Sleep(1000);
    puts("
别搞事情嗷  ( ̄▽ ̄) ");
    Sleep(2000);
    system("cls");
    return ;
}

void loading(int p)
{
    if(p!=4)
    {
        printf("
============================
");
        printf("||    游戏准备进程:%d/4   ||
",p);
        printf("============================

");
    }
    else
    {
        printf("
============================
");
        printf("||      游戏即将开始啦    ||
");
        printf("============================

");
    }
    printf("开发者:弥攸——可以关注公众号:33[32m 代码小帮手 33[0m q(≧▽≦q)

");
    return ;
}
void Init()
{
    for(int i=0;i<m;++i)
    for(int k=0;k<n;++k)
    {
        visx[i][k]=0;
        viso[i][k]=0;
        pan[i][k]=' ';
    }
}

int pd(int x)
{
    if(x<0||x>=m)return 0;
    return 1;
}

void swap()
{
    int t=p.y;
    p.y=p.x;
    p.x=m-t-1;
}

void PR()
{
    /*/
    //(以下是调试使用) 
    puts("CVis  X图:");
    printf("    ");
    for(int k=0;k<n;++k)
    printf("  %2d  ",k);
    puts(""); 
    for(int i=0;i<m;++i)
    {
        printf("    ");
        for(int k=0;k<n;++k)
        printf(" -----"); 
        puts("");
        
        for(int k=0;k<n;++k)
        {
            if(!k)printf("%2d:|",i);
            printf("%4.1lf |",visx[i][k]);
        }
        puts("");
        if(i==m-1)
        {
            printf("    ");
            for(int k=0;k<n;++k)
            printf(" -----"); 
            puts("");
        }
    }
    
    
    puts("CVis  O图:");
     printf("    ");
    for(int k=0;k<n;++k)
    printf("  %2d  ",k);
    puts(""); 
    for(int i=0;i<m;++i)
    {
        printf("    ");
        for(int k=0;k<n;++k)
        printf(" -----"); 
        puts("");
        
        for(int k=0;k<n;++k)
        {
            if(!k)printf("%2d:|",i);
            printf("%4.1lf |",viso[i][k]);
        }
        puts("");
        if(i==m-1)
        {
            printf("    ");
            for(int k=0;k<n;++k)
            printf(" -----"); 
            puts("");
        }
    }
    //*/
    system("cls");
    puts("
目前棋盘:
");
    int version=PRvis;
    if(version==1)
    {
        //以左上为00的坐标 
        printf("    ");
        for(int k=0;k<n;++k)
        printf("  %2d ",k);
        puts(""); 
        for(int i=0;i<m;++i)
        {
            printf("    ");
            for(int k=0;k<n;++k)
            printf(" ----"); 
            puts("");
            
            for(int k=0;k<n;++k)
            {
                if(!k)printf("%2d:|",i);
                if(i==p.x&&k==p.y)
                {
                    printf("  ");
                    printf("33[32m%c33[0m",pan[i][k]);
                    printf(" |");
                }
                else printf("  %c |",pan[i][k]);
            }
            puts("");
            if(i==m-1)
            {
                printf("    ");
                for(int k=0;k<n;++k)
                printf(" ----"); 
                puts("");
            }
        }
    }
    if(version==2)
    {
        //以左下为00的坐标
        for(int i=0;i<m;++i)
        {
            printf("    ");
            for(int k=0;k<n;++k)
            printf(" ----"); 
            puts("");
            
            for(int k=0;k<n;++k)
            {
                if(!k)printf("%2d:|",m-i-1);
                if(i==p.x&&k==p.y)
                {
                    printf("  ");
                    printf("33[32m%c33[0m",pan[i][k]);
                    printf(" |");
                }
                else printf("  %c |",pan[i][k]);
            }
            puts("");
            if(i==m-1)
            {
                printf("    ");
                for(int k=0;k<n;++k)
                printf(" ----"); 
                puts("");
            }
        }
        printf("    ");
        for(int k=0;k<n;++k)
        printf("  %2d ",k);
        puts("");  
    }
}

void PM()
{
    puts("该您下棋咯~~~ ");
    while(~scanf("%d %d",&p.x,&p.y))
    {
        if(p.x<0)
        {
            special=1;
            break;
        }
        if(PRvis==2)swap(); 
        if(!pd(p.x)||!pd(p.y))
        {
            puts("坐标超出范围,请重新输入 ~( ̄▽ ̄)~");
            continue;
        }
        if(pan[p.x][p.y]!=' ')
        {
            printf("坐标已被占用,请重新输入 ~( ̄▽ ̄)~
");
            continue;
        }
        pan[p.x][p.y]='x';
        visx[p.x][p.y]=-1;
        viso[p.x][p.y]=-1;
        CVis();
        break;
    }
}

void CM(int cn)
{
    puts("
( = ̄ω ̄= )思考中~~
");
    Sleep(300);
    get(cn);
    /*
    scanf("%d %d",&p.x,&p.y);//方便调试 
    if(PRvis==2)swap(); 
    //*/ 
    pan[p.x][p.y]='o';
    CVis();
    puts("( = ̄ω ̄= )我想到啦!");
    Sleep(500);
}

void get(int cn)
{
    if(Difficult==1)
    {
        int ok=0;
        while(!ok)
        {
            p.x=rand()%m;
            p.y=rand()%n;
            if(pan[p.x][p.y]==' ')ok=1;
        }
    }
    else   //点数优先级
    { 
        ll maxx=0;
        ll maxo=-1;//取-1是为了防止后期全为零优势点(濒临和棋的情况)而乱取坐标 
        int a,b,c,d; 
        
        if(cn==m*n-2) 
        {
            do
            {
                c=rand()%(m/3)+m/3;
                d=rand()%(n/3)+n/3;
            }while(pan[c][d]!=' ');//第一点趋中优势
            p.x=c,p.y=d;
            return ;
        }
        
        for(int i=0;i<m;++i)
        for(int k=0;k<n;++k)
        {
            if(pan[i][k]==' ')
            {
                if(visx[i][k]>maxx)
                {
                    maxx=visx[i][k];
                    a=i;b=k;
                }
                if(viso[i][k]>maxo)
                {
                    maxo=viso[i][k]; 
                    c=i;d=k;
                }
            } 
        }
        if(maxo>=maxx)p.x=c,p.y=d;//优胜 
        else if(maxx>=2)//防胜 
        {
            p.x=a,p.y=b;
        }
        else p.x=c,p.y=d;//任意优势点(可优化)
        visx[p.x][p.y]=-1;
        viso[p.x][p.y]=-1; 
    }
}
//                        jcs数    x/o   上1/下0   jc延伸数 
int CK(int i,int k,int j,int jcn,char x,int cn,int jc) 
{
    //计算 空三或者 3连+1白 
    char dx;
    dx=x=='x'?'o':'x';
    
    if(cn)// 空3  和  3+1白 
    {//     当前方向有两个 且 边缘点是自己     或者    有三点  且     有一边是空白       反向点                              延伸点
        if((jcn==2&&pan[i+jc*f[j]][k+jc*g[j]]==x)||(jcn==3 && ( (dx!=pan[i-f[j]][k-g[j]]&&pd(i-f[j])&&pd(k-g[j])) || (dx!=pan[i+jc*f[j]][k+jc*g[j]]&&pd(i+jc*f[j])&&pd(k+jc*g[j])) )))return 1;
    }
    else
    {//         同上   
        if((jcn==2&&pan[i-jc*f[j]][k-jc*g[j]]==x)||(jcn==3 && ( (dx!=pan[i+f[j]][k+g[j]]&&pd(i+f[j])&&pd(k+g[j])) || (dx!=pan[i-jc*f[j]][k-jc*g[j]]&&pd(i-jc*f[j])&&pd(k-jc*g[j])) )))return 1;
    }
    return 0;
}
//                         x/o     模式/上/下 
int ck(int i,int k,int j,char x,int cn) 
{
    //计算 1+1和2 点情况 
    char dx;
    dx=x=='x'?'o':'x';
    int ls,lx,ys=0,yx=0,firs=0,firx=0;
    //    ls,lx分别记录 当前方向 的 向上向下两种情况 
    //    fir两种分别记录两向 
    for(ls=1;pan[i+ls*f[j]][k+ls*g[j]]!=dx&&pd(i+ls*f[j])&&pd(k+ls*g[j])&&ls<5;ls++)
    if(pan[i+ls*f[j]][k+ls*g[j]]==x&&ls<=3)
    {
        if(!firs)firs=ls;
        ys++;
    }
    for(lx=1;pan[i-lx*f[j]][k-lx*g[j]]!=dx&&pd(i-lx*f[j])&&pd(k-lx*g[j])&&lx<5;lx++)
    if(pan[i-lx*f[j]][k-lx*g[j]]==x&&lx<=3)
    {
        if(!firx)firx=lx;
        yx++;
    }
    if(!cn)//   1+1有效边的情况 
    { //   1+1点距大于3  或者 邻点不为空(lx/ls数字 (停止点) 必须不为邻点)  或者 长度被限制  或者  不属于延伸边 (没有自己)   
        if(firs+firx>3||firs+1==ls||firx+1==lx||ls+lx<7||ls<3||lx<3||ys!=1||yx!=1)return 0;
        return 1;
    }
    else//   2点有效边情况 
    {//    长度限制           点数要求                                        两边为空 
        if(ls+lx>6&&((cn==1&&ys>=2)||(cn==2&&yx>=2))&&pan[i+(ls-1)*f[j]][k+(ls-1)*g[j]]==' '&&pan[i-(lx-1)*f[j]][k-(lx-1)*g[j]]==' ')return 1;
        return 0;
    }
}
void jp(int i,int k,int j,int s[],ll &Q,ll &E,int &C,int p,char X) 
{
    //基本点判断   
    char x,dx;
    if(p)x='x',dx='o';
    else x='o',dx='x';
    int js=0;
    for(s[0]= f[j],s[1]= g[j];pd(i+s[0])&&pd(k+s[1])&&x==pan[i+s[0]][k+s[1]];s[0]+=f[j],s[1]+=g[j],Q++);
    for(s[2]=-f[j],s[3]=-g[j];pd(i+s[2])&&pd(k+s[3])&&x==pan[i+s[2]][k+s[3]];s[2]-=f[j],s[3]-=g[j],E++);
    //   3+1 或者2+2 限制点 
    if((Q==3&&E==1)||(E==3&&Q==1)||(Q>=2&&E>=2))Q=8,js=1;
    else
    {
        // 数学运算 
        if(Q>2)Q+=Q-2;
        if(E>2)E+=E-2;
        if(Q>0&&E>0&&pd(i+s[0])&&pd(i+s[2])&&pd(k+s[3])&&pd(k+s[1])&&' '==pan[i+s[2]][k+s[3]]&&' '==pan[i+s[0]][k+s[1]])Q++;//简单优化 
        Q+=E;
    }
    //   四连点强化 
    if(Q>=6)Q=8;//补上> :bug x_xxxx| 空点为7.0 
    // 2+1点强化 
    if(Q==4&&(E==1||E==2)&&pd(i+s[0])&&pd(i+s[2])&&pd(k+s[3])&&pd(k+s[1])&&' '==pan[i+s[2]][k+s[3]]&&' '==pan[i+s[0]][k+s[1]])Q=7.1,js=1;
    if(js)
    {
        C=0;
        if(X!=' ')return ;
        if(p)visx[i][k]=Q;
        else viso[i][k]=Q;
    }
    //下面是3连的QE两种情况 
    if(Q==4&&E==0)
    {
        if(!pd(i+s[0])||!pd(k+s[1])||pan[i+s[0]][k+s[1]]!=' ')Q-=2;
        else if(!pd(i-f[j])||!pd(k-g[j])||pan[i-f[j]][k-g[j]]==dx)Q--; 
        else 
        {
            Q=6.9;
            if(X==' ')Q=7.1;
        }
    }
    if(E==4&&Q==4)
    {
        if(!pd(i+s[2])||!pd(k+s[3])||pan[i+s[2]][k+s[3]]!=' ')Q-=2;
        else if(!pd(i+f[j])||!pd(k+g[j])||pan[i+f[j]][k+g[j]]==dx)Q--;
        else 
        {
            Q=6.9;
            if(X==' ')Q=7.1;
        }
    }
}
void sl(int i,int k,int j,int C,int &c,char x)
{
    //死路优化 
    char dx;
    dx=x=='x'?'o':'x';
    
    int Q,E,y;//分开对各向长度考虑 + //判断属于延伸
    if(C)
    {
        for(Q=1;dx!=pan[i+Q*f[j]][k+Q*g[j]]&&pd(i+Q*f[j])&&pd(k+Q*g[j])&&Q<5;Q++)if(pan[i+Q*f[j]][k+Q*g[j]]==x)y=1; 
        for(E=1;dx!=pan[i-E*f[j]][k-E*g[j]]&&pd(i-E*f[j])&&pd(k-E*g[j])&&E<5;E++)if(pan[i-E*f[j]][k-E*g[j]]==x)y=1;
        //长度限制     且当前点优先级不高   在此方向不对该点赋值 
        if(Q+E<6&&y&&((x=='x'&&visx[i][k]<6)||(x=='o'&&viso[i][k]<6)))c=0;
    }
}
 
ll BC(int i,int k,char X)
{
    if(Difficult==1)return 0;
    //记录当前点的值,返回给BFS 
    ll value=0;
    //记录当前点周围有效边数量 
    int disx=0,diso=0;
    //若有此点算是交叉点,则后面不再对该点赋值 
    int Cx=1,Co=1;
    //记录有效边类型 
    int tex=0,teo=0,twx=0,two=0;
    //遍历四个方向 
    for(int j=0;j<4;++j)
    {
        if(Difficult>2)
        {
            //交叉点判断 
            int jc,jcx,jco;
            //基本记录变量 
            int jx=0,jo=0;
            //记录当前直线有效边数量 
            for(jc=1,jcx=0,jco=0;pd(i+jc*f[j])&&pd(k+jc*g[j])&&jc<4;jc++)
            {
                //数学操作 
                if('o'==pan[i+jc*f[j]][k+jc*g[j]])jco++,jcx-=2;
                if('x'==pan[i+jc*f[j]][k+jc*g[j]])jcx++,jco-=2;
            }
            //不同情况操作 
            if(CK(i,k,j,jcx,'x',1,jc))disx++,jx++,tex=1;
            else if(ck(i,k,j,'x',1))disx++,jx++,twx=1;
            if(CK(i,k,j,jco,'o',1,jc))diso++,jo++,teo=1;
            else if(ck(i,k,j,'o',1))diso++,jo++,two=1;
            
            for(jc=1,jcx=0,jco=0;pd(i-jc*f[j])&&pd(k-jc*g[j])&&jc<4;jc++)
            {
                if('o'==pan[i-jc*f[j]][k-jc*g[j]])jco++,jcx-=2;
                if('x'==pan[i-jc*f[j]][k-jc*g[j]])jcx++,jco-=2;
            }
            if(CK(i,k,j,jcx,'x',0,jc))disx++,jx++,tex=1;
            else if((ck(i,k,j,'x',2)))disx++,jx++,twx=1;
            if(CK(i,k,j,jco,'o',0,jc))diso++,jo++,teo=1;
            else if(ck(i,k,j,'o',2))diso++,jo++,two=1;
            //1+1有效边 一条直线只判断一次 
            if(ck(i,k,j,'x',0))disx++,jx++,twx=1;
            if(ck(i,k,j,'o',0))diso++,jo++,two=1;
            //数学处理 
            if(disx>=2||diso>=2)
            {
                if(X==' ')
                {
                    visx[i][k]=7;
                    viso[i][k]=7;
                    if(twx==1&&tex==1)visx[i][k]=7.1;
                    if(two==1&&teo==1)viso[i][k]=7.1;
                }
                value=5;
                Cx=0;Co=0;//是交叉点,取消后续改变
                //数学处理 
                if(jx==2||jo==2)
                {
                    if(X==' ')
                    {
                        visx[i][k]++;
                        viso[i][k]++;
                    }
                    else value++;
                }
                break;
            }
        }
        //QE为当前方向取值,同jp函数 
        ll Qx=0,Ex=0,Qo=0,Eo=0;
        // 数组存方向延伸  cx/co  同CxCo 用于死路判断取消后续改变 
        int x[4],o[4],cx=1,co=1;
        jp(i,k,j,x,Qx,Ex,Cx,1,X);
        jp(i,k,j,o,Qo,Eo,Co,0,X);
        if(Qx>=7&&X=='x')return Qx;
        if(Qo>=7&&X=='o')return Qo;//有绝杀直接返回 
        //死路判断 
        sl(i,k,j,Cx,cx,'x');
        sl(i,k,j,Co,co,'o');
        if(!cx&&!co)continue;//优化处理 
        if(X==' ')
        {
            if(Qx>visx[i][k]&&Cx&&cx)visx[i][k]=Qx;
            if(Qo>viso[i][k]&&Co&&co)viso[i][k]=Qo;
        }
        else
        {
            if(X=='x'&&Qx>value&&Cx&&cx)value=Qx;
            if(X=='o'&&Qo>value&&Co&&co)value=Qo;
        }
    }
    return value;
}
void BFS(int x,int y,char X,int key,ll up)//低值空白点 -> 谋略计算优先级 
{
    //假设预算法,本来应该有后续遍历的,但没想到一次遍历就很强了,就没写后续 
    pan[x][y]=X;
    ll value;int tp,sk=0;
    //tp 用于延伸方向判断长度  
    char dx;
    dx=x=='x'?'o':'x'; 
    for(int j=0;j<4;++j)//四条直线方向  每线搜索3*2个点   
    {
        for(int jc= 1,tp=0;pd(x+jc*f[j])&&pd(y+jc*g[j])&&pan[x+jc*f[j]][y+jc*g[j]]!=dx&&jc<4+tp;++jc)
        {
            //如果该点是敌对点,延伸 
            if(pan[x+jc*f[j]][y+jc*g[j]]==X)tp++;
            //不存在或者为空跳过 
            if(!pd(x+jc*f[j])||!pd(y+jc*g[j])||pan[x+jc*f[j]][y+jc*g[j]]!=' ')continue;
            // 数学操作   该点值本身过大 不计入假设影响 
            if(X=='x'&&visx[x+jc*f[j]][y+jc*g[j]]>=5)continue;
            if(X=='o'&&viso[x+jc*f[j]][y+jc*g[j]]>=5)continue;
            
            value=BC(x+jc*f[j],y+jc*g[j],X);
            up+=value;// up用于存影响值 
            
            if(value>=5)sk++;if(value>=7)sk++,key++;//数学操作 
        }
        for(int jc= 1,tp=0;pd(x-jc*f[j])&&pd(y-jc*g[j])&&pan[x-jc*f[j]][y-jc*g[j]]!=dx&&jc<4+tp;++jc)
        {
            if(pan[x-jc*f[j]][y-jc*g[j]]==X)tp++;
            if(!pd(x-jc*f[j])||!pd(y-jc*g[j])||pan[x-jc*f[j]][y-jc*g[j]]!=' ')continue;
             
            if(X=='x'&&visx[x-jc*f[j]][y-jc*g[j]]>=5)continue;
            if(X=='o'&&viso[x-jc*f[j]][y-jc*g[j]]>=5)continue;
            value=BC(x-jc*f[j],y-jc*g[j],X);
            up+=value;
            if(value>=5)sk++;if(value>=7)sk++,key++;
        }
    }
    if(Difficult>4)
    {
        //下为数学操作,赋值处理,没有解释,数据是长期多次测试获取的  最优选择 
        if(key>=2)
        {
            if(X=='x')visx[x][y]=6;
            if(X=='o')viso[x][y]=6;
        }
        else if(sk>2)
        {
            if(X=='x'&&visx[x][y]<5)visx[x][y]=5;
            if(X=='o'&&viso[x][y]<5)viso[x][y]=5;
        }
        else
        {
            if(X=='x'&&visx[x][y]<6)visx[x][y]=up/5;
            if(X=='o'&&viso[x][y]<6)viso[x][y]=up/5;
        }
    }
    else
    {
        //降低难度  粗略处理数据 
        if(sk>2)
        {
            if(viso[x][y]<5)viso[x][y]=5;
        }
        else if(sk)
        {
            if(viso[x][y]<6)viso[x][y]=up/5;
        }
    }
    pan[x][y]=' ';
} 
void CVis()
{
    for(int i=0;i<m;++i)
    for(int k=0;k<n;++k)
    {
        if(pan[i][k]==' ')
        {
            visx[i][k]=0;
            viso[i][k]=0;
            BC(i,k,' ');
        }
    }
    if(Difficult>3)
    {
        for(int i=1;i<m-1;++i)
        for(int k=1;k<n-1;++k)
        {
            if(pan[i][k]==' ')
            {
                if(visx[i][k]<5)BFS(i,k,'x',0,0);
                if(viso[i][k]<5)BFS(i,k,'o',0,0);
            }
        }
    }
    return ;
}

void win(char winner)
{
    puts("");
    if(winner=='x')
    {
        printf("咦!Σ(っ°Д°)っ	");
        Sleep(1000);
        char S[200]={"好吧,虽然很不想承认...    是我输了!
"};
        for(int i=0;S[i];++i)
        {
            printf("%c",S[i]);
            if(i==5||i==25)Sleep(500);
            Sleep(50);
        }
        Sleep(1500);
        if(Difficult!=6)
        {
            char s[200]={"
但是!!!  还有更难的嗷  (~ ̄▽ ̄)~   

而且 , 通关后可以知道开发者的小故事呢 ~( ̄▽ ̄)~  祝您游戏愉快

"};
            for(int i=0;s[i];++i)
            {
                printf("%c",s[i]);
                if(i==10||i==40||i==50||i==92)Sleep(500);
                Sleep(50);
            }
        }
        else
        {
            int C;
            do
            {
                puts("
是否愿意听开发者的长故事?

1愿意	0不愿意"); 
                scanf("%d",&C);
            }while(C!=1&&C!=0);
            if(!C)return ;
            char s[]={"
恭喜通关啦, 说明你已经算是五子棋资深玩家了呢.   

"
            "其实呢.

为了降低降低难度, 难度6我留了一个漏洞, 我作为开发者, 在难度5就顶不住了.

"
            "大概用了两个星期才写好这个五子棋AI, 本来还有后续的, 发现已经很难了, 就没再继续写了.

"
            "嗯 , , 就这样吧, 谢谢您能玩我的游戏, 希望您能关注我的公众号,有福利嗷( ̄︶ ̄). 

"};
            for(int i=0;s[i];++i)
            {
                printf("%c",s[i]);
                if(s[i]==',')Sleep(500);
                if(i==223||i==225||s[i]=='.')Sleep(1000);
                Sleep(50);
            } 
        }
        Sleep(1500);
    }
    if(winner=='o')
    {
        printf("承让!承让!

");
        Sleep(1000);
        printf("要不~~~

");
        Sleep(2000);
        printf("再来一局试试? ( ̄▽ ̄) 
");
        Sleep(1000);
    }
    return ;
}

int check(int x,int y)
{
    for(int j=0;j<4;++j)
    {
        int i,p=4;
        for(i= 1; pd(x+i*f[j]) && pd(y+i*g[j]) && pan[x+i*f[j]][y+i*g[j]]==pan[x][y] && p ; ++i,--p);
        for(i=-1; pd(x+i*f[j]) && pd(y+i*g[j]) && pan[x+i*f[j]][y+i*g[j]]==pan[x][y] && p ; --i,--p);
        if(!p)
        {
            win(pan[x][y]);
            return 1;
        }
    }
    return 0;
}

void Game()
{
    Init();
    
    PR();
    
    int t=m*n;
    int cm=t%2;
    if(Difficult==6)
    {
        t--;
        cm=t%2;//重置出手序号 
        p.x=m/2;p.y=n/2;
        pan[p.x][p.y]='o';
        visx[p.x][p.y]=-1;
        viso[p.x][p.y]=-1;
        CVis();
        PR();
        if(PRvis==1)printf("电脑落子:【%d %d】
",p.x,p.y);
        else printf("电脑落子:【%d %d】
",p.y,m-p.x-1);
    }
    while(t--)
    {
        if(t%2==cm)CM(t);
        else PM();
        
        PR();
        
        if(t%2==cm)
        {
            if(PRvis==1)printf("电脑落子:【%d %d】
",p.x,p.y);
            else printf("电脑落子:【%d %d】
",p.y,m-p.x-1);
        }
        Sleep(1000);
        
        if(special)
        {
            system("cls");
            return ;
        }
        if(check(p.x,p.y))return ;
    }
    puts("
和棋啦 ~( ̄▽ ̄)~ ");
    return ; 
}
View Code

这是软件链接,可以直接下载试玩嗷。

链接:https://pan.baidu.com/s/17VD9yR0etH8YZWLES7sdIg
提取码:ps25 

试玩后觉得可以,想深度了解的话,可以关注并咨询微信公众号:代码小帮手。

-----------------------------------------------------------------------------------------------

2020.6.11(更新——修复了难度3电脑先手bug,微略提高了难度)

2020.6.11(更新——修复了难度3死亡bug,难度2优化,优化了对话框)

2020.6.12(更新——新增难度4,加入了几个经典策略,简单优化算法逻辑,添加了一些注释)

2020.6.14(更新——强化难度4,简单优化,加入大量注释,因为是纯数学+逻辑的算法,虽然有注释,但是想学习的还是难嗷 (~ ̄▽ ̄)~,另外, 今天战胜福院OJ的 AI 啦!o(* ̄▽ ̄*)o  )

2020.6.15(更新——改动函数调用顺序,添加游戏流程提示,微调难度4)

2020.6.19(更新——修复了不知道多少bug,精简了差不多8k代码量(保留原有并新增注释),主要在优化算法,但是难度怎么能没什么变化呢( •̀ .̫ •́ )✧,所以我又强化了难度4,并输给了(先手模式的难度4)难度5,输了一局,但着实没注意到死局已成,记录棋谱如下:

【开始,棋盘2,规格10,难度5,3 3,3 6,6 5,8 1,4 7,3 4,2 5,5 7,6 1,4 3】

然后我发现我没了( ̄_ ̄|||) ,还行吧,可能还会继续改进的。)

2020.7.1(更新——版本更新,焕然一新的那种( •̀ .̫ •́ )✧,跟福院榜一的AI对抗,不断更新算法,无数次突破,嗯……不说了,,由于难度大幅提升,所以重整难度,分为6种,棋盘面板多选,更补充了颜色提示,另外,这次可能会是最后一次更新,所以呢,我加入了大量注释,但是因为是逻辑转为数学算法(模拟),所以很多地方不能完全说明,只能大致理解,所以呢,要学习起来难度很大,原创性和独一性也就很强,全部代码行数800+,长度2w+,OVER)(加入了公众号宣传( ̄▽ ̄)哈)

2020.7.1(说明——算法优化数据是   跟   fjutacm里的   1015题的   超强AI的   AC榜的  榜一的   AI   对战,下面放战绩图,因为不便操作他人的代码,所以选择   全图225点的先手开局(我o) + 一局后手(胜),再此默默感谢他  (  ´ ▽ ` ʃ♡ƪ)  ,才让我的AI变得几乎没有死角,也因为如此,我的代码里面的数学数据无法多解释嗷,是很多很多次测试的最优选择,另外,我从那输掉的三局里看出了优化之处,但是因为我觉得别太难,留个漏洞,算是好事,而且我写的算法也只写了一部分,强度就大幅超出了我的预期,还有时间原因,就没再写下去了,OVER)

2020.7.5(说明——个人学习期,暂时不会更新AI,会收集整理优化游戏体验,强化AI的新想法,不会死更嗷o(* ̄▽ ̄*)o)

原文地址:https://www.cnblogs.com/Renhr/p/13082311.html