用C語言完成:三子棋。


今天要完成一個相對於之前學習更有挑戰性的小程序——三子棋。

相信我們大部分人都接觸過三子棋,這是一款操作簡單易上手的小游戲。

先簡單介紹一下三子棋的規則,方便我們接下來的編程和理解。規則如下:

在九宮格棋盤上,只要將自己的三個棋子走成一條線(橫、豎、對角線),對方就算輸了。

 

規則很簡單,但是我們應該從哪里入手完成這個三子棋程序呢?

 

首先,我們的游戲程序應該先有個菜單頁面,這個菜單頁面用來讓用戶操作選擇玩游戲,或是退出。

界面可以很簡單,只需要幾條 printf 語句即可。

這里我們盡可能用函數來完成游戲的功能:

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

這就是一個簡單的主菜單界面,效果如下:

既然菜單中有選項,我們就必須要設計一個變量用來接收用戶的選擇。

而且游戲程序本身應該允許用戶反復進行玩耍,所以在主函數中,我們需要用一個循環來完成這個功能。

do-while循環在調用時會先運行循環體,而后在進行判斷,所以這里我們選擇使用do-while循環:

int main()
{
    int choice;
    do
    {
        menu();
        printf("Input your choice:");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf(" Input error!Please try again.\n");
            break;
        }
    } while (choice);
    return 0;
}

由於用戶選擇選項1時我們需要為用戶啟動游戲程序,所以這里我們使用一個switch語句來接受用戶的選擇。

選擇0時退出程序,所以我們只需要跳出循環,即可退出。

而輸入0、1之外的值時,我們應該向用戶報輸入錯誤,所以在default中輸出一條報錯信息。

接下來就是我們程序的重點——三子棋游戲本身了。

先創建一個game()函數,里面的內容我們一步步來填充。

void game()
{
}

在程序開始階段,我們首先要創建一個3*3的二維字符數組,

由於長和寬我們要經常用到,為了后續修改方便,我們采用宏定義方式:

#define ROWS 3
#define COLS 3

接下來在game()函數中創建數組:

char board[ROWS][COLS];

並將這個數組進行初始化,因為這個數組在后續需要輸出展示在用戶面前,所以我們將值初始化為空格“ ”。

初始化用函數進行完成:

void init_board(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ' ';
        }
    }
}

接下來,我們應該輸出這個數組棋盤,來檢查一下是否初始化完成,

但我們沒有展示棋盤的函數,所以我們需要完成這個顯示棋盤函數:

void show_board(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (int i = 0; i < rows; i++)
    {
        printf("  %c | %c | %c  \n",board[i][0],board[i][1],board[i][2]);
        if (i != rows - 1)
            printf(" ---|---|--- \n");
    }    
}

這里需要利用循環來輸出我們棋盤的格式,格式不統一,可以根據自己的喜好進行修改。

下面展示一下我這個代碼所輸出的棋盤:

上面已經看出我的棋盤初始化已經完成,所以接下來我們需要考慮如何讓電腦或用戶進行下棋操作了。

電腦走需要讓電腦產生隨機坐標,然后在數組的這個坐標位置放入一個“X”作為電腦的棋子。

所以代碼如下:

void ComputerMove(char board[ROWS][COLS], int rows, int cols)
{

    int x, y;
    printf("Compter's turn to move:\n");
    while (1)
    {
        x = rand() % rows;
        y = rand() % cols;
        if (board[x][y] == ' ')
        {
            board[x][y] = 'X';
            break;
        }
    }
}

rand()是用來生成隨機數的,這里我們還需要在主函數main中加上一行代碼。

由於我們不希望他多次生成隨機數,生成一次就足夠用了,所以直接在創建choice變量的下一行加上下面這個代碼即可:

srand((unsigned int)time(NULL));

注意生成隨機數需要引用time.h這個頭文件。

電腦下完棋后,需要輪到我們的用戶進行下棋操作,這個函數和電腦下棋大同小異,

但是要注意人的習慣不會輸入(0,0)這個坐標,而是輸入(1,1)。

所以這里我們要給傳過去的參數-1。

解決這個問題后的代碼如下:

void player_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y;
    printf("Player's turn to move:\n");
    while (1)
    {
        printf("Input x and y(like x y):\n");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= rows && y >= 1 && y <= cols)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = 'O';
                break;
            }
            else printf("The location has been taken!Please try again.\n");
        }
        else printf(" Input error!Please try again.\n");
    }
}

在雙方走完后,我們需要判斷是否勝利,也就是判斷之前我們提到的規則,

這時我們需要編寫一個checkwin()函數來檢測並返回一個值表示誰獲勝。

代碼如下:

char check_win(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (i = 0; i < rows; 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 < cols; 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];
    else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
        return board[1][1];
    else if (is_full(board, rows, cols))
        return 'q';
    return 0;
}

由於可能出現棋盤下滿,卻沒人獲勝的情況,
所以我們需要在其中判斷一下平局的情況,

這里我們編寫了一個is_full()函數,用來判斷棋盤是否下滿:

static int is_full(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

注意這個函數我們只在checkwin中會使用到,我們並不希望它在其他源文件的函數中被使用,所以我們加上了static。

這時程序的雛形已經基本完成,我們只需要按我們自己理解的游戲步驟來完成game()函數即可。

所以完成后的game()函數如下所示:

void game()
{
    char win = 0;
    char arr[ROWS][COLS];
    init_board(board, ROWS, COLS);
    do
    {
        computer_move(board, ROWS, COLS);
        show_board(board, ROWS, COLS);
        win = check_win(board, ROWS, COLS);
        if (win != 0)
            break;
        player_move(board, ROWS, COLS);
        show_board(board, ROWS, COLS);
        win = check_win(board, ROWS, COLS);
    } while (win == 0);
    if (win == 'X')
        printf("You lose!Good luck next time!\n");
    if (win == 'O')
        printf("You win!Congratulations!\n");
    if (win == 'q')
        printf("The score was tied!Good luck next time!\n");
}

這樣,將上面各個部分合在一起,這個程序就被我們完成了。

 

下面放上我自己寫的,比較丑陋的代碼:

我的代碼分為三部分,

第一部分是頭文件:

#ifndef __CHESS_H__
#define __CHESS_H__

#include<stdio.h>
#include<time.h>
#include<Windows.h>

#define ROWS 3
#define COLS 3

void show_board(char board[ROWS][COLS], int rows, int cols);
void init_board(char board[ROWS][COLS], int rows, int cols);
void computer_move(char board[ROWS][COLS], int rows, int cols);
void player_move(char board[ROWS][COLS], int rows, int cols);
char check_win(char board[ROWS][COLS], int rows, int cols);

# endif//__CHESS_H__

第二部分是源文件的函數部分:

#include"3chess.h"

void show_board(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (int i = 0; i < rows; i++)
    {
        printf("  %c | %c | %c  \n",board[i][0],board[i][1],board[i][2]);
        if (i != rows - 1)
            printf(" ---|---|--- \n");
    }    
}

void init_board(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ' ';
        }
    }
}

void computer_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y, i;
    printf("Compter's turn to move:\n");
    while (1)
    {
        x = rand() % rows;
        y = rand() % cols;    
        for (i = 0; i < rows; i++)
        {
            if (board[i][0] == board[i][1] && board[i][0] == 'X' && board[i][2] == ' ')
            {
                board[i][2] = 'X';
                goto flag1;
            }
            else if (board[i][1] == board[i][2] && board[i][1] == 'X' && board[i][0] == ' ')
            {
                board[i][0] = 'X';
                goto flag1;
            }
            else if (board[i][0] == board[i][2] && board[i][2] == 'X' && board[i][1] == ' ')
            {
                board[i][1] = 'X';
                goto flag1;
            }
            else if (board[0][i] == board[1][i] && board[0][i] == 'X' && board[2][i] == ' ')
            {
                board[2][i] = 'X';
                goto flag1;
            }
            else if (board[1][i] == board[2][i] && board[1][i] == 'X' && board[0][i] == ' ')
            {
                board[0][i] = 'X';
                goto flag1;
            }
            else if (board[0][i] == board[2][i] && board[2][i] == 'X' && board[1][i] == ' ')
            {
                board[1][i] = 'X';
                goto flag1;
            }
            else if (board[0][0] == board[1][1] && board[0][0] == 'X' && board[2][2] == ' ')
            {
                board[2][2] = 'X';
                goto flag1;
            }
            else if (board[1][1] == board[2][2] && board[1][1] == 'X' && board[0][0] == ' ')
            {
                board[0][0] = 'X';
                goto flag1;
            }
            else if (board[0][0] == board[2][2] && board[0][0] == 'X' && board[1][1] == ' ')
            {
                board[1][1] = 'X';
                goto flag1;
            }
            else if (board[0][2] == board[1][1] && board[1][1] == 'X' && board[2][0] == ' ')
            {
                board[2][0] = 'X';
                goto flag1;
            }
            else if (board[1][1] == board[2][0] && board[1][1] == 'X' && board[0][2] == ' ')
            {
                board[0][2] = 'X';
                goto flag1;
            }
            else if (board[2][0] == board[0][2] && board[2][0] == 'X' && board[1][1] == ' ')
            {
                board[1][1] = 'X';
                goto flag1;
            }
        }
        for (i = 0; i < rows; i++)
        {
            if (board[i][0] == board[i][1] && board[i][0] == 'O' && board[i][2] == ' ')
            {
                board[i][2] = 'X';
                goto flag1;
            }
            else if (board[i][1] == board[i][2] && board[i][1] == 'O' && board[i][0] == ' ')
            {
                board[i][0] = 'X';
                goto flag1;
            }
            else if (board[i][0] == board[i][2] && board[i][2] == 'O' && board[i][1] == ' ')
            {
                board[i][1] = 'X';
                goto flag1;
            }
            else if (board[0][i] == board[1][i] && board[0][i] == 'O' && board[2][i] == ' ')
            {
                board[2][i] = 'X';
                goto flag1;
            }
            else if (board[1][i] == board[2][i] && board[1][i] == 'O' && board[0][i] == ' ')
            {
                board[0][i] = 'X';
                goto flag1;
            }
            else if (board[0][i] == board[2][i] && board[2][i] == 'O' && board[1][i] == ' ')
            {
                board[1][i] = 'X';
                goto flag1;
            }
            else if (board[0][0] == board[1][1] && board[0][0] == 'O' && board[2][2] == ' ')
            {
                board[2][2] = 'X';
                goto flag1;
            }
            else if (board[1][1] == board[2][2] && board[1][1] == 'O' && board[0][0] == ' ')
            {
                board[0][0] = 'X';
                goto flag1;
            }
            else if (board[0][0] == board[2][2] && board[0][0] == 'O' && board[1][1] == ' ')
            {
                board[1][1] = 'X';
                goto flag1;
            }
            else if (board[0][2] == board[1][1] && board[1][1] == 'O' && board[2][0] == ' ')
            {
                board[2][0] = 'X';
                goto flag1;
            }
            else if (board[1][1] == board[2][0] && board[1][1] == 'O' && board[0][2] == ' ')
            {
                board[0][2] = 'X';
                goto flag1;
            }
            else if (board[2][0] == board[0][2] && board[2][0] == 'O' && board[1][1] == ' ')
            {
                board[1][1] = 'X';
                goto flag1;
            }
        }
        if (board[x][y] == ' ')
        {
            board[x][y] = 'X';
            goto flag1;
        }
    }
flag1:;
}

void player_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y;
    printf("Player's turn to move:\n");
    while (1)
    {
        printf("Input x and y(like x y):\n");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= rows && y >= 1 && y <= cols)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = 'O';
                break;
            }
            else printf("The location has been taken!Please try again.\n");
        }
        else printf(" Input error!Please try again.\n");
    }
}

static int is_full(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

char check_win(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (i = 0; i < rows; 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 < cols; 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];
    else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
        return board[1][1];
    else if (is_full(board, rows, cols))
        return 'q';
    return 0;
}

這一部分是經過發揮的,讓電腦更智能,但代碼部分我並沒有想出簡化的寫法,只好一步步的用if語句進行完成了。

第三部分是源文件的游戲測試部分:

#include"3chess.h"
void menu()
{
    printf("***************************************\n");
    printf("*      1.play             0.exit      *\n");
    printf("***************************************\n");
}
void first_move()
{
    printf("***************************************\n");
    printf("*  1.computer first   2.player first  *\n");
    printf("***************************************\n");
}
void game()
{
    int choice_1, win;
    char board[ROWS][COLS];
    init_board(board, ROWS, COLS);
    first_move();
flag:
    printf("Input your choice;");
    scanf("%d", &choice_1);
    switch (choice_1)
    {
    case 1:
        do
        {
            computer_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = check_win(board, ROWS, COLS);
            if (win != 0)
                break;
            player_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = check_win(board, ROWS, COLS);
        } while (win == 0);
        if (win == 'X')
            printf("You lose!Good luck next time!\n");
        if (win == 'O')
            printf("You win!Congratulations!\n");
        if (win == 'q')
            printf("The score was tied!Good luck next time!\n");
        break;
    case 2:
        do
        {
            show_board(board, ROWS, COLS);
            player_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = check_win(board, ROWS, COLS);
            if (win != 0)
                break;
            computer_move(board, ROWS, COLS);
            win = check_win(board, ROWS, COLS);
        } while (win == 0);
        if (win == 'X')
            printf("You lose!Good luck next time!\n");
        if (win == 'O')
            printf("You win!Congratulations!\n");
        if (win == 'q')
            printf("The score was tied!Good luck next time!\n");
        break;
    default:
        printf(" Input error!Please try again.\n");
        goto flag;
    }
}
int main()
{
    int choice;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("Input your choice:");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf(" Input error!Please try again.\n");
            break;
        }
    } while (choice);
    return 0;
}

這一部分,我加入了讓用戶選擇電腦先走或者用戶先走的功能,使用戶的游戲體驗更好。

以上就是我的代碼,希望各位能幫助我進行優化改進。


免責聲明!

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



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