C語言版掃雷小游戲
本文實例為大家分享了C語言版掃雷小游戲的具體代碼,供大家參考,具體內(nèi)容如下
一、游戲功能
1、顯示該點周圍雷的個數(shù)
2、第一次下子,不炸死
3、坐標周圍沒雷,可以實現(xiàn)展開
二、效果展示
三、設(shè)計思路
這里由于博主目前能力有限,所以這里就用輸入坐標的形式來進行排雷。
要想實現(xiàn)上方游戲功能其實也不難,總體思路就是:我們用幾個算法模塊來模擬游戲規(guī)則,實現(xiàn)上方的功能,然后用函數(shù)來調(diào)用各個模塊使游戲跑起來。
接下來我們就來看看如何用C語言代碼來實現(xiàn)游戲吧!
四、游戲?qū)崿F(xiàn)步驟
1、游戲菜單
首先我們需要打印一份游戲菜單界面,讓玩家進行選擇是否開始游戲,這里我們使用do…while循環(huán)語句,使的玩家不至于玩玩一次之后直接退出。
主函數(shù)部分:
int main() { int input = 0; do { menu();//打印菜單的函數(shù) printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: printf("開始游戲\n"); game();//游戲主體 break; case 2: system("cls");//清屏選項 break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯誤,請重新選擇\n"); Sleep(1000);//1000毫秒--一秒 system("cls"); break; } } while (input); return 0; }
這里我們用了Windows庫函數(shù)清屏,如果屏幕上顯示的東西太多了,我們可以選擇2來清屏,還有一個睡眠函數(shù),如果輸出錯誤會短暫的提示你一秒,告訴你選擇錯誤了,然后清屏。
菜單函數(shù):
void menu() { printf("**************************************************\n"); printf("******* Welcome to Minesweeper *******\n"); printf("********** 1. 開始游戲 **********\n"); printf("********** 2. 清空屏幕 **********\n"); printf("********** 0. 退出游戲 **********\n"); printf("**************************************************\n"); }
效果如圖:
2、創(chuàng)建初始化棋盤
我們在游戲菜單顯示出來后,就可以進行選擇開始游戲啦!
想玩掃雷就必須得有一個棋盤,這樣我們就可以在上面進行排雷。
在這里我們需要用二維數(shù)組來創(chuàng)建兩個棋盤,一個用于展示給玩家,并儲存排雷信息;一個用于在后臺隨機生成雷并儲存。假如我們要打印9X9的棋盤,那我們的二維數(shù)組大小也是9X9的嗎?,不能,因為我們在設(shè)計算法時需要統(tǒng)計該坐標周圍8個方位雷的個數(shù),假如要統(tǒng)計邊界坐標周圍雷的個數(shù),那么就會有數(shù)組越界的問題,那我們就要在9X9的邊界多上一圈元素,也就要定義11X11的數(shù)組元素,這些多出來的一圈元素我們在打印棋盤的時候進行限制不要打印出來就行,如下圖:
創(chuàng)建棋盤:
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 char mine[ROWS][COLS] = { 0 };//存放雷的信息 char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
在創(chuàng)建完棋盤后,我們就要對兩個棋盤進行初始化:
1、對于存放布置雷的棋盤我們用 字符 ' 1 ' 表示雷,用字符 ‘ 0 ' 表示非雷,這里我們首先全部初始化為非雷,雷的排布我們在布雷的地方講。
2、對于展示給玩家,并儲存排雷信息的棋盤我們用 ‘ * ' 來初始化。
初始化棋盤函數(shù):
InitBoard(mine, ROWS,COLS,'0'); InitBoard(show, ROWS,COLS,'*');
函數(shù)的定義:
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) { int i = 0; for (i = 0; i < rows; i++) { int j = 0; for (j = 0; j < cols; j++) { board[i][j] = set; } } }
3、布雷
我們將棋盤初始化完后,我們就要進行布雷的操作了。
雷的分布位置:我們在玩掃雷時知道,每次雷的分布的位置是不一樣的,是隨機分布的,所以我們在布雷操作的時候要調(diào)用隨機函數(shù)rand(),在使用隨機函數(shù)之前,我們要先在主函數(shù)中使用srand()函數(shù)生成隨機起點,這樣就可以保證每次雷的位置不一樣了。關(guān)于這兩個函數(shù)的使用,可以去MSDN或者cplusplus中去查詢其作用。
然后就是雷的個數(shù):每次分布一個就減少一個。
接著就是布雷的范圍:因為我們玩家進行排雷是在9X9的棋盤內(nèi)進行的,所以我們需限定布雷的范圍也在9X9的范圍內(nèi)。
接下來我們來看看到底如何實現(xiàn)的吧!
主函數(shù):
int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu();//打印菜單 printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: game();//游戲主體 break; case 2: system("cls");//清屏選項 break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯誤,請重新選擇\n"); Sleep(1000); system("cls"); break; } } while (input); return 0; }
布雷函數(shù):
#define EASY_COUNT 10 //雷的個數(shù) SetMine(mine, ROW, COL);
函數(shù)的定義:
void SetMine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = EASY_COUNT;//雷的個數(shù) while (count) { //生成隨機下標(1~9) x = rand() % row + 1; y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count--; } } }
4、打印棋盤
我們將上方操作完成之后,就需要在屏幕上打印出棋盤了,但這里一共有兩個棋盤,我們需要打印的棋盤是專門展示給玩家,并儲存排雷信息的棋盤即用 ‘ * ' 初始化的棋盤。
還有就是我們需打印的大小是9X9的范圍,而不是全部范圍11X11的。
還有我們需要打印棋盤的行數(shù)和列數(shù),以便玩家看坐標。
打印棋盤函數(shù):
DisplayBoard(show, ROW, COL);
函數(shù)定義:
void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; printf("----------------\n"); for (i = 0; i <= 9; i++) { printf("%d ", i);//打印列標 } printf("\n"); for (i = 1; i <= row; i++) { int j = 0; printf("%d ", i);//打印行標 for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("----------------\n"); }
5、排雷
完成上方所有操作后,就到我們最精彩,也是最重要的部分了。
要求:
1、輸入排查坐標要在打印的棋盤范圍內(nèi);
2、統(tǒng)計排查坐標周邊八個位置的雷的個數(shù);
3、保證第一次輸入坐標絕對安全,不炸死;
4、坐標周圍無雷則進行自動展開
排雷主邏輯函數(shù):
FindMine(mine, show, ROW, COL);
統(tǒng)計排查坐標周邊八個位置的雷的個數(shù)的函數(shù):
GetMineCount(char mine[ROWS][COLS], int x, int y)
第一次安全函數(shù):
safe(char mine[ROWS][COLS], int row,int col,int x, int y)
展開函數(shù)
OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
函數(shù)定義(從上往下):
排雷主邏輯函數(shù):
//主邏輯函數(shù) void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0;//統(tǒng)計排雷的個數(shù) int count = 0;// 統(tǒng)計雷的個數(shù) while (win<row*col-EASY_COUNT) { printf("請輸入要排查的坐標"); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) //輸入坐標是否合法 { if (mine[x][y] == '1') { if (0 == win)//第一次踩到雷,重新布雷 { safe(mine, ROW,COL,x, y); //DisplayBoard(mine, ROW, COL); count = GetMineCount(mine, x, y); if (count == 0) { show[x][y] = ' '; win++; OpenMine(mine, show, ROW, COL, x, y,&win);//如果周圍沒有雷,進行擴展 DisplayBoard(show, row, col); } else { show[x][y] = count + '0'; DisplayBoard(show, row, col); } } else { printf("很遺憾,你被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } } else { count = GetMineCount(mine, x, y); if (count == 0) { show[x][y] = ' '; } else { show[x][y] = count + '0'; } win++; OpenMine(mine, show, ROW, COL, x, y,&win); DisplayBoard(show, ROW, COL); } } else { printf("坐標不在范圍內(nèi),請重新輸入\n"); } } if (win == row*col - EASY_COUNT) { printf("恭喜你,排雷成功\n"); } }
統(tǒng)計周圍雷的個數(shù):
//統(tǒng)計排查坐標周邊八個位置的雷的個數(shù) int GetMineCount(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0'); }
第一次下子,不炸死,則重新布雷:
//第一次安全 void safe(char mine[ROWS][COLS], int row,int col,int x, int y) { mine[x][y] = '0'; int count = 1; while (count) { //生成隨機下標(1~9) int i = rand() % row + 1; int j = rand() % col + 1; if ((mine[i][j] != '1') && i != x && j != y) { mine[i][j] = '1'; count--; } } }
坐標周圍沒雷,可以實現(xiàn)展開:
//展開函數(shù) void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int* p) { int i = -1; int j = -1; for (i = -1; i < 2; i++)//邊界 { for (j = -1; j < 2; j++) { if (i != 0 || j != 0) // 避免排到自己注意此處的邏輯關(guān)系 { if (x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col) { if (show[x + i][y + j] == '*' && mine[x + i][y + j] != '1') { int count = GetMineCount(mine, x + i, y + j); if (count != '0') { show[x + i][y + j] = count + '0'; (*p)++; } else { show[x + i][y + j] = ' '; (*p)++; OpenMine(mine, show,ROW,COL, x + i, y + j, p); } } } } } } }
五、總結(jié)
和三子棋一樣,將整個工程分為game.c,game.h和test.c三個文件。如下圖
1、在頭文件game.h主要包括各個函數(shù)的聲明還有調(diào)用庫函數(shù)所需的頭文件以及棋盤行數(shù)列數(shù)的宏定義,方便以后我們?nèi)绻胄薷男谢蛘吡袛?shù)目,直接修改宏定義的內(nèi)容即可。
2、源文件game.c中則包括各種函數(shù)的實現(xiàn),該文件中要引用頭文件game.h
3、test.c中則包括游戲開始菜單的打印和調(diào)用game.c中的函數(shù)
game.h內(nèi)容
#pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #include<Windows.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 //雷的個數(shù) #define EASY_COUNT 10 //初始化棋盤 void InitBoard(char board[ROWS][COLS], int rows, int cols,char set); //布置雷 void SetMine(char board[ROWS][COLS], int row, int col); //打印棋盤 void DisplayBoard(char board[ROWS][COLS], int row, int col); //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //第一次安全 void safe(char mine[ROWS][COLS], int row, int col, int x, int y); //統(tǒng)計排查坐標周邊八個位置的雷的個數(shù) int GetMineCount(char mine[ROWS][COLS], int x, int y); //坐標周圍展開函數(shù) void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int* p);
game.c內(nèi)容
#include "game.h" //初始化棋盤 void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) { int i = 0; for (i = 0; i < rows; i++) { int j = 0; for (j = 0; j < cols; j++) { board[i][j] = set; } } } //布置雷 void SetMine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = EASY_COUNT; while (count) { //生成隨機下標(1~9) x = rand() % row + 1; y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count--; } } } //打印棋盤 void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; printf("----------------\n"); for (i = 0; i <= 9; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { int j = 0; printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("----------------\n"); } //排雷主邏輯 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0;//統(tǒng)計排雷的個數(shù) int count = 0;// 統(tǒng)計雷的個數(shù) while (win<row*col-EASY_COUNT) { printf("請輸入要排查的坐標"); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) //輸入坐標是否合法 { if (mine[x][y] == '1') { if (0 == win)//第一次踩到雷,重新布雷 { safe(mine, ROW,COL,x, y); //DisplayBoard(mine, ROW, COL); count = GetMineCount(mine, x, y); if (count == 0) { show[x][y] = ' '; win++; OpenMine(mine, show, ROW, COL, x, y,&win);//如果周圍沒有雷,進行擴展 DisplayBoard(show, row, col); } else { show[x][y] = count + '0'; DisplayBoard(show, row, col); } } else { printf("很遺憾,你被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } } else { count = GetMineCount(mine, x, y); if (count == 0) { show[x][y] = ' '; } else { show[x][y] = count + '0'; } win++; OpenMine(mine, show, ROW, COL, x, y,&win); DisplayBoard(show, ROW, COL); } } else { printf("坐標不在范圍內(nèi),請重新輸入\n"); } } if (win == row*col - EASY_COUNT) { printf("恭喜你,排雷成功\n"); } } //統(tǒng)計排查坐標周邊八個位置的雷的個數(shù) int GetMineCount(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0'); } //保證第一次下子安全 void safe(char mine[ROWS][COLS], int row,int col,int x, int y) { mine[x][y] = '0'; int count = 1; while (count) { //生成隨機下標(1~9) int i = rand() % row + 1; int j = rand() % col + 1; if ((mine[i][j] != '1') && i != x && j != y) { mine[i][j] = '1'; count--; } } } //展開函數(shù) void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int* p) { int i = -1; int j = -1; for (i = -1; i < 2; i++)//邊界 { for (j = -1; j < 2; j++) { if (i != 0 || j != 0) // 避免排到自己注意此處的邏輯關(guān)系 { if (x + i >= 1 && x + i <= row && y + j >= 1 && y + j <= col) { if (show[x + i][y + j] == '*' && mine[x + i][y + j] != '1') { int count = GetMineCount(mine, x + i, y + j); if (count != '0') { show[x + i][y + j] = count + '0'; (*p)++; } else { show[x + i][y + j] = ' '; (*p)++; OpenMine(mine, show,ROW,COL, x + i, y + j, p); } } } } } } }
test.c內(nèi)容
#include "game.h" void menu() { printf("**************************************************\n"); printf("******* Welcome to Minesweeper *******\n"); printf("********** 1. 開始游戲 **********\n"); printf("********** 2. 清空屏幕 **********\n"); printf("********** 0. 退出游戲 **********\n"); printf("**************************************************\n"); } void game() { char mine[ROWS][COLS] = { 0 };//存放雷的信息 char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息 //初始化一下棋盤 InitBoard(mine, ROWS,COLS,'0'); InitBoard(show, ROWS,COLS,'*'); //布置雷 SetMine(mine, ROW, COL); //打印棋盤 //DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); //排查雷 FindMine(mine, show, ROW, COL); } int main() { int input = 0; srand((unsigned int)time(NULL)); do { menu();//打印菜單 printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: game();游戲主體 break; case 2: system("cls");//清屏選項 break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯誤,請重新選擇\n"); Sleep(1000); system("cls"); break; } } while (input); return 0; }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++ 數(shù)據(jù)結(jié)構(gòu)二叉樹(前序/中序/后序遞歸、非遞歸遍歷)
這篇文章主要介紹了C++ 數(shù)據(jù)結(jié)構(gòu)二叉樹(前序/中序/后序遞歸、非遞歸遍歷)的相關(guān)資料,這里提供實例代碼來幫助大家理解掌握二叉樹,需要的朋友可以參考下2017-07-07