三子棋游戲設計與實現(C 語言版)

一、需求分析

目標:實現一個簡單的人機對戰三子棋,支持以下功能:

  1. 初始化空棋盤,清晰展示落子狀態。
  2. 玩家通過坐標落子(X?代表玩家),電腦隨機落子(O?代表電腦)。
  3. 實時判斷勝負:某方三子連成一線(行 / 列 / 對角線)則獲勝;棋盤填滿則平局。

二、設計思路

1. 模塊拆分(高內聚低耦合)

  • 數據層:用二維數組?char board[ROW][COL]?存儲棋盤狀態。
  • 邏輯層:封裝獨立函數,如初始化棋盤、打印棋盤、落子、勝負判斷。
  • 交互層:通過菜單讓用戶選擇 “開始游戲” 或 “退出”,控制游戲流程。

三、代碼結構解析

1. 多文件組織(工程化思路)

  • Noughts and crosses.h:聲明函數、定義常量(如?ROW=3),解耦接口與實現。
  • Noughts and crosses.c:實現具體邏輯(初始化、打印、落子等),隱藏細節。
  • test.c:負責游戲流程控制(菜單、主循環),專注交互。

2. 關鍵函數拆解

1.頭文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include<windows.h>//棋盤尺寸
#define ROW 3
#define COL 3//初始化
void InitBoard(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 CheckWin(char board[ROW][COL], int row, int col);
//設置控制臺文本顏色
void SetColor(int color);

2.關鍵函數分析(每個函數的定義寫在Noughts and crosses.c):

  1. ? ? ? ??
    void InitBoard(char board[ROW][COL], int row, int col)
    {for (int i = 0;i < row;i++){for (int j = 0;j < col;j++){board[i][j] = ' ';}}//隨機種字(用于電腦下棋隨機化)srand((unsigned int)time(NULL));
    }

    初始化,通過二維數組來實現棋盤,將9個格子初始化為空。? srand((unsigned? ? ? int)time(NULL));這段代碼:是指time(NULL)以獲取當前系統時間(從 1970 年 1 月 1 日到現在的秒數,也叫 “時間戳” )。將其類型轉換為unsigned??int 來適配srand 這樣就會生成隨機數的 “起點,生成真隨機值。如果是一個常數,那么會生成固定的序列。

  2. void DisplayBoard(char board[ROW][COL], int row, int col)
    {system("cls");//清空printf("=== 三子棋游戲 ===\n");for (int i = 0;i < row;i++){for (int j = 0;j < col;j++){if (board[i][j] == 'X'){SetColor(12);//紅色}else if (board[i][j] == 'O'){SetColor(9);//藍色}else{SetColor(7);//白色默認色}printf(" %c ", board[i][j]);if (j < col - 1){SetColor(7);printf("|");}}printf("\n");if (i < row - 1){SetColor(7);for (int j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}printf("\n");}}
    }
    

    打印棋盤,棋盤里會有X ,O ,“? ” ,---,|,等元素。通過循環遍歷用判斷語句來給這其中的元素附加顏色,然后再打印二維數組的元數 ,再通過判斷語句的條件,讓 | 這個放在其該在的位置(這里的是落子后面的 | )再“\n"換行?。這就第一行完事了接著我們要想第二行,在第一個循環里加上行的判斷條件,先給它附上顏色 ,再加嵌套循環,來給--- 加上 ,再加上 | 。再換行。

  3. //玩家下棋
    void PlayerMove(char board[ROW][COL], int row, int col)
    {int x, y;printf("玩家下棋(輸入坐標,如:1 1)");while (1){scanf_s("%d %d", &x, &y);if (x >= 0 && x < row && y >= 0 && y < col){if (board[x][y] == ' '){board[x][y] = 'X';break;}else{printf("該位置已占有,請重新輸入");}}else{printf("坐標無效,請重新輸入(l~%d, l~%d):",row,col);}}}

    玩家下棋,我這里是通過坐標落子,要定義兩個變量下x,y。因為我要將每次下完棋更新再同一棋盤,而不是每下完其再在小黑屏里加一個棋盤,所以我加了個while循環。首先我們要判斷x,y的定義域。接著還在注意落子的地方是不是空的。還有下棋時,你填的坐標是否正確。不正確如何處理。這些可以用判斷語句來實現。

  4. // 策略AI:優先封堵玩家即將獲勝的位置,否則隨機落子
    void ComputerMove(char board[ROW][COL], int row, int col)
    {printf("電腦思考中...\n");// 1. 先檢查電腦自己能否獲勝,有機會則直接落子for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] == ' ') {// 嘗試在此處落子board[i][j] = 'O';// 檢查是否能贏if (CheckWin(board, row, col) == 'O') {return; // 能贏則直接落子}// 不能贏則撤銷嘗試board[i][j] = ' ';}}}// 2. 再檢查玩家是否即將獲勝,若有則封堵for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){if (board[i][j] == ' '){// 模擬玩家在此處落子board[i][j] = 'X';// 檢查玩家是否能贏if (CheckWin(board, row, col) == 'X') {// 封堵這個位置board[i][j] = 'O';return;}// 玩家不能贏則撤銷嘗試board[i][j] = ' ';}}}// 3. 若沒有需要封堵的位置,隨機落子while (1) {int x = rand() % row;int y = rand() % col;if (board[x][y] == ' ') {board[x][y] = 'O';break;}}
    }

    為了讓游戲不是那么簡單。我加了電腦3種下棋方式:1.判斷電腦下棋是否能贏,就下。2.判斷玩家下棋能贏就阻斷。3.最后是沒有前幾種情況就隨機下。這里要用到CheckWin函數。其實這里的邏輯就是:預測。你們可以分析代碼就知道了。這樣也能找到些許樂趣。

  5. // 判斷勝負
    // 返回值:
    // 'X' -> 玩家勝
    // 'O' -> 電腦勝
    // 'Q' -> 平局
    // 'C' -> 繼續
    char CheckWin(char board[ROW][COL], int row, int col)
    {// 1. 檢查行for (int 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];}}// 2. 檢查列for (int j = 0; j < col; j++){if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ') {return board[0][j];}}// 3. 檢查對角線if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') {return board[0][0];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ') {return board[0][2];}// 4. 檢查是否平局(無空格)int full = 1;for (int i = 0; i < row; i++){for (int j = 0; j < col; j++) {if (board[i][j] == ' '){full = 0;break;}}if (!full) break;}if (full) {return 'Q';}// 5. 繼續游戲return 'C';
    }

    檢查輸贏:我們首先要給輸贏 ,平or 繼續游戲用一些符號表示作為返回值。'X' -> 玩家勝? 'O' -> 電腦勝? 'Q' -> 平局? ?'C' -> 繼續。X 與 O是玩家和電腦的子的形式,可以通過行,列,對角線的檢查 方便返回二維數組里的元素。平局:我們要定義一個變量full來查看棋盤是否滿了。最后只剩:C 繼續游戲了。

  6. void SetColor(int color) {HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hConsole, color);
    }

    這是我們要改顏色用的函數。

3.菜單

  1. 代碼:
     char board[ROW][COL];char result = 'C';int player_wins = 0;int computer_wins = 0;int ties = 0;char play_again = 'Y';while (play_again == 'Y' || play_again == 'y') {// 初始化棋盤InitBoard(board, ROW, COL);printf("=== 三子棋游戲 ===\n");printf("總戰績:玩家 %d 勝 | 電腦 %d 勝 | 平局 %d 次\n",player_wins, computer_wins, ties);DisplayBoard(board, ROW, COL);// 游戲循環while (1) {// 玩家回合PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);// 判斷結果result = CheckWin(board, ROW, COL);if (result == 'X') {printf("=== 玩家獲勝! ===\n");player_wins++;break;}else if (result == 'Q') {printf("=== 平局! ===\n");ties++;break;}// 電腦回合ComputerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);// 判斷結果result = CheckWin(board, ROW, COL);if (result == 'O') {printf("=== 電腦獲勝! ===\n");computer_wins++;break;}else if (result == 'Q') {printf("=== 平局! ===\n");ties++;break;}}// 詢問是否再來一局printf("是否再來一局?(Y/N): ");scanf_s(" %c", &play_again);while (play_again != 'Y' && play_again != 'y' &&play_again != 'N' && play_again != 'n') {printf("輸入無效,請輸入 Y 或 N: ");scanf_s(" %c", &play_again);}}// 顯示最終戰績printf("\n=== 游戲結束 ===\n");printf("最終戰績:玩家 %d 勝 | 電腦 %d 勝 | 平局 %d 次\n",player_wins, computer_wins, ties);if (player_wins > computer_wins) {printf("玩家勝率更高!\n");}else if (player_wins < computer_wins){printf("電腦勝率更高!\n");}else {printf("雙方勢均力敵!\n");}return 0;

    2.分析:這里我們要有? 游戲繼續還是結束? 記錄比賽比分? ?勝率的分析等的功能 。因此我們要定義 6個變量 。第一個while決定著游戲的繼續還是結束,如果繼續就初始化以及打印棋盤。第二個while來按照先玩家再電腦的順序落子,里面要有打印棋盤刷新棋盤。還有判斷落子后的效果。第三個while則是與第一個while呼應判斷玩家是否玩還是不玩,以及玩家輸入錯誤信息的處理方式。最后結束游戲打印結果勝率的分析。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88711.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88711.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88711.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GD32 CAN1和TIMER0同時開啟問題

背景&#xff1a;今天在一個項目調試的時候發現了一些問題&#xff0c;由此貼記錄一下問題解決的過程。使用的芯片是GD32F305VE。使用到了CAN1和TIMER0。在使用這連個外設的時候發送了一些問題。單獨使用CAN1。功能正常。單獨使用TIMER0。配置為輸出模式。功能正常。但是當兩個…

劍指offer56_數組中唯一只出現一次的數字

數組中唯一只出現一次的數字在一個數組中除了一個數字只出現一次之外&#xff0c;其他數字都出現了三次。 請找出那個只出現一次的數字。 你可以假設滿足條件的數字一定存在。 思考題&#xff1a; 如果要求只使用 O(n) 的時間和額外 O(1) 的空間&#xff0c;該怎么做呢&#xf…

從語音識別到智能助手:Voice Agent 的技術進化與交互變革丨Voice Agent 學習筆記

From Research AI&#xff1a; 最近看到 Andrew Ng 的一句話讓我印象深刻&#xff1a;“While some things in AI are overhyped, voice applications seem underhyped right now.”&#xff08;盡管 AI 中有些領域被過度炒作&#xff0c;語音應用卻似乎被低估了&#xff09;。…

什么是Jaccard 相似度(Jaccard Similarity)

文章目錄? 定義&#xff1a;&#x1f4cc; 取值范圍&#xff1a;&#x1f50d; 舉例說明&#xff1a;&#x1f9e0; 應用場景&#xff1a;?? 局限性&#xff1a;&#x1f4a1; 擴展概念&#xff1a;Jaccard 相似度&#xff08;Jaccard Similarity&#xff09; 是一種用于衡量…

ragflow_多模態文檔解析與正文提取策略

多模態文檔解析與正文提取策略 RAGflow的文檔解析系統位于deepdoc/parser/目錄下,實現了對多種文檔格式的統一解析處理。該系統采用模塊化設計,針對不同文檔格式提供專門的解析器,并通過視覺識別技術增強解析能力。本文將深入探討RAGflow的文檔解析系統的設計原理、實現細節…

數據結構棧的實現(C語言)

棧的基本概念棧是一種特殊的線性存儲結構&#xff0c;是一種操作受到限制的線性表&#xff0c;特殊體現在兩個地方&#xff1a;1、元素進棧出棧的操作只能從同一端完成&#xff0c;另一端是封閉的&#xff0c;通常將數據進棧叫做入棧&#xff0c;壓棧等&#xff0c;出棧叫做彈棧…

【springboot】IDEA手動創建SpringBoot簡單工程(無插件)

大致步驟 創建Maven工程 引入依賴 提供啟動類 詳細教程 創建Maven工程 修改pom.xml文件 添加父節點 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.3</…

獨立開發第二周:構建、執行、規劃

一 第二周的獨立開發旅程落下帷幕。相較于第一周的適應&#xff0c;本周的核心詞是“聚焦”與“執行”。 目標非常明確&#xff1a;在產品開發上取得進展&#xff1b;在個人工作節奏上&#xff0c;將上周初步形成的框架進行實踐與固化。 同時&#xff0c;為至關重要的自媒體運營…

在YOLO-World中集成DeformConv、CBAM和Cross-Modal Attention模塊的技術報告

在YOLO-World中集成DeformConv、CBAM和Cross-Modal Attention模塊的技術報告 1. 引言 1.1 項目背景 目標檢測是計算機視覺領域的核心任務之一,而YOLO(You Only Look Once)系列算法因其出色的速度和精度平衡而廣受歡迎。YOLO-World是YOLO系列的最新發展,專注于開放詞匯目標…

從UI設計到數字孿生實戰應用:構建智慧金融的風險評估與預警平臺

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;傳統金融風控的 “滯后困境” 與數字孿生的破局之道金融風險的隱蔽性、突…

【Linux】權限相關指令

前言&#xff1a; 上兩篇文章我們講到了&#xff0c;關于Linux中的基礎指令。 【Linux】初見&#xff0c;基礎指令-CSDN博客【Linux】初見&#xff0c;基礎指令&#xff08;續&#xff09;-CSDN博客 本文我們來講Linux中關于權限中的一些指令 shell命令 Linux嚴格來說是一個操…

前端學習3--position定位(relative+absolute+sticky)

繼上一篇&#xff0c;做下拉菜單的時候&#xff0c;涉及到了position&#xff0c;這篇就來學習下~先看下position在下拉菜單中的應用&#xff1a;一、關鍵代碼回顧&#xff1a;/* 下拉菜單容器 */ .dropdown {position: relative; /* ? 關鍵父級 */ }/* 下拉內容&#xff08;默…

APP Inventor使用指南

APP Inventor使用指南一、組件介紹二、邏輯設計設計方法&#xff1a;設計實例&#xff08;參考嘉立創教程&#xff09;點擊跳轉 &#xff1a; app inventor&#xff08;點不開的話需要&#x1fa84;&#x1fa84;&#x1fa84;&#x1fa84;&#x1fa84;&#xff09; 一、組…

SpringAI實現保存聊天記錄到redis中

redis相關準備添加依賴我利用redission來實現<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.37.0</version> </dependency>添加配置文件spring:redis:database: 5host: 127.0.0.1…

Unity中使用EzySlice實現模型切割與UV控制完全指南

引言 在Unity中實現3D模型的動態切割是一個常見的需求&#xff0c;無論是用于游戲特效、建筑可視化還是醫療模擬。本文將全面介紹如何使用EzySlice插件實現高效的模型切割&#xff0c;并深入探討如何通過Shader Graph精確控制切割面的UV映射。 第一部分&#xff1a;EzySlice基…

【c++學習記錄】狀態模式,實現一個登陸功能

狀態模式建議為對象的所有可能狀態新建一個類&#xff0c; 然后將所有狀態的對應行為抽取到這些類中。 原始對象被稱為上下文 &#xff08;context&#xff09;&#xff0c; 它并不會自行實現所有行為&#xff0c; 而是會保存一個指向表示當前狀態的狀態對象的引用&#xff0c;…

Docker 搭建 Harbor 私有倉庫

1 部署 Harbor 注意&#xff1a;docker、docker-compose、Harbor的版本是否適配&#xff0c;這里使用的版本如下表&#xff1a; Docker版本Docker Compose版本Harbor版本v19.09.8v1.29.2v2.8.2 1.1 安裝 docker-compose # 下載 docker-compose 1.29.2 版本 curl -L "h…

C++類模板繼承部分知識及測試代碼

目錄 0.前言 1.類模板基本使用 2.類模板繼承 2.1類模板繼承過程中的模板參數 情況1&#xff1a;父類非模板&#xff0c;子類為模板 情況2&#xff1a;父類模板&#xff0c;子類為非模板 情況3&#xff1a;父類模板&#xff0c;子類為模板 3.STL中的模板類分析 3.1STL中…

Laravel + Python 圖片水印系統:實現與調試指南

前言 本系統通過 Laravel 作為前端框架接收用戶上傳的圖片&#xff0c;調用 Python 腳本處理水印添加&#xff0c;最終返回處理后的圖片。這種架構充分利用了 Laravel 的便捷性和 Python 圖像處理庫的強大功能。 一、Python 水印處理腳本 from PIL import Image, ImageEnhance …

【速通RAG實戰:企業應用】25、從數智化場景看RAG:是臨時方案,還是終局架構?

引言&#xff1a;RAG為何成為數智化場景的"必爭之地"&#xff1f; 當ChatGPT在2023年掀起生成式AI浪潮時&#xff0c;一個矛盾逐漸凸顯&#xff1a;大語言模型&#xff08;LLM&#xff09;能生成流暢文本&#xff0c;卻常陷入"幻覺"&#xff08;虛構事實&a…