簡單程序設計-五子棋


          《程序設計-五子棋》

                        作者:蠟筆小黑(原創博文,轉載請說明)

前言:很多剛剛接觸編程的人都不知道怎么下手編寫程序,特別是學習了新的知識點,不知道有什么用,那么本文將以簡單的存儲結構及簡單的運算,條件語句,分支語句,循環語句結合,帶來一個雙人對戰版五子棋,這是一個簡單的模型,實現了五子棋最最基本的功能,還有好多地方需要補全,如邊界問題,設計問題,游戲邏輯問題,希望讀者閱讀后能夠注意,通過自己的努力來完善它,還能擴展各種功能,如悔棋,網絡對戰等,有時候寫程序和小生命一樣,慢慢會成長,而我們作為“父母”的看到自己的小寶寶成為有用之才,過程之欣喜特別棒!下面正題! 

需求分析:通過C++語言來實現一個以windows控制台為展示平台的簡單版五子棋程序,其中通過鍵盤輸入來控制游戲中的行為(光標移動、落子、確認)。規則要求某一方在橫豎斜方向連續存在五個或五個以上本人所執棋子獲得為獲勝。

 

流程設計:

游戲流程分析:   

     

 

   當我們要扒一個已存在的程序時(有的是五子棋的程序,可以在互聯網里找到很多),我們可以從他的UI入手,通過我們所觀察到的,所感受到,所使用到的服務,來對軟件進行分析,從而獲得以上流程,但我們一旦需要將需求變為代碼時,我們的設計就要考慮的更多了。

這樣我們就需要一種能力--抽象

 1.首先,我們需要一個棋盤,那么我可以使用C++里的什么來存儲和表示棋盤呢?通過抽象,因為棋盤是個二維圖形,我推薦使用二維數組,假設我們構建一個19行*19列的棋盤。

實現:
       int qiPan[19][19];            //聲明一個19行19列的數組來存儲棋盤 
    
    for(int h=0;h<19;h++)        //對數組進行遍歷,所有元素進行初始化(賦值),默認為0值 
    {
        for(int l=0;l<19;l++)
        {
            qiPan[h][l]=0;        //對當前元素進行初始化(賦值),默認為0值
        }
    }
 
for(int h=0;h<19;h++)        //打印 
{
    for(int l=0;l<19;l++)
    {
        switch(qiPan[h][l])
        {
            case 0:         //如果棋盤存儲的元素為0時,我們打印 · 樣式的字符
                cout<<"·";
                break;
        } 
    }
    cout<<endl;
}
運行以上代碼,我們可以得到一個棋盤。

2.那么擁有棋盤后,我們需要擁有一個光標,來對落子位置進行定點,那么我如何進行表示呢。我們可以在棋盤上找一個點,也就是在數組對應位置找一個元素,更改他的值,我們用8來表示光標,而找到這個元素我們需要知道其橫縱坐標值,我們用兩個int變量表示。
    int X=9;                    //2.聲明並初始化光標的橫縱坐標 
    int Y=9;                    
    
    qiPan[9][9]=8;                //更改棋盤中光標所在元素的值為8

打印時,我們只要在switch 語句中添加一個case 選項 8即可:
        
case 8:           //如果棋盤存儲的元素為0時,我們打印 · 樣式的字符
    cout<<""; 
    break;
獲得光標后我們如何移動他呢?那么我們可以通過接受鍵盤輸入的字符來控制光標的移動,本例中使用 W上,S下,A左,D右 來移動光標。
        char xx=getch();            //控制台從鍵盤獲得一個字符的函數(方法)
        switch(xx)                    //控制
        {
            case 'w':                //
                Y=Y-1;                //使光標縱坐標-1 
                qiPan[Y][X]=8;        //將光標寫入棋盤 
                qiPan[Y+1][X]=0;        //使原本位置的值還原 
                break;
            case 's':                //
                Y=Y+1;
                qiPan[Y][X]=8;
                qiPan[Y-1][X]=0;    
                break;    
            
            case 'a':                //
                X=X-1;
                qiPan[Y][X]=8;
                qiPan[Y][X+1]=0;    
                break;
            case 'd':                //
                X=X+1;
                qiPan[Y][X]=8;
                qiPan[Y][X-1]=0;    
                break;                                
        }

 

3.這時,我們可以控制光標的移動了,接下來要實現落子操作,棋子又怎么表示呢?

我們可以使用兩個int類型的值來表示:白子- 1,黑子- 2,那么我們只要在棋盤中更改光標所在位置元素的值為12就可以了,那么我們這么做可行嗎?

我們回顧一下光標移動的代碼,我們會發現,光標的移動會影響元素的變化,那么我們如果在棋盤中進行落子后,我們光標再次移動有可能會改變已記錄的落子信息,為了使光標與棋子不沖突,我們使用兩個圖層,表示兩個相同的棋盤。

 

 

   那么我就需要再聲明一個棋盤,方法和1中一樣:

 

    int qiPanTwo[19][19];        //聲明一個19行19列的數組來存儲棋盤 
    
    for(int h=0;h<19;h++)        //對數組進行遍歷,所有元素進行初始化(賦值),默認為0值 
    {
        for(int l=0;l<19;l++)
        {
            qiPanTwo[h][l]=0;    //對當前元素進行初始化(賦值),默認為0值
        }
    }

好,棋盤2已經建立好了,那么我們如何落子?我們一定要選擇執棋方后,在光標位置通過接收鍵盤輸入的j落子,那么我們只需要在2.中switch語句中添加一個分支 case ’j’:即可,並且我們需要使用一個變量來表示玩家,我們可以在程序一開始定義:

int player=1;//設定玩家並進行初始化賦值
            
case 'j':                    //落子 
    if(player==1)            //如果當前玩家為白色方時 
    {
        qiPanTwo[Y][X]=1;    //通過棋盤1中的光標位置更改棋盤2
//中對應元素的值為1,也就是白棋落子
        player=2;            //白棋落子后更換玩家                    
    }
    else if(player==2) 
    {
        qiPanTwo[Y][X]=2;
        player=1;                    
    }
break;    
落子成功,接下來我們可以把它展示出來,由於此時我們要對兩個棋盤進行統一的打印,那么我們使用swicth就不能進行統一的分支選擇了,此時我們需要將1.中的打印內容改為:
        if(qiPan[h][l]==8)   //由於光標所在圖層應該在棋子圖層之上,所以優先考慮。
        {
            cout<<"";
        }
        else if(qiPanTwo[h][l]==0)
        {
            cout<<"·";
        }
        else if(qiPanTwo[h][l]==1)
        {
            cout<<"";
        }
        else if(qiPanTwo[h][l]==2)
        {
            cout<<"";
        }        
4.游戲規則,我們落子之后要進行一個判斷,如何判斷是否勝利呢?    
      此時,我們就要使用游戲規則來進行算法的分析,當落子位橫、縱、斜5格內存在相互連接的五個同類棋子時,我們可認為執該棋者獲勝,所以我們需要在各個方向進行判斷。
        int shu=1,heng=1,pie=1,na=1;//橫豎撇捺計數器,累計到5則表示某方向出現五個相同的旗子
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y+i][X]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              shu++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y-i][X]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              shu++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              heng++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              heng++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //左下 
        {
            if(qiPanTwo[Y+i][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              pie++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //右上 
        {
            if(qiPanTwo[Y-i][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              pie++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //右下 
        {
            if(qiPanTwo[Y+i][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              na++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //左上 
        {
            if(qiPanTwo[Y-i][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              na++;
            else
              break;      
        }
        if(shu==5||heng==5||pie==5||na==5)
        {
            if(qiPanTwo[Y][X]==1)
                {
                    cout<<"白子獲勝!";
                    system("pause");
                    break;
                }
            else 
                {
                    cout<<"黑子獲勝!";
                    system("pause");
                    break;
                }
        }
        shu=1,heng=1,pie=1,na=1;    

好 當完成這一步時,我們的程序基本就搞定了,剩下就是按照一開始的流程進行拼接了,其中我們在打印屏幕之前,要對上一次打印的結果進行擦除,使用函數
system(“cls”);//擦除控制台中所有已顯示的字符
就可以完成了。

 

 完整代碼(可運行):

 

#include<iostream>
#include<string> 
#include<windows.h> 
#include<conio.h>
using namespace std;
int main()
{
    int player=1;                //定義一個玩家,當1時為白方,2時為黑方 
    
    //................................棋盤1..............................................
        
    int qiPan[19][19];            //1.聲明一個19行19列的數組來存儲棋盤 1 
    
    for(int h=0;h<19;h++)        //對數組進行遍歷,所有元素進行初始化(賦值),默認為0值 
    {
        for(int l=0;l<19;l++)
        {
            qiPan[h][l]=0;        //對當前元素進行初始化(賦值),默認為0值
        }
    }
    
    //...............................棋盤2................................................
    
    int qiPanTwo[19][19];        //聲明一個19行19列的數組來存儲棋盤  2
    
    for(int h=0;h<19;h++)        //對數組進行遍歷,所有元素進行初始化(賦值),默認為0值 
    {
        for(int l=0;l<19;l++)
        {
            qiPanTwo[h][l]=0;    //對當前元素進行初始化(賦值),默認為0值
        }
    }
    
    //...............................光標聲明.............................................
            
    int X=9;                    //2.聲明並初始化光標的橫縱坐標 
    int Y=9;                    
    qiPan[9][9]=8;
    
    //..............................顯示...................................................
    
    for(int h=0;h<19;h++)        
        {
            for(int l=0;l<19;l++)
            {

                if(qiPan[h][l]==8)
                {
                    cout<<"";
                }
                else if(qiPanTwo[h][l]==0)
                {
                    cout<<"·";
                }
                else if(qiPanTwo[h][l]==1)
                {
                    cout<<"";
                }
                else if(qiPanTwo[h][l]==2)
                {
                    cout<<"";
                }    
            }
            cout<<endl;
        }

    //..............................輸入控制...............................................
    
    while(true)
    {
        char xx=getch();            //控制台從鍵盤獲得一個字符 
        switch(xx)                    //控制
        {
            case 'w':                //
                Y=Y-1;                //使光標縱坐標-1 
                qiPan[Y][X]=8;        //講光標寫入棋盤 
                qiPan[Y+1][X]=0;        //使原本位置的值還原 
                break;
                
            case 's':                //
                Y=Y+1;
                qiPan[Y][X]=8;
                qiPan[Y-1][X]=0;    
                break;    
                            
            case 'a':                //
                X=X-1;
                qiPan[Y][X]=8;
                qiPan[Y][X+1]=0;    
                break;
                
            case 'd':                //
                X=X+1;
                qiPan[Y][X]=8;
                qiPan[Y][X-1]=0;    
                break;    
                
            case 'j':                    //落子 
                if(player==1)            //如果當前玩家為白色方時 
                {
                    qiPanTwo[Y][X]=1;    //通過棋盤1中的光標位置更改棋盤2中對應元素的值為1,也就是白棋落子
                    player=2;            //白棋落子后更換玩家                    
                }
                else if(player==2) 
                {
                    qiPanTwo[Y][X]=2;
                    player=1;                    
                }
                break;                                
        }
        
    //................................清屏操作................................................    
    
        system("cls");                
        
    //...............................打印.....................................................
                
        for(int h=0;h<19;h++)        
        {
            for(int l=0;l<19;l++)
            {

                if(qiPan[h][l]==8)
                {
                    cout<<"";
                }
                else if(qiPanTwo[h][l]==0)
                {
                    cout<<"·";
                }
                else if(qiPanTwo[h][l]==1)
                {
                    cout<<"";
                }
                else if(qiPanTwo[h][l]==2)
                {
                    cout<<"";
                }    
            }
            cout<<endl;
        }
    
    
    //.........................游戲規則..............................................
    
        int shu=1,heng=1,pie=1,na=1;//橫豎撇捺 
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y+i][X]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              shu++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y-i][X]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              shu++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              heng++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //
        {
            if(qiPanTwo[Y][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              heng++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //左下 
        {
            if(qiPanTwo[Y+i][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              pie++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //右上 
        {
            if(qiPanTwo[Y-i][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              pie++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //右下 
        {
            if(qiPanTwo[Y+i][X+i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              na++;
            else
              break;      
        }
        for(int i=1;i<=4;i++) //左上 
        {
            if(qiPanTwo[Y-i][X-i]==qiPanTwo[Y][X]&&qiPanTwo[Y][X]!=0)
              na++;
            else
              break;      
        }
        if(shu==5||heng==5||pie==5||na==5)
        {
            if(qiPanTwo[Y][X]==1)
                {
                    cout<<"白子獲勝!";
                    system("pause");
                    break;
                }
            else 
                {
                    cout<<"黑子獲勝!";
                    system("pause");
                    break;
                }
        }
    } 
    
    return 0; 
}
     

      2017-02-01    20:13:59   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM