C語言實現(xiàn)遞歸版掃雷游戲實例
思路
清晰的邏輯
為方便將其分為三個文件:text.c(測試) game.c(函數(shù)實現(xiàn)) game.h(頭文件聲明)
在排雷的時候為了方便,我們需要將每一行每一列對應的行數(shù),列數(shù)打印出來。
#define LEI 10 #define ROW 10 #define LOW 10 #define ROWS ROW+2 #define LOWS LOW+2 //在定義棋盤的長寬時,特意加上2,便于標記行數(shù)列數(shù)。

菜單
打印的菜單只需要有開始游戲、退出游戲的選項即可
void menu()
{
printf("*************************************\n");
printf("************1.開始游戲***************\n");
printf("************0.退出游戲***************\n");
printf("*************************************\n");
}棋盤
1.雷盤
2.棋盤
掃雷需要先記錄雷的信息再進行排雷,如果使用一個棋盤太過于復雜,所以我們使用兩個棋盤,一個用于布置雷,一個用于玩家排雷。
兩個棋盤初始化
布置雷的棋盤初始化,將字符‘0’作為非雷,字符‘1’作為雷。
玩家盤將字符‘*’作為還沒有掃的地方
board(arr1, ROWS, LOWS, '0');//雷盤 board(arr2, ROWS, LOWS, '*');//玩家盤
因為兩個的初始化方式不同,所以我們采用傳參ret初始化
//初始化棋盤
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < lows; j++)
{
arr1[i][j] = ret;
}
}布置雷
布置的雷放置需要隨機,所以采用兩個隨機數(shù)來定位坐標。
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
int count = LEI;
while (count)
{
int x = rand() % row + 1;
int y = rand() % low + 1;
if (arr1[x][y] == '0')
{
arr1[x][y] = '1';
count--;
}
}
//displayboard(arr1, ROW, LOW);//用于測試
}排雷
當我們輸入一個坐標時,我們需要知道這個坐標周圍雷的個數(shù),定義一個Get_num函數(shù)來獲取雷個數(shù)。但此時只能獲取一個坐標的信息,我們知道一般的掃雷,如果當前坐標雷的個數(shù)為0,就會展開,這個過程較為復雜,所以我們使用遞歸來實現(xiàn)
//玩家盤
static int Get_num(char arr1[ROWS][LOWS],int x, int y)//獲得當前坐標周圍雷的個數(shù)
{
int count = 0;
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (arr1[i][j] == '1')
{
count++;
}
}
}
return count;
}
//判斷是否展開,實現(xiàn)函數(shù)
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';//記錄雷的個數(shù)
//遞歸散開
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';
arr1[x][y] = ' ';
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}判斷輸贏
輸:即每排一次雷,檢查一下雷盤對應的信息,如果是雷,就被炸死,如果不是,就繼續(xù)排雷。
贏:當玩家將所有的非雷的區(qū)域都排查出來時,判斷為贏。(這里采用一個計數(shù)器,沒排一次雷計數(shù)器就++一下,當計數(shù)器與總的非雷的區(qū)域數(shù)目相同時,判斷為贏)
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
int x = 0;
int y = 0;
while (1)
{
printf("請輸入坐標:>");
scanf("%d,%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
{
if (arr1[x][y] == '1')
{
arr2[x][y] = '#';
displayboard(arr2, ROW, LOW);//排雷
printf("遺憾你輸了\n");
break;
}
else
{
Judge(arr2, arr1, x, y);
displayboard(arr2, ROW, LOW);//排雷
}
}
else
{
printf("輸入錯誤!\n");
}
//判斷掃雷是否贏
int i = 0, flag = 0;
for (i = 1; i <= ROW; i++)
{
int j = 0;
for (j = 1; j <= LOW; j++)
{
if (arr2[i][j] != '*')
{
flag++;
}
}
}
if (flag == ROW*LOW - LEI)
{
printf("你贏了!\n");
break;
}
}
}text.c實現(xiàn)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//菜單
void menu()
{
printf("*************************************\n");
printf("************1.開始游戲***************\n");
printf("************0.退出游戲***************\n");
printf("*************************************\n");
}
void game()
{
//初始化棋盤
char arr1[ROWS][LOWS] = { 0 };//雷盤
char arr2[ROWS][LOWS] = { 0 };//玩家盤
board(arr1, ROWS, LOWS, '0');
board(arr2, ROWS, LOWS, '*');
//打印棋盤
//displayboard(arr1, ROW, LOW);//布置雷
displayboard(arr2, ROW, LOW);//排雷
//布置雷
Get_lei(arr1,ROW,LOW);
//排雷
Out_lei(arr2,ROW,LOW, arr1);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
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);
return 0;
}game.c實現(xiàn)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盤
void board(char arr1[ROWS][LOWS], int rows, int lows, char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < lows; j++)
{
arr1[i][j] = ret;
}
}
}
//打印棋盤
void displayboard(char arr1[ROWS][LOWS], int row, int low)
{
printf("<———掃雷游戲———>\n");
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
if (i == 1)
{
for (j = 0; j <= low; j++)
{
printf("%2d ", j);
}
printf("\n");
}
for (j = 1; j <= low; j++)
{
if (j == 1)
{
printf("%2d ", i);
}
printf("%2c ", arr1[i][j]);
}
printf("\n");
}
printf("<———掃雷游戲———>\n");
}
//布置雷
void Get_lei(char arr1[ROWS][LOWS], int row, int low)
{
int count = LEI;
while (count)
{
int x = rand() % row + 1;
int y = rand() % low + 1;
if (arr1[x][y] == '0')
{
arr1[x][y] = '1';
count--;
}
}
//displayboard(arr1, ROW, LOW);
}
//玩家盤
static int Get_num(char arr1[ROWS][LOWS],int x, int y)
{
int count = 0;
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (arr1[i][j] == '1')
{
count++;
}
}
}
return count;
}
//判斷是否展開,實現(xiàn)函數(shù)
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';
//遞歸散開
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';
arr1[x][y] = ' ';
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}
void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS])
{
int x = 0;
int y = 0;
while (1)
{
printf("請輸入坐標:>");
scanf("%d,%d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= LOW)
{
if (arr1[x][y] == '1')
{
arr2[x][y] = '#';
displayboard(arr2, ROW, LOW);//排雷
printf("遺憾你輸了\n");
break;
}
else
{
Judge(arr2, arr1, x, y);
displayboard(arr2, ROW, LOW);//排雷
}
}
else
{
printf("輸入錯誤!\n");
}
//判斷掃雷是否贏
int i = 0, flag = 0;
for (i = 1; i <= ROW; i++)
{
int j = 0;
for (j = 1; j <= LOW; j++)
{
if (arr2[i][j] != '*')
{
flag++;
}
}
}
if (flag == ROW*LOW - LEI)
{
printf("你贏了!\n");
break;
}
}
}
game.h實現(xiàn)
#pragma once #include <stdio.h> #include <stdlib.h> #define LEI 10 #define ROW 10 #define LOW 10 #define ROWS ROW+2 #define LOWS LOW+2 //初始化棋盤 void board(char arr1[ROWS][LOWS],int rows,int lows,char ret); //打印棋盤 void displayboard(char arr1[ROWS][LOWS], int row, int low); //布置雷 void Get_lei(char arr1[ROWS][LOWS], int row, int low); //玩家盤 void Out_lei(char arr2[ROWS][LOWS], int row, int low, char arr1[ROWS][LOWS]);
遞歸部分詳解
遞歸條件:1.有停止的條件。2.每一次遞歸都會向這個條件靠攏。
那么這里的停止條件是什么呢?
遞歸:當返回雷的個數(shù)為0時,就符合繼續(xù)遞歸的條件,我們需要將當前坐標周圍的點全部排除。且需要將已經排查了的坐標做一個標記,否則就會不停的排查下去,就會形成死遞歸。所以
停止條件:當前這個坐標是已被排查過的,就停止遞歸。
因為每一次排查都會的一個標記,所以這就是那個不斷向停止條件靠攏的過程。
//判斷是否展開,實現(xiàn)函數(shù)
static void Judge(char arr2[ROWS][LOWS], char arr1[ROWS][LOWS], int x, int y)
{
if (x > 0 && x <= ROW && y > 0 && y <= LOW)
{
int ret = Get_num(arr1, x, y);
if (ret != 0)
arr2[x][y] = ret + '0';
//遞歸散開
else if (arr1[x][y] != ' ')
{
arr2[x][y] = '0';//玩家盤
arr1[x][y] = ' ';//雷盤
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
Judge(arr2, arr1, i, j);
}
}
}
else
{
return;
}
}
}總結
到此這篇關于C語言實現(xiàn)遞歸版掃雷游戲實例的文章就介紹到這了,更多相關C語言遞歸版掃雷內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
c語言循環(huán)加數(shù)組實現(xiàn)漢諾塔問題
本文主要介紹了c語言循環(huán)加數(shù)組實現(xiàn)漢諾塔問題,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01

