使用C語言實現五子棋遊戲

本文實例為大傢分享瞭C語言實現五子棋遊戲的具體代碼,供大傢參考,具體內容如下

一、實現的目的和意義

1、鞏固和加深對c語言知識的理解
2、學會使用編譯器的各種調試
3、提高解決實際問題的能力

二、實現內容描述

實現簡單的人人對戰五子棋,此設計用的是C語言去實現

三、實現原理

采用二位數組保存棋盤信息,棋盤上面的任何一個位置,裡頭可以放三個信息:

1、空
2、用戶1的落子
3、用戶2的落子

下棋就是在二維數組種找對應的空位置,進行落子,落完之後立即就要判斷落子位置是否有五字連珠,從而判斷誰數輸誰贏。每走一次棋會有四種情況:

*用戶1贏
*用戶2贏
*平局(這裡說的平局是棋盤被占滿的情況)
*沒有出結果 意思就是時此用戶沒贏 下個用繼續去下棋

四、實現模塊五子棋實現分為三大模塊

文件名                       作用
five_chress.h       五子棋的函數聲明,頭文件聲明等
five_chress.c       五子棋函數接口的實現
main.c              五子棋函數測試功能

五、模塊代碼分析

1、five_chress.h

#pragma once
#include <stdio.h>
#include <string.h>
#include<Windows.h>
#define ROW 10//數組號行號 按需求調整
#define COL 10//數組列數 按需求調整
#define PLAYER1 1//玩傢編號,默認棋盤數據是0,玩傢1落子,該位置被改成1
#define PLAYER2 2//玩傢編號,默認棋盤數據是0,玩傢2落子,該位置被改成2
#define NEXT        0//遊戲繼續
#define PLAYER1_WIN 1//玩傢1贏
#define PLAYER2_WIN 2//玩傢2贏
#define DRAW        3//平局

   enum Dir{
    LEFT,
    RIGHT,
    UP,
    DOWN,
    LEFT_UP,
    LEFT_DOWN,
    RIGHT_UP,
    RIGHT_DOWN
    };//用枚舉去表示4個方向,上下,左右,左上右下,右上左下,統計用戶當前棋子四個方向的棋數是否為大於等於5
    void Menu();//實現菜單
    void Game();//構建遊戲入口Game()函數      

2、five_chress.c

#include "five_chress.h"

int x = 0;
int y = 0;

void Menu()
{
    printf("############################\n");
    printf("## 1. Play        0. Exit ##\n");
    printf("############################\n");
    printf("Please Select# ");
}

//按照x,y作為起點,按照特定的方向,求連續相對的最大格式
int ChessCount(int board[][COL], int row, int col, enum Dir d)
{
    int _x = x - 1; //從1
    int _y = y - 1; //從1

    int count = 0;
    while (1){
        switch (d){
        case LEFT://從當前位置向左移動統計 橫坐標不變 縱坐標變瞭 所以是y--
            _y--;
            break;
        case RIGHT://從當前位置向右移動統計 橫坐標不變 縱坐標變瞭 所以是_y++
            _y++;
            break;
        case UP://從當前位置向上移動統計 縱坐標不變 橫坐標變瞭 所以是_x--
            _x--;
            break;
        case DOWN://從當前位置向下移動統計 縱坐標不變 橫坐標變瞭 所以是_x++
            _x++;
            break;
        case LEFT_UP://從當前位置向左上移動統計 縱,橫變都變瞭 所以是_x--,_y--
            _x--, _y--;
            break;
        case LEFT_DOWN://從當前位置左下移動統計 縱,橫坐標都變瞭 所以是_x++,_y--
            _x++, _y--;
            break;
        case RIGHT_UP://從當前位置右上移動統計 縱,橫坐標都變瞭 所以是_x--,_y++-
            _x--, _y++;
            break;
        case RIGHT_DOWN://從當前位置右下移動統計 縱,橫坐標都變瞭 所以是_x++,_y++
            _x++, _y++;
            break;
        default:
            //Do Nothing
            break;
        }
        if (_x < 0 || _x > row - 1 || _y < 0 || _y > col - 1){
            break;/表示越界瞭就停止
        }
        //合法
        if (board[x - 1][y - 1] == board[_x][_y]){
            count++;//統計從舊位置出發統計和他一樣的個數
        }
        else{
            break;//如果碰到不一樣的就終止循環
        }
    }
    return count;//返回統計個數
}

//4種情況
//NEXT:表明要繼續
//PLAYER1_WIN: 用戶1贏瞭
//PLAYER2_WIN:用戶2贏瞭
//DRAW: 平局
int IsOver(int board[][COL], int row, int col)
{
    
    int count1 = ChessCount(board, row, col, LEFT) + ChessCount(board, row, col, RIGHT) + 1; //?
    int count2 = ChessCount(board, row, col, UP) + ChessCount(board, row, col, DOWN) + 1; //?
    int count3 = ChessCount(board, row, col, LEFT_UP) + ChessCount(board, row, col, RIGHT_DOWN) + 1; //?
    int count4 = ChessCount(board, row, col, LEFT_DOWN) + ChessCount(board, row, col, RIGHT_UP) + 1; //?

    if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5){
        //有五子連珠
        //一定有人贏
        //x, y
        if (board[x - 1][y - 1] == PLAYER1){
            return PLAYER1_WIN;
        }
        else{
            return PLAYER2_WIN;
        }
    }

    int i = 0;
    for (; i < row; i++){
        int j = 0;
        for (; j < col; j++){
            if (board[i][j] == 0){
                return NEXT;//當前位置還沒有被填寫棋盤不滿 當前用戶沒有贏返回next  讓下個用戶繼續下
            }
        }
    }

    return DRAW;//最後一種情況棋盤滿瞭 為平局
}

void ShowBoard(int board[][COL], int row, int col)
{
    //printf("\e[1;1H\e[2J");這是linux環境下用的清屏
    //講數組內容,進行可視化
    system("cls");//vs環境下用的清屏
    
    int i = 0;
    for (i=1; i <= col; i++){
        printf("%3d", i);
    }
    printf("\n");

    for (i = 0; i < row; i++){
        int j = 0;
        printf("%2d",i + 1 );
        for (; j < col; j++){
            if (board[i][j] == 0){
                printf(" . ");
            }
            else if (board[i][j] == PLAYER1){
                printf(" x ");
            }
            else{
                printf (" y ");
            }
        }
        printf("\n");
    }
}

void PlayerMove(int board[][COL], int row, int col, int who)
{
    while (1){
        printf("Player[%d] Please Enter Your Pos# ", who);
        scanf("%d %d", &x, &y);
        if (x < 1 || x > row || y < 1 || y > col){
            printf("Pos Is Not Right!\n");
            continue;
        }
        else if (board[x - 1][y - 1] != 0){
            printf("Pos Is Occupied!\n");
            continue;
        }
        else{
            //合法性,去重
            board[x - 1][y - 1] = who;
            break;
        }
    }
}

void Game()
{
    int board[ROW][COL];
    memset(board, 0, sizeof(board));
    int result = NEXT;
    do{
        ShowBoard(board, ROW, COL);//顯示棋盤
        PlayerMove(board, ROW, COL, PLAYER1);//Player1先走
        result = IsOver(board, ROW, COL);//判斷遊戲是否結束
        if (NEXT != result){
            break;//如果返回值不等於NEXT就跳出循環 說明當前用戶贏瞭或者平局 如果=NEXT 下個用戶繼續下
        }
        ShowBoard(board, ROW, COL);//同上
        PlayerMove(board, ROW, COL, PLAYER2);
        result = IsOver(board, ROW, COL);
        if (NEXT != result){
            break;
        }
    } while (1);
    //p1 win, p2 win, draw
    switch (result){
    case PLAYER1_WIN:
        ShowBoard(board, ROW, COL);
        printf("恭喜用戶1,你已經贏瞭!\n");
        break;
    case PLAYER2_WIN:
        printf("恭喜用戶2,你已經贏瞭!\n");
        break;
    case DRAW:
        printf("平局\n");
        break;
    default:
        //do nothing!
        break;
    }
}

分析:

我們要先構建遊戲入口void game()函數在裡面構建上層本調用框架 例如一開始初始化數組把每個位置都置為0,然後構建調用框架:

1、我們要保存二位數組並可視化 就要構建ShowBoard函數;
2、之後 我們要讓用戶下棋 就要構建PlayerMove()函數
3、第一個用戶下完之後就要立馬判斷當前用戶是否贏,因為落子和判定是強相關的 這時候要構建 IsOver()函數
如果此用戶沒贏 那二個用戶繼續下。
當我們這些函數邏輯都明確好的時候 就用分而治之思想 ,實現他們的功能。
* 1、ShowBoard()函數裡面我用到瞭一個c語言裡面的清屏函數printf(“cls”);引上頭文件window.h,這個的作用是在固定地方刷新視圖,把上次的視圖清理掉 ,顯示當前位置視圖。
後面就打印視圖的內容。用戶一和用戶二可以用字符表示,也可以用圓圈圖案表示這個圖案可以在網上找復制一下就可
*2、 Playermove()函數讓用戶下棋,裡面先考慮它的合法性 ,不能越界和重復,再然後用我們在five_chrsss.h文件定義宏來賦值 ,賦完之後再終止循環。
*3、 Isover()函數裡面是讓我們判斷誰輸誰贏 換句話遊戲是否結束。遊戲結束標志是分為四種情況。用戶一贏,用戶二贏,平局,繼續。前兩種情況則需要判斷從當前位置出發 沿四個方向當前用戶棋的個數是否為大於等於5,在判斷一下是哪個用戶的棋 就返回哪個用戶。 而這判斷需要在構建並調用ChressCount()函數去統計當前用戶的個數是否大於等於5,有4個方向,例如上和下為一個方向,左和右為一個方向,左上和右下為一個方向,右上和左下為一個方向,分別各自相加之後在加上1就是當前的棋,如果滿足這個4個方向大於等於5的一個條件,我們就能知道一定有人贏,否則在繼續判斷周圍是否有
空位置,有則返回NEXT讓下個用戶繼續下,沒有則返回平局*ChressCoun()函數具體分析請看代碼塊

這些函數實現完之後再在Game()函數裡面來個Switch循環,來結收宏 去打印誰贏 還是平局。

3、main.c

#include "five_chress.h"

int main()
{
    int quit = 0;
    int select = 0;
    while (!quit){
        Menu();
        scanf("%d", &select);
        switch (select){
        case 1:
            Game();
            break;
        case 0:
            quit = 1;
            printf("ByeBye!\n");
            break;
        default:
            printf("Enter Error, Try Again!\n");
            break;
        }
    }

    return 0;
}

main函數作為測試入口,相比較裡面的邏輯是很簡單的,創建一個菜單函數和調用一個Game函數,再增添點其他的內容。

六、實現結果

七、總結

實現五子棋給我最大的體會是應用比理論學習難得多,首先要邏輯清楚,也會涉及到各種實際問題,但是加深瞭我對知識的理解和運用,也知道瞭隻有多練習 多寫代碼才能更好的提升編程技術。同時我也學到瞭實現一個復雜的項目時,先去構建一個框架,一個清晰的邏輯。再去逐個擊破每個問題,要學會用分而治之的思想去解決問題。

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: