//转自:https://www.luogu.com.cn/paste/c1fvaio2
//作者:https://www.luogu.com.cn/user/217233
/*
制作者:SqrtSecond
版本号:v1.1.9 
v1.1.9更新内容:
压行 

v1.1.8更新内容:
修复了一些bug 

v1.1.7更新内容:
增加了设置页面和两个功能

v1.1.6更新内容:
1.增强了人机程序
2.修复了一些bug
3.更新了单人游戏的操作系统 

v1.1.5更新内容:
1.修改了棋盘边框系统,使64位电脑与32位电脑兼容
2.修改了键盘的控制系统 
3.增加新功能:按Enter或空格键可快速跳过剧情。
4.更新了5次神秘事件之后的buff特效
5.新增了人机系统和单人游戏

可以转载,但请务必注明出处!
*/
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
int Speed=3,pianhao=1;
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)
#define color(COLOR) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),COLOR);
void putss(string a)
{
    while(KEY_DOWN('\r')||KEY_DOWN(' '));
    bool flag=true;int len=a.length();
    for(int i=0;i<len-1;++i)
    {
        if(KEY_DOWN('\r')||KEY_DOWN(' '))flag=false;
        putchar(a[i]);
        if(flag)Sleep(Speed*10);
    }
    putchar(a[len-1]);
    while(KEY_DOWN('\r')||KEY_DOWN(' '));
}
int win1,win2,AIturn;bool flag,p;
int game(int turn);
void hint();
int Setting()
{
    system("cls");
    puts("速度调节——s\n");
    puts("键盘偏好——k\n");
    puts("退出——e\n");
    while(true)
    {
        if(KEY_DOWN('E')){while(KEY_DOWN('E'));return 0;}
        if(KEY_DOWN('S'))
        {
            while(true)
            {
                system("cls");
                color(112);for(int i=1;i<=6-Speed;++i)puts("  ");
                color(7);for(int i=6-Speed+1;i<=5;++i)puts("");
                printf("当前速度:%d\n",6-Speed);
                puts("按方向上下键进行设置,E键退出\n");
                while(true)
                {
                    if(KEY_DOWN(VK_UP))
                    {
                        while(KEY_DOWN(VK_UP));
                        Speed++;
                        if(Speed==6)Speed=5;
                        break;
                    }
                    if(KEY_DOWN(VK_DOWN))
                    {
                        while(KEY_DOWN(VK_DOWN));
                        Speed--;
                        if(Speed==0)Speed=1;
                        break;
                    }
                    if(KEY_DOWN('E')){while(KEY_DOWN('E'));return 1;}
                }
            }
        }
        if(KEY_DOWN('K'))
        {
            while(true)
            {
                system("cls");
                puts("按左右键进行设置,E键退出\n");
                puts(pianhao==0?"当前偏好:wsad控制方向,空格键放置棋子":"当前偏好:方向键控制方向,Enter键放置棋子");
                puts("\n注:本设置仅在单人游戏时有效");
                while(true)
                {
                    if(KEY_DOWN(VK_LEFT)||KEY_DOWN(VK_RIGHT))
                    {
                        pianhao=1-pianhao;
                        while(KEY_DOWN(VK_LEFT)||KEY_DOWN(VK_RIGHT));
                        break;
                    }
                    if(KEY_DOWN('E')){while(KEY_DOWN('E'));return 1;}
                }
            }
        }
    }
}
int home()
{
    system("cls");
    puts("主菜单\n");
    puts("开始游戏 —— s\n");
    puts("游戏说明 —— h\n");
    puts("设置 —— p\n");
    puts("退出 —— e\n");
    puts("制作人:SqrtSecond\n");
    puts("(P.S.按Enter或空格键可快速跳过剧情)"); 
    while(true)
    {
        if(KEY_DOWN('E'))
        {
            while(true)
            {
                system("cls");
                puts("确定要离开吗?\n");
                puts("是 —— y\n");
                puts("否 —— n\n");
                while(true)
                {
                    if(KEY_DOWN('N'))return 1;
                    if(KEY_DOWN('Y'))
                    {
                        system("cls");
                        puts("qwq");
                        return 0;
                    }
                }
            }
        }
        if(KEY_DOWN('H'))
        {
            hint();
            return 1;
        }
        if(KEY_DOWN('P'))
        {
            while(Setting());
            return 1;
        }
        if(KEY_DOWN('S'))
        {
            system("cls");
            putss("那么,开始游戏吧!\n");system("pause");
            system("cls");
            puts("你要玩什么模式?\n");
            puts("单人,人机先走——a\n");
            puts("单人,人机后走——b\n");
            puts("双人——c\n");
            win1=win2=0;p=0;
            while(true)
            {
                if(KEY_DOWN('A'))AIturn=1,p=1;
                if(KEY_DOWN('B'))AIturn=-1,p=1;
                if(KEY_DOWN('C'))AIturn=0,p=1;
                if(p)
                {
                    putss("好的,开始吧!");system("pause");
                    int r=1;
                    while(true)
                    {r=-game(r);if(r==0)break;}
                    return 1;
                }
            }
        }
    }
}
void hint()
{
    system("cls");
    putss("首先,这是一个双人游戏。\n");system("pause");
    putss("基本规则和标准的三子棋相同。\n");system("pause");
    putss("双方需要每人轮流下一手。\n");system("pause");
    putss("每人下完一手后,都会触发一个随机的事件。\n");system("pause");
    putss("有可能会消除场上已有的棋子……\n");system("pause");
    putss("但也有可能帮你多下一手棋!\n");system("pause");
    putss("这正是这个游戏的好玩之处。\n");system("pause");
    putss("也很靠运气。\n");system("pause");
    putss("另外……\n");system("pause");
    putss("别触发5次神秘事件,否则后果自负……\n");system("pause");
    putss("准备好了就开始吧!\n");system("pause");
    return;
}
int mp[5][5],X,Y;
void putchess()
{
    system("cls");
    printf("比分:%d:%d\n\n",win1,win2);
    puts("◤      ◥");
    for(int i=1;i<=3;++i)
    {
        printf("  ");
        for(int j=1;j<=3;++j)
        {
            if(X==i&&Y==j)color(112);
            printf(mp[i][j]==1?"×":mp[i][j]==-1?"○":"  ");
            if(X==i&&Y==j)color(7);
        }
        puts("  "); 
    }
    puts("◣      ◢");
}
int l;
int win()
{
    l=0;
    for(int i=1;i<=3;++i)
    {
        if(mp[i][1]+mp[i][2]+mp[i][3]==3)l=1;
        if(mp[i][1]+mp[i][2]+mp[i][3]==-3)l=-1;
        if(mp[1][i]+mp[2][i]+mp[3][i]==3)l=1;
        if(mp[1][i]+mp[2][i]+mp[3][i]==-3)l=-1;
    }
    if(mp[1][1]+mp[2][2]+mp[3][3]==3)l=1;
    if(mp[1][1]+mp[2][2]+mp[3][3]==-3)l=-1;
    if(mp[1][3]+mp[2][2]+mp[3][1]==3)l=1;
    if(mp[1][3]+mp[2][2]+mp[3][1]==-3)l=-1;
    if(l==0)
    {
        l=2;
        for(int i=1;i<=3;++i)for(int j=1;j<=3;++j)if(mp[i][j]==0)l=0;
    }
    if(l==2)
    {
        putchess();
        printf("恭喜双方打成平局!\n");system("pause");
        return true;
    }
    if(l!=0)
    {
        putchess();
        printf("%s获得了胜利!\n",l==1?(AIturn==1?"人机":AIturn==-1?"玩家":"玩家1"):(AIturn==-1?"人机":AIturn==1?"玩家":"玩家2"));system("pause");
        l==1?win1++:win2++;
        return true;
    }
    return false;
}
int xx,yy,h,boom,rx,ry,rz;
void effect(int playyer)
{
    rx=rand()%12+1;putchess();
    puts("事件发生!\n");system("pause");
    if(rx<=4)
    {
        ry=rand()%3+1;rz=rand()%3+1;mp[ry][rz]=0;
        putchess();printf("消除格子(%d,%d)!\n",ry,rz);
    }
    else if(rx==5)
    {
        ry=rand()%3+1;mp[ry][1]=mp[ry][2]=mp[ry][3]=0;
        putchess();printf("消除第%d行!\n",ry);
    }
    else if(rx==6)
    {
        ry=rand()%3+1;mp[1][ry]=mp[2][ry]=mp[3][ry]=0;
        putchess();printf("消除第%d列!\n",ry);
    }
    else if(rx==7)
    {
        mp[1][1]=mp[2][2]=mp[3][3]=0;
        putchess();printf("消除左上到右下的对角线!\n");
    }
    else if(rx==8)
    {
        mp[1][3]=mp[2][2]=mp[3][1]=0;
        putchess();printf("消除右上到左下的对角线!\n");
    }
    else if(rx==9)
    {
        do
        {
            ry=rand()%3+1;
            rz=rand()%3+1;
        }while(mp[ry][rz]);
        mp[ry][rz]=h;
        putchess();printf("帮你下一手(%d,%d)!\n",ry,rz);
    }
    else if(rx==10)
    {
        ry=rand()%2;
        if(ry)
        {
            for(int i=1;i<=3;++i)for(int j=1;j<=3;++j)mp[i][j]=-mp[i][j];
            putchess();printf("反转局势!!!");h=-h;
        }
        else puts("无事发生!(偷笑)");
    }
    else
    {
        boom++;
        if(boom==5)
        {
            system("color 4F");printf("神秘事件×%d!!!\n",boom);
            boom=0;system("pause");
            putss("5次神秘事件凑齐了……\n");Sleep(Speed*1000);
            putss("Windows的数据遭受了毁灭性的打击!!!\n");Sleep(Speed*1000);
            for(int i=1;i<=50;++i){system("color 2C");system("color AE");system("color 7A");system("color E4");system("color 58");system("color B6");}
            system("color 4F");
            for(int i=1;i<=3;++i)for(int j=1;j<=3;++j)mp[i][j]=0;
            putchess();
            MessageBox(NULL,"您的Windows可能出现了点问题。","Windows系统自动提示",MB_OK+48);
            MessageBox(NULL,"Windows正在尝试修复您的系统中……","Windows系统自动提示",MB_OK+64);
            MessageBox(NULL,"系统内部存储器已被破坏!","Windows系统自动提示",MB_OK+48);
            putss("数据已被破坏……请重新开始……\n");Sleep(Speed*1000);h=-1;
            int x=rand()%2;
            if(x){
            	MessageBox(NULL,"什么?你竟然活下来了!","天理",MB_OK+48);
            	MessageBox(NULL,"看来要加大打击力度","天理",MB_OK+48);
            	MessageBox(NULL,"一个计算机病毒以光速传入你的电脑","Windows系统自动提示",MB_OK+48);
            	system("shutdown -s -t 31");
            	
			}
        }
        else printf("神秘事件×%d!!!\n",boom);
    }
    system("pause");
    if(rx>=11)system("color 07");
}
/*
x=1,2,3,4(1/3):随机消除一个格子
x=5(1/12):随机消除一行
x=6(1/12):随机消除一列
x=7(1/12):消除左上到右下的对角线
x=8(1/12):消除左上到右下的对角线
x=9(1/12):帮自己下一手
x=10(1/12):反转局势或无事发生 
x=11,12(1/6):神秘事件 
*/
bool player1(){return (((h==1&&AIturn!=-1)||(h==-1&&AIturn==-1))&&pianhao==1)||(((h==1&&AIturn!=1)||(h==-1&&AIturn==1))&&pianhao==0);}
void puthint(){printf("现在轮到%s(执%s)了,你要下在哪一行,哪一列?%s\n",h==1?(AIturn==1?"人机":AIturn==-1?"玩家":"玩家1"):(AIturn==-1?"人机":AIturn==1?"玩家":"玩家2"),h==1?"×":"○",player1()?"(用wsad控制方向,空格键放置棋子)":"(用方向键控制方向,Enter键放置棋子)");}
int AI(int t)
{
    for(int i=1;i<=3;++i)
    {
        if(mp[i][1]+mp[i][2]+mp[i][3]==2*t)return mp[i][1]==0?i*3+1:mp[i][2]==0?i*3+2:i*3+3;
        if(mp[1][i]+mp[2][i]+mp[3][i]==2*t)return mp[1][i]==0?1*3+i:mp[2][i]==0?2*3+i:3*3+i;
    }
    if(mp[1][1]+mp[2][2]+mp[3][3]==2*t)return mp[1][1]==0?4:mp[2][2]==0?8:12;
    if(mp[1][3]+mp[2][2]+mp[3][1]==2*t)return mp[1][3]==0?6:mp[2][2]==0?8:10;//判断己方二子连珠
    for(int i=1;i<=3;++i)
    {
        if(mp[i][1]+mp[i][2]+mp[i][3]==-2*t)return mp[i][1]==0?i*3+1:mp[i][2]==0?i*3+2:i*3+3;
        if(mp[1][i]+mp[2][i]+mp[3][i]==-2*t)return mp[1][i]==0?1*3+i:mp[2][i]==0?2*3+i:3*3+i;
    }
    if(mp[1][1]+mp[2][2]+mp[3][3]==-2*t)return mp[1][1]==0?4:mp[2][2]==0?8:12;
    if(mp[1][3]+mp[2][2]+mp[3][1]==-2*t)return mp[1][3]==0?6:mp[2][2]==0?8:10;//判断对方二子连珠
    if(mp[2][2]==0)return 8;//判中心 
    if(mp[1][1]+mp[2][2]+mp[3][3]==t&&(mp[1][1]==0||mp[2][2]==0))return mp[2][2]==0?8:mp[1][1]==0?4:12;
    if(mp[1][3]+mp[2][2]+mp[3][1]==t&&(mp[1][3]==0||mp[2][2]==0))return mp[2][2]==0?8:mp[1][3]==0?6:10;
    for(int i=1;i<=3;++i)
    {
        if(mp[i][1]+mp[i][2]+mp[i][3]==t&&(mp[i][1]==0||mp[i][2]==0))return mp[i][1]==0?i*3+1:mp[i][3]==0?i*3+3:i*3+2;
        if(mp[1][i]+mp[2][i]+mp[3][i]==t&&(mp[1][i]==0||mp[2][i]==0))return mp[1][i]==0?1*3+i:mp[3][i]==0?3*3+i:2*3+i;//判断己方一子连珠 
    }//判己方一子连珠
    return mp[1][1]==0?4:mp[1][3]==0?6:mp[3][1]==0?10:mp[3][3]==0?12:mp[1][2]==0?5:mp[2][1]==0?7:mp[2][3]==0?9:11;
}
int game(int turn)
{
    boom=0;h=turn;memset(mp,0,sizeof(mp));
    while(true)
    {
        X=Y=2;putchess();
        if(h!=AIturn)
        {
            puthint();
            while(((KEY_DOWN('W')||KEY_DOWN('S')||KEY_DOWN('A')||KEY_DOWN('D')||KEY_DOWN(' '))&&player1())||((KEY_DOWN(VK_UP)||KEY_DOWN(VK_DOWN)||KEY_DOWN(VK_LEFT)||KEY_DOWN(VK_RIGHT)||KEY_DOWN('\r'))&&!player1()));
            while(true)
            {
                if((KEY_DOWN('W')&&player1())||(KEY_DOWN(VK_UP)&&!player1()))
                {
                    X=(X+1)%3+1;
                    putchess();puthint();
                    while((KEY_DOWN('W')&&player1())||(KEY_DOWN(VK_UP)&&!player1()));
                }
                if((KEY_DOWN('A')&&player1())||(KEY_DOWN(VK_LEFT)&&!player1()))
                {
                    Y=(Y+1)%3+1;
                    putchess();puthint();
                    while((KEY_DOWN('A')&&player1())||(KEY_DOWN(VK_LEFT)&&!player1()));
                }
                if((KEY_DOWN('S')&&player1())||(KEY_DOWN(VK_DOWN)&&!player1()))
                {
                    X=(X%3)+1;
                    putchess();puthint();
                    while((KEY_DOWN('S')&&player1())||(KEY_DOWN(VK_DOWN)&&!player1()));
                }
                if((KEY_DOWN('D')&&player1())||(KEY_DOWN(VK_RIGHT)&&!player1()))
                {
                    Y=(Y%3)+1;
                    putchess();puthint();
                    while((KEY_DOWN('D')&&player1())||(KEY_DOWN(VK_RIGHT)&&!player1()));
                }
                if((KEY_DOWN(' ')&&player1())||(KEY_DOWN('\r')&&!player1()))
                {
                    while((KEY_DOWN(' ')&&player1())||(KEY_DOWN('\r')&&!player1()));
                    if(!mp[X][Y])break;
                }
            }
        }
        else
        {
            puts("人机计算中……");
            int m=AI(AIturn),y=(m+2)%3+1,x=(m-y)/3;
            if(x==y&&x==2)Sleep(Speed*100);
            else if(x+y==3||x+y==5)
            {
                Sleep(Speed*50);
                X=x;Y=y;putchess();puts("人机计算中……");Sleep(Speed*50);
            }
            else
            {
                Sleep(Speed*33.33);
                X=x;putchess();puts("人机计算中……");Sleep(Speed*33.33);
                Y=y;putchess();puts("人机计算中……");Sleep(Speed*33.33);
            }
        }
        mp[X][Y]=h;X=Y=4;
        if(win())break;
        effect(h);   
        if(win())break;
        h=-h;
    }
    while(true)
    {
        system("cls");
        puts("要再玩一局吗?\n");
        puts("是 —— y\n");
        puts("否 —— n\n");
        while(true)
        {
            if(KEY_DOWN('N'))
            {
                system("cls");
                putss("正在计算最终得分……\n");
                Sleep(Speed*666.66);
                if(win1!=win2)
                {
                    putss("最终的胜利者是:\n");Sleep(Speed*333.33);
                    printf("%s!\n",win1>win2?(AIturn==1?"人机":AIturn==-1?"玩家":"玩家1"):(AIturn==-1?"人机":AIturn==1?"玩家":"玩家2"));system("pause");
                }
                else
                {
                    putss("最终结果是……\n");Sleep(Speed*333.33);
                    puts("平局!");system("pause");
                }
                printf("你们的比分为:%d:%d。\n",win1,win2);system("pause");
                putss("欢迎下次再玩!\n");system("pause");
                return 0;
            }
            if(KEY_DOWN('Y'))return h;
        }
    }
}
int main()
{
    srand(time(NULL));
    while(home());
    return 0;
}