C語言——實現三子棋

@toc 算法

三子棋設計

前期準備:

工程文件思路:
主函數 放到ticktacktoe(三子棋)中
三子棋具體的實現 放到game.c / game.h數組

image-20210731153017666

 

主函數遊戲思路:
三子棋遊戲思路:
一、至少玩一次,能夠玩屢次,do…while循環
二、進入遊戲後先打印菜單提示
三、提示用戶輸入,根據輸入值來肯定後續的遊戲進程(1表明玩遊戲,0表明退出,其餘須要從新選擇
 
三子棋玩遊戲的思路:markdown

首先咱們要知道三子棋的一些信息:
一、三子棋形狀
image-20210731154500176框架

image-20210731153314301

二、遊戲規則:同一形狀連成直線(三格)即獲勝
因此獲勝的條件:一、橫排同形狀 二、豎排同形狀 三、對角線同形狀
 
三子棋遊戲實現具體思路:
1.咱們要記錄下棋的結果,就須要對應的二維數組來存儲
2.建立的二維數組要進行初始化,賦值成空格" "
3.打印棋盤,看一下展現的效果ide

image-20210731153346722

遊戲狀態判斷 四種狀態 玩家贏,電腦贏,平局,繼續
4.玩家下棋
5.判斷玩家是否遊戲勝利 判斷遊戲狀態是否繼續
6.電腦下棋(隨機落子的方式)
7.判斷電腦是否遊戲勝利 判斷遊戲狀態是否繼續函數


遊戲初始設計

設計菜單

void menu()
{
    printf("***************************************\n");
    printf("*********1   play game ****************\n");
    printf("*********0   exit game ****************\n");
    printf("***************************************\n");

}

主函數總體設計

int main()
{   
    menu();
    int input=0;
    do
    {
        printf("請選擇:\n");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出遊戲\n");
            break;
        default:
            printf("選擇錯誤");
            break;
        }
    } while (input);
    return 0;
}

遊戲函數的設計

注:測試

#define ROW 3 //行
#define COL 3 //列

1.大致結構咱們已經完成,接下來咱們設計該遊戲的重中之重,遊戲函數game()
關於該遊戲咱們首先要對棋盤進行初始化將其初始化爲空格,這裏用兩個循環來實現優化

void  Init_board(char board[ROW][COL], int row, int col)
{
    int i = 0, j = 0;
    for (i = 0;i < ROW;i++)
    {
        for(j=0;j<COL;j++)
        {
            board[i][j] = ' ';
        }

    }

}

2.初始化棋盤後,咱們進行打印棋盤設計

void print_board(char board[ROW][COL], int row, int col)
 {
     int i = 0;
     for (i = 0;i < row;i++)
     {
         printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
         if(i<row-1)
         printf("---|---|---\n");
     }

 }

咱們先看這種,這種寫法確實符合咱們的要求,但咱們仔細想一想,若是咱們把開始的ROE ,COL定義成其餘的數字,那麼這種寫法就不能實現,例如5x5,10x10的棋盤,由於上述代碼的printf所寫的,已經將他的形式鎖死了,因此不能實現其餘棋盤,因此這種寫法難以推廣,接下來咱們進行優化3d

void print_board(char board[ROW][COL], int row, int col)
 {
     int i = 0,j=0;
     for (i = 0;i < row;i++)
     {

         for (j = 0;j < col;j++)
         {
             printf(" %c ", board[i][j]);
             if (j < col - 1)
                 printf("|");
         }
         printf("\n");
         if (i < row - 1)
         {
             for (j = 0;j < col;j++)
             {
                 printf("---");
                 if (j < col - 1)
                     printf("|");

             }
             printf("\n");
         }
     }
 }

寫成這樣咱們就能夠打印各類棋盤了

3.當棋盤完成初始化及打印完棋盤後,咱們就能夠進行下棋了
進行下棋時,無疑覺得玩家一步,電腦一步,首先咱們來完成玩家下棋的代碼

void playermove(char board[ROW][COL], int row, int col)
 {
     int x = 0, y = 0;
     printf("玩家走\n");
     while (1)
     {
         printf("請輸入一個座標");
         scanf("%d%d", &x, &y);
         if (x >= 1 && x <= row && y >= 1 && y <=col)
         {
             if (board[x - 1][y - 1] != ' ')
             {
                 printf("該座標已被佔用,請從新輸入");
             }
             else
             {
                 board[x - 1][y - 1] = '*';
                 break;
             }
         }
         else
         {
             printf("座標錯誤,請從新輸入");
         }
     }
 }

這裏咱們要注意,咱們所寫的程序是面向用戶的,他們不會像咱們同樣知道二維i數組的第一個座標是(0,0),他們會寫成(1,1),
因此咱們這裏寫成 board[x - 1][y - 1]

其次是電腦下棋

void computermove(char board[ROW][COL], int row, int col)
 {
     printf("電腦走\n");

     while (1)
     {
         int x = rand() % row;
         int y = rand() % col;
         if (board[x][y] == ' ')
         {
             board[x][y] = '#';
             break;
         }
     }
 }

這裏咱們的電腦是比較「笨」的,他所下棋的位置是比較隨機的,同時咱們還要注意這裏rand(隨機數) 函數的使用,由於電腦下棋座標是(0,0)到(2,2)(這裏是以二維數組來講),因此rand()%3 便可,這樣隨機數的範圍就是0-2了,同時使用了rand就須要srand配合使用,
寫到這裏咱們將主函數增長srand((unsigned)time(NULL)); 語句
(這裏簡單說下rand 函數隨機數範圍肯定,ranf ()%num,生成隨機數的範圍就是0到num-1)
 

遊戲檢測輸贏的實現

遊戲已經大體完成 ,接下來實現判斷遊戲輸贏,這裏我用如下進行判斷
井號 表明電腦贏
星號表明人贏
c 表明繼續
f 表明平局

void game()
{

    char ret;
    char board[ROW][COL];
    //初始化棋盤
    Init_board(board, ROW, COL );
    //打印棋盤
    print_board(board, ROW ,COL);
    while (1)
    {
        playermove(board, ROW, COL);//玩家下棋
        ret =checkwin(board, ROW, COL);
        if (ret != 'c')
        {
            break;
        }
        print_board(board, ROW, COL);

        computermove(board, ROW, COL);//電腦下棋
        ret = checkwin(board, ROW, COL);
        if (ret != 'c')
        {
            break;
        }
        print_board(board, ROW, COL);
    }
    if (ret == '#')
        printf("電腦贏了\n");
    if (ret == '*')
        printf("你贏了\n");
    if (ret == 'f')
        printf("雙方平局\n");
    print_board(board, ROW, COL);
}

上述大致判斷框架完成,接下來就是checkwin() 函數的實現
這個遊戲無疑就是三行,三列,或對角線連成一條線則取得勝利,且每個格子裏不是咱們所初始化的空格

char checkwin(char board[ROW][COL], int row, int col)
 {
     int i = 0;
     //三行
     for (i = 0;i < row;i++)
     {
         if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
         {
             return board[i][0];
         }
     }
     //三列 
     for (i = 0;i < col;i++)
     {
         if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
         {
             return board[0][i];
         }
     }
     //對角線
     if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
     {
         return board[1][1];
     }
     if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
     {
         return board[1][1];
     }
     //平局
     if (full(board,row,col) == 1)
     {
         return 'f';
     }
     //遊戲繼續,沒有贏或平局
     return 'c';
 }

這裏咱們又寫了一個新的函數full()來判斷棋盤是否填滿

int full(char board[ROW][COL], int row, int col)
 {
     int j = 0, i = 0;
     for (i = 0;i < row;i++)
     {
         for (j = 0;j < col;j++)
         {
             if (board[i][j] == ' ')
                 return 0;
         }
     }
     return 1;

 }

到這遊戲實現,具體思路就這樣的

 

最終代碼部分

game.h

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 3
#define COL 3
#include<stdio.h>
#include <stdlib.h>
#include <time.h>

//初始化棋盤
void Init_board(char board[ROW][COL], int row, int col);
//打印棋盤
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//電腦下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//檢測輸贏
char IsWin(char board[ROW][COL], int row, int col);

//告訴咱們四種遊戲的狀態
//玩家贏 - '*'
//電腦贏 - '#'
//平局   - 'Q'
//繼續   - 'C'

game.c

//game.c遊戲實現部分
#include "game.h"
//棋盤初始化爲空格的函數
void InitBoard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
        for (i = 0; i < row; i++)
        {
            for (j = 0; j < col; j++)
            {
                board[i][j] = ' ';
            }
        }
}
//打印棋盤的函數
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
//  int i = 0;
//  for (i = 0; i < row; i++)
//  {
//      //打印一行的數據
//      printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);
//      //打印分割行
//      if (i < row - 1)
//          printf("---|---|---\n");
//  }
//}
//這個打印函數寫死了棋盤邊框,只有3*3的棋盤邊框,所以不是很合適

//改進後的棋盤打印函數
void DisplayBoard(char board[ROW][COL], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++)
        {
            //打印一行的數據
            printf(" %c ", board[i][j]);
            if (j < col - 1)
                printf("|");
        }
        printf("\n");
        //打印分割行
        if (i < row - 1)
        {
            for (j = 0; j < col; j++)
            {
                printf("---");
                if (j < col - 1)
                    printf("|");
            }
            printf("\n");
        }
    }
}
//保存下棋步驟的函數
//玩家走步記錄函數
//這裏要站在玩家角度設計代碼,3*3列棋盤玩家通常會認爲是3行(1,2,3行)*3列(1,2,3列)
//實際上在計算機思惟上應該是3行(0,1,2行)*3列(0,1,2列)
void PlayerMove(char board[ROW][COL], int row, int col)
{
    int x = 0;
    int y = 0;
    printf("玩家先走:(行+空格+列)\n");
    while (1)
    {
        printf("請輸入要下的座標:>");
        scanf("%d%d", &x, &y);
        //判斷x,y座標的合法性
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("該座標被佔用\n");
            }
        }
        else
        {
            printf("座標非法,請從新輸入!\n");
        }
    }
}
//電腦走步記錄函數
void ComputerMove(char board[ROW][COL], int row, int col)
{
    int x = 0;
    int y = 0;
    printf("電腦走:>\n");
    while (1)
    {
        x = rand() % row;//模3只能產生0,1,2
        y = rand() % col;//模3只能產生0,1,2
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
}

//棋盤是否下滿的判斷函數
//返回1表示棋盤滿了
//返回0,表示棋盤沒滿
int IsFull(char board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (board[i][j] == ' ')//當二維數組中存在空格時,說明棋盤沒滿
            {
                return 0;//沒滿
            }
        }
    }
    return 1;//滿了
}

//檢查橫三行,豎三列,對角線是否有三個相同的棋子
char IsWin(char board[ROW][COL], int row, int col)
{
    int i = 0;
    //橫三行
    for (i = 0; i < row; i++)
    {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
        {
            //當有三個棋子相同時,返回三個棋子中的一個便可
            //設定中,玩家下棋是‘*’,電腦下棋是'#’,玩家贏 返回,'*'電腦贏返回'#'
            //不用判斷電腦下棋仍是人下棋,直接返回就行
            return board[i][1];
        }
    }
    //豎三列
    for (i = 0; i < col; i++)
    {
        if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
        {
            //當有三個棋子相同時,返回三個棋子中的一個便可
            //設定中,玩家下棋是‘*’,電腦下棋是'#’,玩家贏 返回,'*'電腦贏返回'#'
            //不用判斷電腦下棋仍是人下棋,直接返回就行
            return board[1][i];
        }
    }
    //兩個對角線
    if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
        return board[1][1];
    if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
        return board[1][1];
    //判斷是否平局
    if (1 == IsFull(board, ROW, COL))
    {
        //當棋盤滿了沒有結果說明平局
        return 'Q';
    }
    //判斷完,輸贏,平局,只剩下一種繼續的可能性
    return 'C';
}

ticktacktoe.c

//ticktacktoe.c遊戲測試及初始化部分
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
    printf("**********************\n");
    printf("*** 1.play  2.exit ***\n");
    printf("**********************\n");
}
//遊戲算法實現
void game()
{
    char ret = 0;
    //採用數組存儲走出的棋盤信息
    char board[ROW][COL] = { 0 };
    //棋盤初始化爲空格
    InitBoard(board,ROW,COL);
    //打印棋盤邊框
    DisplayBoard(board, ROW, COL);
    //下棋程序,玩家先下,電腦後下
    //既然是在棋盤內下棋,那麼形參列表應該有棋盤的相關信息
    //調用須要行列信息,棋盤信息

    while (1)
    {
        //玩家走步記錄函數及打印
        PlayerMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);
        //判斷玩家是否贏
        ret = IsWin(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
        //電腦走步記錄函數及打印
        ComputerMove(board, ROW, COL);
        DisplayBoard(board, ROW, COL);
        //判斷電腦是否贏
        ret = IsWin(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    //經過Iswin輸贏判斷函數的返回值輸出遊戲結果
    if (ret == '*')
    {
        printf("玩家贏\n");
    }
    else if (ret == '#')
    {
        printf("電腦贏\n");
    }
    else
    {
        printf("平局\n");
    }
}

void test()
{
    int input = 0;
    srand((unsigned int)time(NULL));//用時間戳控制生成隨機值
    do
    {
        menu();
        printf("請選擇:>");
        scanf("%d", &input);
        switch (input)
        {
        case 0:
            printf("退出遊戲\n");
            break;
        case 1:
            printf("遊戲開始\n");
            game();
            break;
        default:
            printf("選擇錯誤,請從新選擇!\n");
                break;
        }

    } while (input);
}

int main()
{
    test();
    return 0;
}

效果展現

image-20210731155855612

image-20210731155911291

相關文章
相關標籤/搜索