C 語 言 --- 掃 雷 游 戲 初 階 版
- 代 碼 全 貌 與 功 能 介 紹
- 掃雷游戲的功能說明
- 游 戲 效 果 展 示
- 游 戲 代 碼 詳 解
- game.h
- test.c
- game.c
- 總結
💻作 者 簡 介:曾 與 你 一 樣 迷 茫,現 以 經 驗 助 你 入 門 C 語 言
💡個 人 主 頁:@笑口常開xpr 的 個 人 主 頁
📚系 列 專 欄:C 啟新程
?代 碼 趣 語:每 個 人 都 應 該 學 習 編 程,因 為 它 教 會 你 如 何 思 考。
💪代 碼 千 行,始 于 堅 持,每 日 敲 碼,進 階 編 程 之 路。
📦gitee 鏈 接:gitee
???????在 編 程 的 世 界 里,每 一 行 代 碼 都 可 能 隱 藏 著 無 限 的 可 能 性 。你 是 否 想 過,一 個 小 小 的 程 序 究 竟 能 改 變 什 么?它 可 以 是 解 決 復 雜 問 題 的 工 具 ,也 可 以 是 實 現 夢 想 的 橋 梁。今 天,就 讓 我 們 一 起 走 進 C 語 言 掃 雷 的 世 界,探 索 它 的 無 限 潛 力。
網頁版掃雷游戲
代 碼 全 貌 與 功 能 介 紹
?????????整 個 游 戲 項 目 由 三 個 主 要 文 件 構 成:game.h、test.c 和 game.c。這 種 多 文 件 的 架 構 設 計,有 助 于 將 不 同 功 能 模 塊 分 離,提 高 代 碼 的 可 讀 性、可 維 護 性 與 可 擴 展 性 。
game.h
game.h 包 含 了 游 戲 所 需 的 頭 文 件 引 用、常 量 定 義 以 及 函 數 聲 明。
test.c:
test.c 是游戲的主邏輯文件,負責處理用戶輸入和游戲流程的控制;
game.c
game.c 則實現了游戲的具體功能函數。
下 面 展 示
完整代碼
。
讀 者 可 以 將 這 段 代 碼 復 制 到 自 己 的 編 譯 器 中 運 行:
game.h
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2//雷的數量
#define EASY_COUNT 10//實現掃雷游戲中的函數聲明
//初始化棋盤
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盤
void DisPlayBoard(char board[ROWS][COLS], int row, int col);//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);//排查雷
void FindMine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
test.c
#include "game.h"
void menu()
{printf("**********************************\n");printf("********** 1.play *********\n");printf("********** 0.exit *********\n");printf("**********************************\n");
}void game()
{//需要存放布置雷的信息,需要存放排查出的雷的信息 -- 需要2個二維數組//排查時,防止坐標越界,要給數組行,列各加2char mine[ROWS][COLS] = { 0 };//布置好的雷的信息char show[ROWS][COLS] = { 0 };//排查出的雷的信息//1.初始化棋盤InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//2.打印棋盤//DisPlayBoard(mine, ROW, COL);DisPlayBoard(show, ROW, COL);//3.布置雷SetMine(mine, ROW, COL);//DisPlayBoard(mine, ROW, COL);//4.排查雷FindMine(mine, show, ROW, COL);
}
void test()
{srand((unsigned int)time(NULL));int input = 0;do{ //打印菜單menu();printf("請選擇:>");scanf("%d", &input);switch (input){case 1:printf("掃雷游戲\n");//實現掃雷游戲的邏輯game();break;case 0:printf("退出游戲\n");break;default:printf("選擇錯誤,請重新選擇\n");break;}} while (input);
}
int main()
{//實現游戲的主邏輯test();return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h"void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}
}
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;printf("----------掃雷----------\n");for (i = 0; i <= col; i++){if (i == 0){printf(" ");continue;}printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("----------掃雷----------\n");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//1.產生隨機的坐標1~9int x = rand() % row + 1;int y = rand() % col + 1;//2.在坐標中放置雷if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]+ mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;while (win < (row * col - EASY_COUNT)){printf("請輸入要排查的坐標:> ");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] != '*'){printf("該坐標被排查過了\n");continue;}if (mine[x][y] == '1'){printf("很遺憾,你被炸死了\n");DisPlayBoard(mine, ROW, COL);break;}else{//統計一下坐標int n = get_mine_count(mine, x, y);show[x][y] = n + '0';DisPlayBoard(show, ROW, COL);win++;}}else{printf("坐標非法,請重新輸入\n");}}if (win == (row * col - EASY_COUNT)){printf("恭喜你,排雷成功\n");DisPlayBoard(mine, ROW, COL);}
}
掃雷游戲的功能說明
- 使 用 控 制 臺 實 現 經 典 的 掃 雷 游 戲
- 游 戲 可 以 通 過 菜 單 實 現 繼 續 玩 或 者 退 出 游 戲
- 掃 雷 的 棋 盤 是 9 * 9 的 格 子
默 認 隨 機 布 置 10 個 雷- 可 以 排 查 雷
如 果 位 置 不 是 雷,就 顯 示 周 圍 有 幾 個 雷
如 果 位 置 是 雷,就 炸 死 游 戲 結 束
把 除 10 個 雷 之 外 的 所 有 非 雷 都 找 出 來,排 雷 成 功,游 戲 結 束
游 戲 效 果 展 示
游 戲 啟 動 后,玩 家 看 到 簡 潔 的 主 菜 單,選 擇 1 開 始 游 戲,反 之,選 擇 0 退 出 游 戲。
此 時,空 棋 盤 呈 現 眼 前,9 × 9 的 棋 盤 格 等 待 著 玩 家 進 行 排 查 雷。
?????????玩 家 輸 入 下 棋 坐 標 后,程 序 會 驗 證 坐 標 合 法 性。若 坐 標 合 法 且 對 應 位 置 沒 有 雷,將 會 顯 示 棋 盤 等 待 玩 家 下 一 次 排 查 雷;如 果 坐 標 是 雷,玩 家 會 收 到 “ 很 遺 憾 ,你 被 炸 死 了 ” 的 提 示; 若 坐 標 不 合 法 ,玩 家 會 收 到 “ 坐 標 非 法 ” 或 “ 該 坐 標 被 排 查 過 了” 的 提 示,需 重 新 輸 入 坐 標。
?????????玩 家 不 斷 根 據 游 戲 規 則 排 查 雷 直 到 雷 全 部 排 查 完 ,在 這 個 過 程 中,程 序 不 斷 檢 查 玩 家 輸 入 的 坐 標 是 否 是 雷 以 及 雷 是 否 全 部 排 查 完。若 玩 家 把 雷 全 部 排 查 完,程 序 立 即 宣 告 “ 恭 喜 你,排 雷 成 功 ”,游 戲 結 束。
游 戲 代 碼 詳 解
game.h
#pragma once
防 止 重 復 包 含
?????????#pragma once 指 令 確 保 這 個 頭 文 件 在 整 個 項 目 中 只 會 被 包 含 一 次。在 大 型 項 目 中,若 多 個 源 文 件 包 含 同 一 個 頭 文 件,若 不 加 以 限 制,頭 文 件 中 的 內 容 會 被 重 復 編 譯,導 致 錯 誤。使 用 此 指 令 可 避 免 這 種 情 況。
#include <stdio.h>?
#include <stdlib.h>
引 入 標 準 庫
?????????#include <stdio.h> 引 入 標 準 輸 入 輸 出 庫,使 得 代 碼 能 夠 使 用 如 printf(用 于 輸 出 信 息)和 scanf( 用 于 獲 取 用 戶 輸 入)等 函 數。#include <stdlib.h> 引 入 標 準 庫,為 rand 函 數( 隨 機 布 置 雷 時 用 到 )等 提 供 支 持。
#define ROW 9
#define COL 9#define ROWS ROW + 2
#define COLS COL + 2//雷的數量
#define EASY_COUNT 10
常 量 定 義:
?????????定 義 了 游 戲 棋 盤 的 大 小 ROW 和 COL 為 9,為 了 防 止 排 查 雷 時 數 組 越 界,定 義 了 ROWS 和 COLS 為 ROW + 2 和 COL + 2。同 時,還 定 義 了 初 級 難 度 下 雷 的 數 量 EASY_COUNT 為 10。
//實現掃雷游戲中的函數聲明
//初始化棋盤
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盤
void DisPlayBoard(char board[ROWS][COLS], int row, int col);//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);//排查雷
void FindMine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
函 數 聲 明:
?????????聲 明 了 四 個 關 鍵 函 數,分 別 是 初 始 化 棋 盤 函 數 InitBoard、打 印 棋 盤 函 數 DisPlayBoard、布 置 雷 函 數 SetMine 和 排 查 雷 函 數 FindMine。
test.c
#define _CRT_SECURE_NO_WARNINGS 1
消 除 安 全 警 告
?????????用 于 消 除 因 使 用 了 一 些 不 安 全 的 函 數( 如 scanf)而 產 生 的 編 譯 警 告。在 較 新 的 編 譯 器 中,為 了 安 全 考 慮,對 一 些 函 數 的 使 用 會 給 出 警 告 , 通 過 定 義 這 個 宏 可 屏 蔽 這 些 警 告。
void menu()?
{?printf("*******************************\n");?printf("************ 1.play *********\n");?printf("************ 0.exit *********\n");?printf("*******************************\n");?
}?
menu 函 數:
?????????menu 函 數 用 于 打 印 游 戲 主 菜 單。通 過 printf 函 數 輸 出 一 個 包 含“ 1.play ”(開 始 游 戲)和 “0.exit”( 退 出 游 戲 )選 項 的 菜 單,為 玩 家 提 供 操 作 選 擇 界 面。
void game()
{//需要存放布置雷的信息,需要存放排查出的雷的信息 -- 需要2個二維數組//排查時,防止坐標越界,要給數組行,列各加2char mine[ROWS][COLS] = { 0 };//布置好的雷的信息char show[ROWS][COLS] = { 0 };//排查出的雷的信息//1.初始化棋盤InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//2.打印棋盤//DisPlayBoard(mine, ROW, COL);DisPlayBoard(show, ROW, COL);//3.布置雷SetMine(mine, ROW, COL);//DisPlayBoard(mine, ROW, COL);//4.排查雷FindMine(mine, show, ROW, COL);
}?
game 函 數:
?????????game 函 數 按 照 游 戲 的 邏 輯 順 序,依 次 完 成 了 棋 盤 初 始 化、顯 示 初 始 棋 盤、布 置 雷 以 及 讓 玩 家 進 行 掃 雷 操 作 等 關 鍵 步 驟,是 實 現 整 個 掃 雷 游 戲 功 能 的 核 心 函 數。
void test()
{srand((unsigned int)time(NULL));int input = 0;do{ //打印菜單menu();printf("請選擇:>");scanf("%d", &input);switch (input){case 1:printf("掃雷游戲\n");//實現掃雷游戲的邏輯game();break;case 0:printf("退出游戲\n");break;default:printf("選擇錯誤,請重新選擇\n");break;}} while (input);
}?
test 函 數:
?????????test 函 數 通 過 srand 初 始 化 隨 機 數 種 子,然 后 進 入 一 個 循 環,顯 示 游 戲 菜 單,根 據 用 戶 輸 入 選 擇 開 始 游 戲 或 退 出 游 戲。選 擇 開 始 游 戲 時 調 用 game 函 數,game 函 數 依 次 調 用 上 述 功 能 函 數 來 完 成 游 戲 的 初 始 化、布 置 雷 和 排 查 雷 等 操 作。
int main()?
{?test();?return 0;?
}
main 函 數:
main 函 數 作 為 程 序 入 口,調 用 test() 函 數 啟 動 游 戲 流 程,最 后 return 0; 表 示 程 序 正 常 結 束 。
game.c
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}
}
初 始 化 棋 盤( InitBoard 函 數 ):
?????????該 函 數 接 受 棋 盤 數 組、行 數、列 數 和 初 始 化 字 符 作 為 參 數,通 過 兩 層 循 環 將 棋 盤 數 組 的 每 個 元 素 初 始 化 為 指 定 字 符。
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;printf("----------掃雷----------\n");for (i = 0; i <= col; i++){if (i == 0){printf(" ");continue;}printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("----------掃雷----------\n");
}
打 印 棋 盤( DisPlayBoard 函 數 ):
?????????此 函 數 用 于 在 控 制 臺 打 印 棋 盤。先 打 印 棋 盤 的 表 頭( 列 號 ),然 后 逐 行 打 印 棋 盤 的 內 容,包 括 行 號 和 每 個 格 子 的 字 符。
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//1.產生隨機的坐標1~9int x = rand() % row + 1;int y = rand() % col + 1;//2.在坐標中放置雷if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}?
布 置 雷( SetMine 函 數 ):
?????????該 函 數 通 過 隨 機 生 成 坐 標,并 在 相 應 位 置 放 置 雷( 將 字 符 設 置 為 ‘1’),直 到 雷 的 數 量 達 到 EASY_COUNT。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;while (win < (row * col - EASY_COUNT)){printf("請輸入要排查的坐標:> ");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] != '*'){printf("該坐標被排查過了\n");continue;}if (mine[x][y] == '1'){printf("很遺憾,你被炸死了\n");DisPlayBoard(mine, ROW, COL);break;}else{//統計一下坐標int n = get_mine_count(mine, x, y);show[x][y] = n + '0';DisPlayBoard(show, ROW, COL);win++;}}else{printf("坐標非法,請重新輸入\n");}}if (win == (row * col - EASY_COUNT)){printf("恭喜你,排雷成功\n");DisPlayBoard(mine, ROW, COL);}
}
排 查 雷( FindMine 函 數 ):
?????????玩 家 輸 入 坐 標 后,函 數 會 檢 查 坐 標 的 合 法 性 和 是 否 已 被 排 查 過 。如 果 坐 標 合 法 且 未 被 排 查,判 斷 該 位 置 是 否 為 雷,若 是 則 游 戲 失 敗,否 則 統 計 周 圍 雷 的 數 量 并 顯 示 在 顯 示 棋 盤 上,直 到 所 有 非 雷 格 子 都 被 排 查 出 來 則 游 戲 勝 利。
總結
???????通 過 這 個 簡 單 的 掃 雷 游 戲,我 們 不 僅 實 踐 了 C 語 言 中 的 基 本 語 法,如 變 量 定 義、循 環 結 構、條 件 判 斷 和 函 數 調 用,還 學 習 了 如 何 使 用 隨 機 數 生 成 函 數 和 輸 入 輸 出 函 數。希 望 這 篇 博 客 能 幫 助 你 更 好 地 理 解 C 語 言 編 程,激 發 你 在 編 程 世 界 中 不 斷 探 索 和 創 新 的 熱 情 。