zoukankan      html  css  js  c++  java
  • 井字棋算法

    井字棋算法

    绪言

    说到井字棋,也许都想起了自己小时候的时光吧。

    井字棋其实很简单,只要你去认真分析它,你就能明白什么叫做“先手不输,后手不赢”。

    算法

    V1

    随机算法。

    扫描全局找出所有空位。

    随机一个空位,下子。

    V2

    先看看自己有没有已经构成两个一空的

      O

        

    X X O 

    (只是打个比方)

    标红的地方都是

    有的话就下子

    如果没有再看看敌人是否已经构成了两子一空。

      如果敌人构成了则要将其破坏(下子)

      如果敌人也没有,就走V1

    V3

    首先搭载V2

    在判断完没有两子一空之后,就可以开始动笔了。

    大量实验证明,先手下角赢的概率最大

    (伪)

    这是为什么呢?

    因为这是一个套路:

    如果你的棋盘是这样的

    先下角

     对手走4或2

    那我就继续走一个邻角

    这时候2P就必须走4否则2P就输了

    这时候,我只需要继续走另一个邻角就好

    这时,789和159都构成了两子一空,无论对方走哪里,只要补齐另一个空就行了


    要是先手走角,后手也走角呢?

    那我就继续走角

    这是2P只能走4

    接着我继续走剩下的一个角9

    2P又陷入了僵局


    那要是先手走角,后手走中间呢?

    那先手就走对角9(走邻角7或3会平局,自己试试咯)

    此时,后手可以走角37或者边2468

    如果后手走角3

    那先手继续走角即可,如图,147,789都构成了两空一子

    如果后手走边4 那先手根据V2只能走6

    后手根据V2只能走3

    先手根据V2只能走7

    后手根据V2只能走8

    结果就只有平局的份了……

    所以,先手走边时,后手唯一造成平局的机会就是

    先走中心,再走边

    Code

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<set>
      7 #include<queue>
      8 #include<vector>
      9 #include<windows.h>
     10 #include<sstream>
     11 #include<ctime>
     12 #include<conio.h>
     13 #define IL inline
     14 #define re register
     15 #define LL long long
     16 using namespace std;
     17 /*
     18 sssss sssss sssss
     19 ss7ss ss8ss ss9ss
     20 sssss sssss sssss
     21 
     22 sssss sssss sssss
     23 ss4ss ss5ss ss6ss
     24 sssss sssss sssss
     25 
     26 sssss sssss sssss
     27 ss1ss ss2ss ss3ss
     28 sssss sssss sssss
     29 s==space
     30 */
     31 
     32 int mode=0;//0 2p 1 easy 2 mid 3 hard
     33 int diff;
     34 int map[3][3];//0 空 1 1P 2 2P||AI 
     35 int stats[3];//0 ping 1 1P 2 2P  
     36 void set_stats(){
     37     stringstream ss;
     38     ss<<"title total:"<<stats[0]+stats[1]+stats[2]<<";stats:1P:P:2P="<<stats[1]<<":"<<stats[0]<<":"<<stats[2]<<"="<<stats[1]*1.0/stats[0]<<":1:"<<stats[2]*1.0/stats[0]<<":"<<stats[1]*1.0/stats[2];
     39     system(ss.str().c_str());
     40     if(stats[0]+stats[1]+stats[2]==10000) system("pause");
     41 }
     42 struct xy{
     43     int x;
     44     int y;
     45     int num(){
     46         return (2-x)*3+y+1;//7-3x+y=num() 3x-y=7-num() 3x=7-num()+y
     47     }
     48     bool operator!=(xy z){
     49         if(x==z.x&&y==z.y) return 0;
     50         return 1;
     51     }
     52     bool operator==(xy z){
     53         if(x==z.x&&y==z.y) return 1;
     54         return 0;
     55     }
     56     int value(){
     57         return map[x][y];
     58     }
     59     xy eof(){
     60         return {-1,-1};
     61     }
     62     xy up(){
     63         xy ans=*this;
     64         if(x<2&&x>=0) ans.x++;
     65         else ans={-1,-1};
     66         return ans;
     67     }
     68     xy down(){
     69         xy ans=*this;
     70         if(x>0&&x<3) ans.x--;
     71         else ans=eof();
     72         return ans;
     73     }
     74     xy left(){
     75         xy ans=*this;
     76         if(y>0&&y<3) ans.y--;
     77         else ans=eof();
     78         return ans;
     79     }
     80     xy right(){
     81         xy ans=*this;
     82         if(y<2&&y>=0) ans.y++;
     83         else ans=eof();
     84         return ans;
     85     }
     86     xy edge(int w){
     87         if(*this==eof()) return eof();
     88         xy ans=*this;
     89         if(w<3) ans=ans.up();
     90         if(w>=2&&w<=4) ans=ans.right();
     91         if(w>=4&&w<=6) ans=ans.down();
     92         if((w>=6&&w<8)||w==0) ans=ans.left(); 
     93         return ans;
     94     }
     95     int point(){
     96         if(num()==5)return 0;
     97         if(num()%2) return 2;
     98         return 1;
     99     }
    100 };
    101 xy turn(int num){
    102     xy ans;
    103     ans.y=(num-1)%3;
    104     ans.x=(7-num+ans.y)/3;
    105     return ans;
    106 }
    107 xy eof(){
    108     return {-1,-1};
    109 }
    110 unsigned short lb,lf;
    111 const int A=10,B=11,C=12,D=13,E=14,F=15;
    112 void SetColor(unsigned short BackGroundColor,unsigned short ForeColor)
    113 {
    114     HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);  
    115     SetConsoleTextAttribute(hCon,(ForeColor%16)|(BackGroundColor%16*16));  
    116 }
    117 int lx,ly;
    118 void getxy()
    119 {
    120     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    121     CONSOLE_SCREEN_BUFFER_INFO csbi;
    122     GetConsoleScreenBufferInfo(hConsole, &csbi);
    123     lx=csbi.dwCursorPosition.X,ly=csbi.dwCursorPosition.Y;
    124 }
    125 void gotoxy(int x, int y)
    126 {
    127     COORD pos;
    128     pos.X = x - 1;
    129     pos.Y = y - 1;
    130     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
    131 }
    132 IL void backxy()
    133 {
    134     COORD pos;
    135     pos.X = lx;
    136     pos.Y = ly;
    137     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
    138 }
    139 int main(); 
    140 void init(){
    141     for(int i=1;i<10;i++) map[turn(i).x][turn(i).y]=0;
    142     system("cls");
    143     cout<<"请输入模式:
    【0】双人对战
    【1】人机easy
    【2】人机mid
    【3】人机hard
    【4】神仙打架
    【5】学习神仙
    ";
    144     do{
    145         mode=getch()-'0';
    146     }while(mode<0||mode>5);
    147     diff=max(min(mode,3),1);
    148     cout<<"游戏中 按下r键可以重新选择
    ";
    149     system("pause");    
    150 }
    151 const string cls[9]={"sssss sssss sssss
    ","ss7ss ss8ss ss9ss
    ","sssss sssss sssss
    
    ","sssss sssss sssss
    ","ss4ss ss5ss ss6ss
    ","sssss sssss sssss
    
    ","sssss sssss sssss
    ","ss1ss ss2ss ss3ss
    ","sssss sssss sssss
    "};
    152 void show(){
    153     system("cls");
    154     for(int i=0;i<9;i++) cout<<cls[i];
    155     memset(map,sizeof(map),0);
    156 }
    157 int fp;//先手 
    158 vector<int>step;
    159 xy algo(int p,int m=diff){//1 随机 2 找2排2 3 特殊 
    160     int dr=p==1?2:1;
    161     vector<xy>line;
    162     if(m>1){
    163         //找出自己二连 
    164         for(int n=1;n<10;n++)
    165         for(int k=0;k<8;k++){
    166             if(turn(n).value()==0){
    167                 if(turn(n).edge(k)!=eof()&&turn(n).edge(k).value()==p&&turn(n).edge(k).edge(k)!=eof()&&turn(n).edge(k).edge(k).value()==p) return turn(n); 
    168                 if(turn(n).edge(k)!=eof()&&turn(n).edge(k).value()==p&&turn(n).edge((k+4)%8)!=eof()&&turn(n).edge((k+4)%8).value()==p) return turn(n);
    169             }
    170         }
    171         //排除敌人二连 
    172         for(int n=1;n<10;n++)
    173         for(int k=0;k<8;k++){
    174             if(turn(n).value()==0){
    175                 if(turn(n).edge(k)!=eof()&&turn(n).edge(k).value()==dr&&turn(n).edge(k).edge(k)!=eof()&&turn(n).edge(k).edge(k).value()==dr) return turn(n); 
    176                 if(turn(n).edge(k)!=eof()&&turn(n).edge(k).value()==dr&&turn(n).edge((k+4)%8)!=eof()&&turn(n).edge((k+4)%8).value()==dr) return turn(n);
    177             }
    178         }
    179         if(m==3||(m==2&&rand()%10<4)){
    180             /*
    181             第一步走角        无明显差异
    182             第二步走角        无明显差异 
    183             优先走角        优 1.3427:1:0.8555 1.5694
    184             除前两步走角    优 1.3582:1:0.8667 1.5670
    185             优先走中心        优 2.0000:8:1.0000 2.0000 
    186             中心->角        优 0.4090:1:0.1468 2.7849
    187             角->中心        优 1.4097:1:0.8786 1.6044 
    188             */
    189             if(step.size()+1==2)//如果是第二步 
    190             {
    191                 if(turn(step[0]).point()==2) return turn(5);//先手走角就走中间 
    192             }
    193             if(step.size()+1==3)//如果是第三步 
    194             {
    195                 if(turn(step[0]).point()==2)//并且第一步走的是角 
    196                 {
    197                     if(turn(step[1]).point()==0)//如果后手走中心
    198                     {
    199                         for(int k=0;k<8;k+=2) if(turn(step[0]).edge(k).edge(k)!=eof()) return turn(step[0]).edge(k).edge(k);
    200                     } 
    201                 }    
    202             }
    203             if(step.size()+1==4)//如果是第四步 
    204             {
    205                 if(turn(step[0]).point()==2&&turn(step[1]).point()==0&&turn(step[2]).point()==2&&step[0]+step[2]==10)//1角2中3对角则4边 
    206                 {
    207                     if(!turn(2).value()) line.push_back(turn(2));
    208                     if(!turn(4).value()) line.push_back(turn(4));
    209                     if(!turn(6).value()) line.push_back(turn(6));
    210                     if(!turn(8).value()) line.push_back(turn(8));
    211                     random_shuffle(line.begin(),line.end());
    212                     if(!line.empty()) return line.front(); 
    213                 } 
    214             }
    215             
    216             {
    217                 //
    218                 if(!turn(1).value()) line.push_back(turn(1));
    219                 if(!turn(3).value()) line.push_back(turn(3));
    220                 if(!turn(7).value()) line.push_back(turn(7));
    221                 if(!turn(9).value()) line.push_back(turn(9));
    222                 random_shuffle(line.begin(),line.end());
    223                 if(!line.empty()) return line.front(); 
    224             }
    225             {
    226                 //中心
    227                 if(!turn(5).value()) return turn(5); 
    228             }
    229             {
    230                 if(!turn(2).value()) line.push_back(turn(2));
    231                 if(!turn(4).value()) line.push_back(turn(4));
    232                 if(!turn(6).value()) line.push_back(turn(6));
    233                 if(!turn(8).value()) line.push_back(turn(8));
    234                 random_shuffle(line.begin(),line.end());
    235                 if(!line.empty()) return line.front(); 
    236             } 
    237             
    238             //找到最优
    239         }
    240     }
    241     //随机
    242     for(int x=0;x<3;x++)
    243     for(int y=0;y<3;y++)
    244         if(map[x][y]==0) line.push_back({x,y});
    245     random_shuffle(line.begin(),line.end());
    246     return line.front();
    247 }
    248 
    249 void edit(xy p,int c){
    250 //    return;////////////////////////////////////////////////////////////////////////////
    251     getxy();
    252     if(c==1) SetColor(7,A);
    253     if(c==2) SetColor(A,7);
    254     if(c==3) SetColor(F,C);
    255     for(int i=p.x*3;i<p.x*3+3;i++)
    256     for(int j=p.y*6;j<p.y*6+5;j++)
    257     {
    258         gotoxy(j+1,i+1+p.x);cout<<cls[i][j];
    259     }
    260     backxy();
    261     SetColor(0,7);
    262 }
    263 
    264 void win(int n,int k,int p){
    265     step.clear();
    266     gotoxy(1,13);
    267     if(p==-1){
    268         cout<<"平局!";
    269         stats[0]++;
    270     } 
    271     if(p==1){
    272         edit(turn(n),3);
    273         edit(turn(n).edge(k),3);
    274         edit(turn(n).edge(k).edge(k),3);
    275         cout<<"1P wins!";
    276         stats[1]++;
    277     }
    278     if(p==2){
    279         edit(turn(n),3);
    280         edit(turn(n).edge(k),3);
    281         edit(turn(n).edge(k).edge(k),3);
    282         cout<<"2P wins!";
    283         stats[2]++;
    284     }
    285     set_stats();
    286     if(mode!=4) system("pause"); 
    287     system("cls");
    288     for(int i=1;i<10;i++) map[turn(i).x][turn(i).y]=0;
    289     show();
    290 }
    291 
    292 int check(){
    293     for(int n=1;n<10;n++)
    294     for(int k=0;k<8;k++)
    295     if(turn(n).value())
    296     if(turn(n).edge(k)!=eof()&&turn(n).edge(k).edge(k)!=eof())
    297     if(turn(n).value()==turn(n).edge(k).value()&&turn(n).edge(k).value()==turn(n).edge(k).edge(k).value())
    298     {
    299         win(n,k,turn(n).value());
    300         return turn(n).value();
    301     }
    302     bool flag=1;
    303     for(int n=1;n<10;n++){
    304         if(turn(n).value()==0){
    305             flag=0;
    306             break; 
    307         } 
    308     }
    309     if(flag){
    310         win(-1,-1,-1);
    311         return 3;
    312     }
    313     return 0;
    314 }
    315 
    316 void first(){
    317     if(mode==4||mode==5){
    318         gotoxy(1,13);
    319         cout<<"AI:";
    320         xy n;
    321         if(mode!=4) Sleep((5-mode)*100);
    322         if(mode==5) Sleep(1000);
    323         n=algo(1);
    324         step.push_back(n.num());
    325         edit(n,1);
    326         map[n.x][n.y]=1;
    327     }
    328     else{
    329         int n;
    330         do{
    331             gotoxy(1,13);
    332             cout<<"1P:";
    333             n=getch();
    334             if(n=='r'){
    335                 main();
    336                 exit(0);
    337             }
    338             if(n=='a'){
    339                 n=algo(1,3).num()+'0';
    340             }
    341             if(n=='d'){
    342                 n=algo(1,2).num()+'0';
    343             }
    344             n-='0';
    345         }while(n<1||n>9||map[turn(n).x][turn(n).y]!=0);
    346         step.push_back(n);
    347         edit(turn(n),1);
    348         map[turn(n).x][turn(n).y]=1;
    349     }
    350     
    351 }
    352 void second(){
    353     if(mode!=0){
    354         gotoxy(1,13);
    355         cout<<"AI:";
    356         xy n;
    357         if(mode!=4) Sleep((5-mode)*100);
    358         if(mode==5) Sleep(1000);
    359         n=algo(2);////////////////////////////可调整AI2的难度 
    360         step.push_back(n.num());
    361         edit(n,2);
    362         map[n.x][n.y]=2;
    363     }
    364     else{
    365         int n;
    366         gotoxy(1,13);
    367         cout<<"2P:";
    368             do{
    369                 n=getch();
    370                 if(n=='r'){
    371                     main();
    372                     exit(0);
    373                 }
    374                 if(n=='a'){
    375                     n=algo(1,3).num()+'0';
    376                 }
    377                 if(n=='d'){
    378                     n=algo(1,2).num()+'0';
    379                 }
    380                 n-='0';
    381         }while(n<1||n>9||map[turn(n).x][turn(n).y]!=0);
    382         step.push_back(n);
    383         edit(turn(n),2);
    384         map[turn(n).x][turn(n).y]=2;
    385     }
    386         
    387     
    388 }
    389 
    390 void about()
    391 {
    392     system("cls"); 
    393     cout<<"井字棋 最终版 code by SOAF
    没有使用搜索算法而先把所有情况列了出来
    这是一个先手不会输,后手不会赢的游戏。
    先手所能做的就是尝试赢,后手所能做的就是尝试不输。
    新手建议尝试easy上手,大佬也别急着玩hard哦!
    祝您游戏愉快!
    "; 
    394     system("pause");
    395     system("cls");
    396 }
    397 
    398 int main()
    399 {
    400     srand(clock());
    401     about();
    402     init();
    403     show();
    404     set_stats();
    405     while(true){
    406         fp=1;
    407         while(true){
    408             first();
    409             if(check()==1){
    410                 break;
    411             }
    412             second();
    413             if(check()==2){
    414                 break;
    415             }
    416         }
    417         if(kbhit()){
    418             if(getch()=='r') main(),exit(0);
    419         }
    420         fp=2;
    421         while(true){
    422             second();
    423             if(check()){
    424                 break;
    425             }
    426             first();
    427             if(check()){
    428                 break;
    429             }
    430         }
    431     }
    432     return 0;
    433 }

    代码较长但功能齐全。不需要的请适当删减!

    End

    当你如此认真的分析完井字棋之后,你就会发现,这真是一个无聊的游戏啊……

  • 相关阅读:
    idea中svn代码冲突
    数据库表的连接(Left join , Right Join, Inner Join)用法详解
    @Param注解的用法解析
    spring @Transactional注解参数详解
    数据库的DDL、DML和DCL的区别与理解
    Mybatis:resultMap的使用总结
    Maps.newHashMap 和 new HashMap的区别
    php 个推的例子
    fidder 调接口 的 小常识
    php Memcached
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/12496401.html
Copyright © 2011-2022 走看看