首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C語言實作三子棋遊戲:完整原始碼與邏輯解析

     編輯:程式設計疑難解答

前言

三子棋是一款經典的棋盤遊戲,規則簡單卻極具策略性。本文將帶領大家使用 C 語言從零開始實作一個可在終端機執行的三子棋遊戲,涵蓋棋盤繪製、玩家與電腦輪流落子、勝負判定等核心邏輯。無論你是程式設計新手,或是想複習陣列與函式操作,這都是一個極佳的練習專案。

核心資料結構設計

遊戲的核心在於棋盤狀態的管理。我們使用一個 3x3 的二維字元陣列 char board[3][3] 來儲存棋盤資訊,初始化為空格 ' '。玩家使用 '@' 代表棋子,電腦使用 '#'。另設一個全域變數 int movesLeft = 9 記錄剩餘可落子位置,每落一子遞減,作為判斷平手的依據。

關鍵函式實作詳解

1. 棋盤繪製 printBoard()

使用雙層迴圈遍歷陣列,配合 printf 格式化輸出,將棋盤以直觀的格線形式呈現在終端機。每次落子後呼叫此函式,即可即時更新畫面。

2. 玩家落子 playerMove()

  • 提示玩家輸入座標(行、列,範圍 1-3)。
  • 輸入驗證:檢查座標是否越界,以及目標位置是否已被佔據(board[r][c] != ' ')。
  • 若輸入無效,遞迴呼叫自身要求重新輸入;若有效,更新陣列並遞減 movesLeft。

3. 電腦落子 computerMove()

  • 採用隨機策略:以 srand(time(NULL)) 設定種子,rand() % 3 產生 0-2 的隨機索引。
  • 使用 while 迴圈確保隨機到的位置為空,避免覆蓋既有棋子。
  • 更新陣列與剩餘步數。

4. 勝負判定 checkWinner()

直接硬編碼列舉所有 8 種獲勝條件(3 橫、3 直、2 對角線),分別檢查是否為三個 '@'(玩家贏)或三個 '#'(電腦贏)。若棋盤滿 movesLeft == 0 且無贏家,回傳平手。此寫法雖程式碼較長,但執行效率極高,適合初學者理解邏輯。

主程式流程控制

main() 函式初始化棋盤後,進入無限迴圈 while(1):

  1. 顯示棋盤。
  2. 檢查是否有勝負結果,若有則跳出迴圈。
  3. 玩家落子 -> 顯示棋盤 -> 檢查勝負。
  4. 電腦落子 -> 迴圈繼續。

迴圈結束後,根據 checkWinner() 回傳值輸出最終結果:「玩家獲勝」、「電腦獲勝」或「平手」。

完整原始碼

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

char board[3][3] = {0};
int movesLeft = 9;

void printBoard() {
    int i, j;
    printf(" | | \n");
    for (i = 0; i < 3; i++) {
        printf("_%c_|_%c_|_%c_\n", board[i][0], board[i][1], board[i][2]);
        if (i < 2) printf(" | | \n");
    }
}

void playerMove() {
    int r, c;
    printf("玩家(@) 請輸入座標 (行 列): ");
    scanf("%d %d", &r, &c);
    if (r < 1 || r > 3 || c < 1 || c > 3 || board[r-1][c-1] != ' ') {
        printf("該位置無法落子,請重新輸入!\n");
        playerMove();
    } else {
        board[r-1][c-1] = '@';
        movesLeft--;
    }
}

void computerMove() {
    int r, c;
    printf("電腦(#) 正在思考...\n");
    srand((unsigned)time(NULL));
    do {
        r = rand() % 3;
        c = rand() % 3;
    } while (board[r][c] != ' ');
    board[r][c] = '#';
    movesLeft--;
}

int checkWinner() {
    // 檢查玩家 (@)
    if ((board[0][0]==board[0][1] && board[0][1]==board[0][2] && board[0][2]=='@') ||
        (board[1][0]==board[1][1] && board[1][1]==board[1][2] && board[1][2]=='@') ||
        (board[2][0]==board[2][1] && board[2][1]==board[2][2] && board[2][2]=='@') ||
        (board[0][0]==board[1][0] && board[1][0]==board[2][0] && board[2][0]=='@') ||
        (board[0][1]==board[1][1] && board[1][1]==board[2][1] && board[2][1]=='@') ||
        (board[0][2]==board[1][2] && board[1][2]==board[2][2] && board[2][2]=='@') ||
        (board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[2][2]=='@') ||
        (board[0][2]==board[1][1] && board[1][1]==board[2][0] && board[2][0]=='@'))
        return 1;

    // 檢查電腦 (#)
    if ((board[0][0]==board[0][1] && board[0][1]==board[0][2] && board[0][2]=='#') ||
        (board[1][0]==board[1][1] && board[1][1]==board[1][2] && board[1][2]=='#') ||
        (board[2][0]==board[2][1] && board[2][1]==board[2][2] && board[2][2]=='#') ||
        (board[0][0]==board[1][0] && board[1][0]==board[2][0] && board[2][0]=='#') ||
        (board[0][1]==board[1][1] && board[1][1]==board[2][1] && board[2][1]=='#') ||
        (board[0][2]==board[1][2] && board[1][2]==board[2][2] && board[2][2]=='#') ||
        (board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[2][2]=='#') ||
        (board[0][2]==board[1][1] && board[1][1]==board[2][0] && board[2][0]=='#'))
        return 0;

    if (movesLeft == 0) return -1; // 平手
    return 2; // 遊戲繼續
}

int main() {
    int i, j;
    for (i = 0; i < 3; i++)
        for (j = 0; j < 3; j++)
            board[i][j] = ' ';

    while (1) {
        printBoard();
        int result = checkWinner();
        if (result != 2) break;

        playerMove();
        printBoard();
        result = checkWinner();
        if (result != 2) break;

        computerMove();
    }

    switch (checkWinner()) {
        case 1: printf("\n恭喜!玩家獲勝!\n"); break;
        case 0: printf("\n電腦獲勝,再接再厲!\n"); break;
        case -1: printf("\n平手!\n"); break;
    }
    system("pause");
    return 0;
}

延伸優化方向

  • AI 升級:引入 Minimax 演算法與 Alpha-Beta 剪枝,實現「必不敗」的完美 AI。
  • 介面優化:使用 system("cls") (Windows) 或 ANSI 轉義碼清屏,提升視覺體驗。
  • 模組化:將棋盤大小抽象為常數,支援擴展為五子棋等變體。

這個專案完整展示了 C 語言處理陣列、函式模組化、隨機數生成與流程控制的基礎能力,是從「寫代碼」邁向「設計程式」的關鍵一步。建議動手敲一遍,並嘗試加入上述優化,加深理解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved