目錄
主函數(shù)test.c
菜單函數(shù)
選擇循環(huán)
掃雷游戲?qū)崿F(xiàn)分析
整體思路?
問題1
問題2?
問題3
問題4?
游戲函數(shù)(函數(shù)調(diào)用)?
創(chuàng)建游戲盤數(shù)組mine
創(chuàng)建游戲盤數(shù)組show
初始化游戲盤數(shù)組InitBoard
展示游戲盤DisplayBoard
游戲盤置雷SetMine
游戲盤排雷FindMine
test.c總代碼
頭文件&函數(shù)聲明game.h
頭文件的包含
游戲符號聲明
游戲函數(shù)聲明
game.h總代碼
游戲函數(shù)game.c
初始化游戲盤InitBoard
展示游戲盤DisplayBoard
優(yōu)化1
優(yōu)化2
游戲盤置雷SetMine
游戲盤排雷FindMine
排查過的位置
未排查過的位置
雷炸死??
非雷計算
找完雷
總循環(huán)
game.c總代碼
今天我們接著來講掃雷游戲的實現(xiàn)。????
主函數(shù)test.c
菜單函數(shù)
void menu()
{
printf("*******************\n");
printf("*******Play.1******\n");
printf("*******Over.2******\n");
printf("*******************\n");
}
選擇循環(huán)
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*******************\n");
printf("*******Play.1******\n");
printf("*******Over.2******\n");
printf("*******************\n");
}
void game()
{
printf("開始掃雷游戲\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
printf("歡迎來到掃雷游戲!\n");
menu();
printf("請輸入您的選擇:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戲結(jié)束\n");
break;
default:
printf("輸入選擇有誤,請重新選擇\n");
break;
}
} while (input);
}
以上代碼我們已經(jīng)寫過三遍了,相信大家都非常熟悉了,不在過多闡述。?
掃雷游戲?qū)崿F(xiàn)分析
整體思路?
- 首先游戲盤9?9,游戲盤上布置了10個雷
- 如果游戲盤的某處坐標不是雷,就計算這個位置的周圍3?3的8個坐標有幾個雷且顯示雷個數(shù)
- 如果游戲盤的某處坐標是雷,就炸死了,顯示游戲結(jié)束
- 如果把游戲盤上所有非雷的位置全部找出來了,顯示排雷成功,游戲結(jié)束。?
- 兩個完全貼合的字符數(shù)組游戲盤
問題1
我們用字符'0'表示非雷,'1'表示是雷。
但是格子里還要顯示周圍3?3的各自雷的個數(shù),數(shù)字1與字符'1'會容易搞混,怎么辦?
?所以我們需要兩個游戲盤
- mine游戲盤。游戲盤初始化為字符'0'和'1'。隨機循環(huán)的布置10個雷的位置。玩家在掃雷的時候計算雷的個數(shù)。
- show游戲盤。游戲盤的展示。游戲盤初始化為字符'*'。玩家掃雷的時候顯示周圍3?3的8個坐標的雷的個數(shù)。
- 特別提醒:二者必須完全無縫貼合????
問題2?
剛剛我們提到mine游戲盤是掃雷時計算某個坐標的周圍3?3的8個坐標的雷的個數(shù),那如果時周圍的坐標該怎么辦,如果計算,已經(jīng)數(shù)組越界了????
?
所以我們要拓展我們的游戲盤,我們創(chuàng)建一個11?11的游戲盤,但我們只訪問9?9的游戲盤
特別提醒:為了我們的便捷的實現(xiàn)我們的掃雷游戲,我們的兩個游戲盤必須無縫貼合,所以我們的show顯示游戲盤也要拓展到11?11。?
問題3
我們掃雷游戲的實現(xiàn)涉及初始化,游戲盤的展示等都需要用到循環(huán) ,那循環(huán)條件條件的控制?
特別提醒:
特別需要注意循環(huán)條件,數(shù)組的下標是從0開始。
初始化數(shù)組就是0~10
訪問數(shù)組就是1~9?
問題4?
當玩家輸入坐標,沒有輸入雷被炸死,這時我們需要顯示雷的坐標,那怎樣去計算雷的個數(shù)?
?游戲盤數(shù)組mine和show都初始化為字符?,F(xiàn)在我們要將字符轉(zhuǎn)化為數(shù)字。
?根據(jù)字符和數(shù)字的ASCII碼值。我們知道'0'數(shù)值為48,'1'數(shù)值為49。
?所以我們知道?'1'-'0'=1? ?'0'-'0'=0
?所以我們可以將(x,y)周圍8個字符坐標分別減去'0'可以得到數(shù)字,再全加到一起得總數(shù)字。
?或者我們也可以先將(x,y)周圍8個坐標字符坐標 加到一起,再一起減去8*'0'得到總數(shù)字。
游戲函數(shù)(函數(shù)調(diào)用)?
創(chuàng)建游戲盤數(shù)組mine
char mine[ROWS][COLS]={0};
創(chuàng)建游戲盤數(shù)組show
char show[ROWS][COLS]={0};
初始化游戲盤數(shù)組InitBoard
- 創(chuàng)建一個InitBoard函數(shù),去分別初始化兩個數(shù)組mine和show
- ?初始化內(nèi)容不一樣,所以把初始化內(nèi)容當作參數(shù)分別傳給函數(shù)InitBoard
- 初始化時傳參時11?11,為了后面計算游戲盤某坐標 周圍8個坐標 里雷的個數(shù)?
InitBoard(mine, ROWS, COLS, '0');//初始化是11?11
InitBoard(show, ROWS, COLS, '*');
展示游戲盤DisplayBoard
- 展示游戲盤,只需要訪問9?9的游戲盤。?
DisplayBoard(mine, ROW, COL);//多余的//訪問是9?9
DisplayBoard(mine, ROW, COL);
游戲盤置雷SetMine
SetMine(mine, ROW, COL);
DisplayBoard(mine, ROW, COL);//多余的
游戲盤排雷FindMine
FindMine(mine, show, ROW, COL);
//傳mine數(shù)組過去計算雷
//傳show數(shù)組展示計算雷的結(jié)果
test.c總代碼
//掃雷游戲的實現(xiàn)
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*******************\n");
printf("*******Play.1******\n");
printf("*******Over.2******\n");
printf("*******************\n");
}
void game()
{
printf("開始掃雷游戲\n");
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
InitBoard(mine, ROWS, COLS, '0');//
InitBoard(show, ROWS, COLS, '*');
//DisplayBoard(mine, ROW, COL);//多余的//訪問是9?9
DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);//多余的
//排除雷——掃雷
FindMine(mine, show, ROW, COL);
//傳mine數(shù)組過去計算雷
//傳show數(shù)組展示計算雷的結(jié)果
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
printf("歡迎來到掃雷游戲!\n");
menu();
printf("請輸入您的選擇:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戲結(jié)束\n");
break;
default:
printf("輸入選擇有誤,請重新選擇\n");
break;
}
} while (input);
}
頭文件&函數(shù)聲明game.h
頭文件的包含
在我們寫代碼的過程中,會調(diào)用庫函數(shù),需要包含頭文件,和聲明函數(shù)。
所以我們將所有函數(shù)聲明和頭文件放到我們.h 文件中。
當然,在其他.c文件需要使用時,我們只需要包含 我們創(chuàng)造的 頭文件"game.h"?即可。?
//#include"game.h"
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
游戲符號聲明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
游戲函數(shù)聲明
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 mine[ROWS][COLS], char show[ROWS][COLS], int row,int col);
//不能board,重復(fù)參數(shù)名
game.h總代碼
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#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 mine[ROWS][COLS], char show[ROWS][COLS], int row,int col);
//不能board,重復(fù)參數(shù)名
游戲函數(shù)game.c
初始化游戲盤InitBoard
- 數(shù)組下標是從0開始的,所以初始化i是0~10?
#include"game.h"
#define _CRT_SECURE_NO_WARNINGS 1
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)//i=0~10
{
for (j = 0; j < cols; j++)//j=0~10
{
board[i][j] = set;
}
}
}
展示游戲盤DisplayBoard
- ?數(shù)組下標是從0開始,所以訪問是0~9
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
當然我們的mine函數(shù)是不會展示的。當玩家輸入坐標時還要去數(shù),所以以上代碼還能不能優(yōu)化??
優(yōu)化1
- 玩家輸入坐標時,還是幾行幾列去尋找,所以我們選擇直接把號碼打印出來。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印列號
for (i = 0; i <= col; i++)//i從0開始,因為行占用了一格
{
printf("%d ", i);
}
printf("\n");
//打印數(shù)字
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印行號
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
優(yōu)化2
- 上下文的文字顯得眼花繚亂,所以我們加上分割線就不會繚亂了。?
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印列號
printf("--------------掃雷--------------\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
//打印數(shù)字
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印行號
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("--------------掃雷--------------\n");
}
優(yōu)化之后?
游戲盤置雷SetMine
- 關(guān)于隨機數(shù)rand,先調(diào)用srand
- 隨機數(shù)rand()%row的范圍0~8
- 隨機數(shù)rand()%row+1的范圍1~9
- 關(guān)于布置雷需要在mine函數(shù)里面去實現(xiàn)
- while循環(huán)的次數(shù)肯定不止EASY_COUNT
void SetMine(char board[ROWS][COLS], int row, int col)
{
//布置雷——循環(huán)隨機數(shù)直到布置完10個雷停止
int count = EASY_COUNT;
while (count)//直到10個雷布置完畢退出循環(huán)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
//產(chǎn)生的坐標就是(0,0)~(9,9)
if (board[x][y] == '0')
//條件設(shè)置,不能重復(fù)計算已經(jīng)設(shè)置過的地方即為1的地方
{
board[x][y] = '1';
count--;
}
}
}
?
游戲盤排雷FindMine
排查過的位置
if(show[x][y] != "*")
{
printf("該坐標被排查過了,請重新輸入坐標\n");
}?
未排查過的位置
雷炸死??
- ?坐標為雷就炸死,游戲結(jié)束
printf("請輸入要查找的雷\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//輸入的坐標要合法
{
if
/
else if(mine[x][y] == '1')//被炸死的條件
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}?
else
//
}
else//玩家輸入非法坐標,重新輸入
{
printf("坐標非法,請重新輸入\n");
}
非雷計算
- ?坐標不為雷,mine計算雷,show展示雷
- ?計算l雷個數(shù)的函數(shù)GetMineCount
//統(tǒng)計雷的個數(shù)
int GetMineCount(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';
}
int win=0;
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if
{
}
else if
//
else//沒有被炸死,顯示雷的個數(shù)
{
//不是雷,就統(tǒng)計x,y坐標周圍有幾個雷
int c = GetMineCount(mine, x, y);
show[x][y] = c + '0';//數(shù)字+'0'=字符數(shù)字放置到字符數(shù)組里去
DisplayBoard(show, ROW, COL);//展示字符數(shù)字——雷的個數(shù),每排查一次都要顯示雷的個數(shù)
win++;//每排查一次雷,雷的個數(shù)減少一次,距離循環(huán)結(jié)束++一次
}?
}
else//玩家輸入非法坐標,重新輸入
{
printf("坐標非法,請重新輸入\n");
}
找完雷
- ?坐標找完雷,游戲結(jié)束
//炸死和排排完雷都跳出循環(huán)
if (win == row * col - EASY_COUNT)//設(shè)置條件只有排完雷才通關(guān)
{
printf("恭喜你排雷成功,游戲通關(guān)\n");
DisplayBoard(mine, ROW, COL);
}
總循環(huán)
int GetMineCount(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("請輸入要查找的雷\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//輸入的坐標要合法
{
if(show[x][y] != "*")
{
printf("該坐標被排查過了,請重新輸入坐標\n");
}
else if (mine[x][y] == '1')//被炸死的條件
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else//沒有被炸死,顯示雷的個數(shù)
{
//不是雷,就統(tǒng)計x,y坐標周圍有幾個雷
int c = GetMineCount(mine, x, y);
show[x][y] = c + '0';//數(shù)字+'0'=字符數(shù)字放置到字符數(shù)組里去
DisplayBoard(show, ROW, COL);//展示字符數(shù)字——雷的個數(shù)
//每排查一次都要顯示雷的個數(shù)
win++;//每排查一次雷,雷的個數(shù)減少一次,距離循環(huán)結(jié)束++一次
}
}
else//玩家輸入非法坐標,重新輸入
{
printf("坐標非法,請重新輸入\n");
}
}
//炸死和排排完雷都跳出循環(huán)
if (win == row * col - EASY_COUNT)//設(shè)置條件只有排完雷才通關(guān)
{
printf("恭喜你排雷成功,游戲通關(guān)\n");
DisplayBoard(mine, ROW, COL);
}
}
game.c總代碼
#include"game.h"
#define _CRT_SECURE_NO_WARNINGS 1
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)//i=0~10
{
for (j = 0; j < cols; j++)//j=0~10
{
board[i][j] = set;
}
}
}
//分別傳兩個數(shù)組,初始化自己想要初始化的字符
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//打印列號
printf("--------------掃雷--------------\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
//打印數(shù)字
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)
{
//布置雷——循環(huán)隨機數(shù)直到布置完10個雷停止
int count = EASY_COUNT;
while (count)//直到10個雷布置完畢退出循環(huán)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
//產(chǎn)生的坐標就是(0,0)~(9,9)
if (board[x][y] == '0')
//條件設(shè)置,不能重復(fù)計算已經(jīng)設(shè)置過的地方即為1的地方
{
board[x][y] = '1';
count--;
}
}
}
int GetMineCount(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("請輸入要查找的雷\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//輸入的坐標要合法
{
if(show[x][y] != "*")
{
printf("該坐標被排查過了,請重新輸入坐標\n");
}
else if (mine[x][y] == '1')//被炸死的條件
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else//沒有被炸死,顯示雷的個數(shù)
{
//不是雷,就統(tǒng)計x,y坐標周圍有幾個雷
int c = GetMineCount(mine, x, y);
show[x][y] = c + '0';//數(shù)字+'0'=字符數(shù)字放置到字符數(shù)組里去
DisplayBoard(show, ROW, COL);//展示字符數(shù)字——雷的個數(shù)
//每排查一次都要顯示雷的個數(shù)
win++;//每排查一次雷,雷的個數(shù)減少一次,距離循環(huán)結(jié)束++一次
}
}
else//玩家輸入非法坐標,重新輸入
{
printf("坐標非法,請重新輸入\n");
}
}
//炸死和排排完雷都跳出循環(huán)
if (win == row * col - EASY_COUNT)//設(shè)置條件只有排完雷才通關(guān)
{
printf("恭喜你排雷成功,游戲通關(guān)\n");
DisplayBoard(mine, ROW, COL);
}
}
?????最后,感謝大家的閱讀,后續(xù)可能會函數(shù)遞歸優(yōu)化,若有錯誤和不足,歡迎指正!
迎來新的學期,希望大家繼續(xù)堅持在每天敲代碼的路上。??????學習的小伙伴
代碼---------→【gitee:https://gitee.com/TSQXG】文章來源:http://www.zghlxwxcb.cn/news/detail-668304.html
聯(lián)系---------→【郵箱:2784139418@qq.com】文章來源地址http://www.zghlxwxcb.cn/news/detail-668304.html
到了這里,關(guān)于C語言之掃雷游戲?qū)崿F(xiàn)篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!