欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言實(shí)現(xiàn)經(jīng)典windows游戲掃雷的示例代碼

 更新時(shí)間:2022年10月12日 11:44:56   作者:努力學(xué)習(xí)游泳的魚  
今天我們會用C語言實(shí)現(xiàn)一個(gè)經(jīng)典的windows小游戲:掃雷。掃雷是一款單機(jī)小游戲,每次通關(guān)最高難度的關(guān)卡都會開心好一陣?,F(xiàn)在學(xué)會了C語言,總算可以自己實(shí)現(xiàn)掃雷了。話不多說,咱們開始吧

1. 前言

大家好,我是努力學(xué)習(xí)游泳的魚。今天我們會用C語言實(shí)現(xiàn)一個(gè)經(jīng)典的windows小游戲:掃雷。掃雷是一款單機(jī)小游戲,我上中學(xué)時(shí)特喜歡在電腦課上玩,研究應(yīng)對各種情況的思路,每次通關(guān)最高難度的關(guān)卡都會開心好一陣?,F(xiàn)在學(xué)會了C語言,總算可以自己實(shí)現(xiàn)掃雷了。話不多說,咱們開始吧。

2. 準(zhǔn)備工作

我們新建一個(gè)項(xiàng)目,并創(chuàng)建三個(gè)文件:

  • test.c - 負(fù)責(zé)測試游戲代碼。
  • game.c - 負(fù)責(zé)游戲功能的具體實(shí)現(xiàn)。
  • game.h - 負(fù)責(zé)頭文件的包含,符號的定義,函數(shù)的聲明。

在test.c和game.c里都要#include "game.h"

測試游戲時(shí),玩一把肯定不過癮,會想要再來一把,這就需要用到do while循環(huán)。

void menu()
{
	printf("****************************\n");
	printf("********  1. play    *******\n");
	printf("********  0. exit    *******\n");
	printf("****************************\n");
}

int main()
{
	int input = 0;

	do
	{
		menu();
		printf("請選擇(1/0):>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戲\n");
			break;
		default:
			printf("選擇錯(cuò)誤,重新選擇!\n");
			break;
		}
	} while (input);

	return 0;
}

3. 設(shè)計(jì)思路

接下來講解掃雷游戲(game函數(shù))實(shí)現(xiàn)的思路。

1.布置雷 - 10個(gè)。

2.掃雷 - 玩法如下:

輸入坐標(biāo),此時(shí)分兩種情況:

  • 是雷 – 就被炸了,游戲結(jié)束。
  • 不是雷 – 就告訴你這個(gè)坐標(biāo)周圍8個(gè)坐標(biāo)上總共有多少個(gè)雷。

直到把所有非雷的位置全部都找出來,游戲結(jié)束,掃雷成功。

我們假設(shè)掃雷的棋盤是9×9的。我們布置雷的信息要想全部存起來,就需要使用9×9的二維數(shù)組。

怎么布置雷呢?假設(shè)要布置10個(gè)雷,我們就隨機(jī)生成10個(gè)坐標(biāo),把數(shù)組的這10個(gè)位置都置成1,其余位置存儲0。實(shí)際排查的時(shí)候,只需要顯示周圍8個(gè)坐標(biāo)有幾個(gè)1就行了。

但是這樣設(shè)計(jì)有一個(gè)問題,假設(shè)有一個(gè)位置周圍只有1個(gè)雷,那就顯示1。我們?nèi)绾闻袛噙@個(gè)1是表示雷的1,還是顯示周圍有一個(gè)雷的1呢?這就有歧義了。

如何解決這個(gè)問題呢?我們可以再搞一個(gè)一樣大的數(shù)組。兩個(gè)數(shù)組,一個(gè)放布置好的雷的信息,另一個(gè)放排查出的雷的信息。對于后者,如果某個(gè)位置沒有排查過,就存儲星號,以保持神秘感;如果排查過了,并且不是雷,就存儲周圍雷的個(gè)數(shù)。由于星號是一個(gè)字符,為了保持類型的統(tǒng)一,雷的個(gè)數(shù)也要用數(shù)字字符來存儲(如某位置周圍有3個(gè)雷,就存儲字符3),那存儲排查出的雷的信息的數(shù)組就是一個(gè)9×9的char類型的數(shù)組。還是為了保持類型的統(tǒng)一,存儲雷的信息的數(shù)組中,我們用字符0表示非雷,字符1表示雷,該數(shù)組也是一個(gè)9×9的char類型的數(shù)組。

階段總結(jié)一下:

  • char mine[9][9] 負(fù)責(zé)存儲布置好的雷的信息,字符1表示雷,字符0表示非雷。
  • char show[9][9] 負(fù)責(zé)存儲排查出的雷的信息,星號表示未排查,數(shù)字字符表示已排查。

但是,這樣設(shè)計(jì)仍然有問題。如果我們要排查數(shù)組邊上或角上的位置,我們需要訪問該位置周圍的8個(gè)位置,就有可能越界訪問了。
如何解決這個(gè)問題呢?我們可以把存放雷的信息的數(shù)組開大一圈,這樣訪問時(shí),排查邊上或角上的數(shù)據(jù)就不會越界了。為了保持兩個(gè)數(shù)組的一一對應(yīng),另一個(gè)數(shù)組也開大一圈。經(jīng)過以上的分析,如果實(shí)際使用的棋盤大小是9×9的,兩個(gè)數(shù)組就應(yīng)該定義為11×11的。

4. 定義數(shù)組

為了以后修改這點(diǎn)方便,我們定義幾個(gè)宏,ROW和COL為實(shí)際使用的大小(9×9),ROWS和COLS為實(shí)際定義數(shù)組的大?。?1×11)。

#define ROW 9
#define COL 9

#define ROWS (ROW + 2)
#define COLS (COL + 2)

接著定義兩個(gè)數(shù)組。

char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };

5. 初始化

mine數(shù)組由于要存儲雷的信息,沒布置雷前,我們想把這個(gè)數(shù)組全部初始化成0。show數(shù)組用于存放排查出來的雷的信息,一開始應(yīng)全部初始化成星號。所以我們需要一個(gè)初始化函數(shù)。由于兩個(gè)數(shù)組初始化的內(nèi)容不一樣,所以我們設(shè)計(jì)函數(shù)時(shí),需要把初始化的內(nèi)容當(dāng)做參數(shù)傳過去。

init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');

具體的實(shí)現(xiàn),只需遍歷數(shù)組就行了。

void init_board(char arr[ROWS][COLS], int rows, int cols, char set)
{
    int i = 0;
    for (; i < rows; ++i)
    {
        int j = 0;
        for (; j < cols; ++j)
        {
            arr[i][j] = set;
        }
    }
}

6. 打印

對兩個(gè)數(shù)組進(jìn)行初始化后,我們想把它們打印出來看看。

初始化時(shí),我們需要初始化整個(gè)數(shù)組(11×11),但是打印以及后面的操作,我們基本只關(guān)心中間的9×9,周圍的一圈只是為了防止越界。

show_board(mine, ROW, COL);
show_board(show, ROW, COL);

具體的實(shí)現(xiàn),也是遍歷數(shù)組除去最外面一圈的元素,那下標(biāo)應(yīng)從1開始,最大是row或col。

void show_board(char arr[ROWS][COLS], int row, int col)
{
    int i = 0;
    for (i = 1; i <= row; ++i)
    {
        int j = 0;
        for (j = 1; j <= col; ++j)
        {
            printf("%c ", arr[i][j]);
        }
        printf("\n");
    }
}

打印出來效果如下:

但是這樣打印不夠完美,我們每次還要去數(shù)某個(gè)位置是第幾行第幾列,所以最好把行標(biāo)和列標(biāo)也打印出來。

每次打印一行前,我們都打印下行號printf("%d ", i);

在所有信息打印前,我們把列標(biāo)打印出來。

for (i = 0; i <= col; ++i)
{
    printf("%d ", i);
}
printf("\n");

當(dāng)然,我們可以在打印的最前和最后加上分割行。printf("------------掃雷------------\n");

下面是打印函數(shù)完整的代碼。

void show_board(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("------------掃雷------------\n");
	for (i = 0; i <= col; ++i)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (i = 1; i <= row; ++i)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; ++j)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
	printf("------------掃雷------------\n");
}

打印效果如下:

7. 布置雷

我們需要在mine數(shù)組里布置雷。set_mine(mine, ROW, COL);

假設(shè)雷的個(gè)數(shù)是EASY_COUNT。#define EASY_COUNT 10

具體的實(shí)現(xiàn),我們需要寫一個(gè)循環(huán),每次隨機(jī)生成一個(gè)坐標(biāo),如果這個(gè)位置不是雷,就在這個(gè)位置放雷,知道把所有的雷放完為止。

void set_mine(char mine[ROWS][COLS], int row, int col)
{
    int count = EASY_COUNT;
    int x = 0;
    int y = 0;
    while (count)
    {
        x = rand() % row + 1;
        y = rand() % col + 1;
        if ('0' == mine[x][y])
        {
            mine[x][y] = '1'; // 布置雷
            --count;
        }
    }
}

不要忘記在調(diào)用rand函數(shù)之前要調(diào)用srand函數(shù),并給srand函數(shù)傳遞用time函數(shù)生成的時(shí)間戳。srand((unsigned int)time(NULL));rand函數(shù)和srand函數(shù)需要引用頭文件stdlib.h,time函數(shù)需要引用頭文件time.h。

我們可以把生成雷的信息打印出來。show_board(mine, ROW, COL);

8. 排查雷

布置好雷后,就開始排查雷。排查雷需要同時(shí)操作兩個(gè)數(shù)組。find_mine(mine, show, ROW, COL);

排查雷時(shí),可以通過一個(gè)循環(huán)反復(fù)獲取坐標(biāo),并對坐標(biāo)進(jìn)行判斷。

  • 首先判斷坐標(biāo)的合法性,橫縱坐標(biāo)都必須在1到row(col)之間。
  • 如果坐標(biāo)合法,再看這個(gè)坐標(biāo)有沒有排查過,如果show數(shù)組在該位置還是星號,說明沒有排查過。
  • 如果坐標(biāo)還沒排查過,再看是不是雷,是雷的話游戲結(jié)束,不是雷的話就顯示該坐標(biāo)周圍有幾個(gè)雷。

循環(huán)會在兩種情況下結(jié)束,

一種是踩到雷了,直接break出去,

另一種是找到所有非雷的位置,就排雷成功了??偣灿衦ow×col個(gè)位置,一共有EASY_COUNT個(gè)雷,那非雷的位置個(gè)數(shù)就是兩者相減。判斷是否排雷成功,可以在循環(huán)條件中判斷。

void find_mine(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("請輸入要排查的坐標(biāo):>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if ('*' == show[x][y])
			{
				if ('1' == mine[x][y])
				{
					printf("很遺憾,你被炸死了\n");
					show_board(mine, row, col);
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					show_board(show, row, col);
					++win;
				}
			}
			else
			{
				printf("該坐標(biāo)已被排查\n");
			}
		}
		else
		{
			printf("坐標(biāo)非法,重新輸入\n");
		}
	}

	if (row * col - EASY_COUNT == win)
	{
		printf("恭喜你,排雷成功\n");
		show_board(mine, row, col);
	}
}

我們用get_mine_count函數(shù)來獲取某個(gè)位置(坐標(biāo)為x,y)周圍8個(gè)坐標(biāo)雷的個(gè)數(shù)。由于字符1的ASCII碼值減去字符0的ASCII碼值是1,而mine數(shù)組里存放的就是字符1和字符0。所以我們只需要把mine數(shù)組中,該位置周圍八個(gè)坐標(biāo)存儲的字符加起來,再減去字符0的ASCII碼值的八倍,就能算出一共有多少個(gè)雷了。由于get_mine_count函數(shù)只在fine_mine函數(shù)中使用,所以加上static。

static int get_mine_count(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';
}

到此為止,整個(gè)掃雷游戲就寫完啦。

9. 完整代碼

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 init_board(char arr[ROWS][COLS], int rows, int cols, char set);

// 打印
void show_board(char arr[ROWS][COLS], int row, int col);

// 布置雷
void set_mine(char mine[ROWS][COLS], int row, int col);

// 排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void init_board(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (; i < rows; ++i)
	{
		int j = 0;
		for (; j < cols; ++j)
		{
			arr[i][j] = set;
		}
	}
}

void show_board(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("------------掃雷------------\n");
	for (i = 0; i <= col; ++i)
	{
		printf("%d ", i);
	}
	printf("\n");

	for (i = 1; i <= row; ++i)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; ++j)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
	printf("------------掃雷------------\n");
}

void set_mine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	int x = 0;
	int y = 0;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if ('0' == mine[x][y])
		{
			mine[x][y] = '1'; // 布置雷
			--count;
		}
	}
}

static int get_mine_count(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 find_mine(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("請輸入要排查的坐標(biāo):>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if ('*' == show[x][y])
			{
				if ('1' == mine[x][y])
				{
					printf("很遺憾,你被炸死了\n");
					show_board(mine, row, col);
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					show_board(show, row, col);
					++win;
				}
			}
			else
			{
				printf("該坐標(biāo)已被排查\n");
			}
		}
		else
		{
			printf("坐標(biāo)非法,重新輸入\n");
		}
	}

	if (row * col - EASY_COUNT == win)
	{
		printf("恭喜你,排雷成功\n");
		show_board(mine, row, col);
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void menu()
{
	printf("****************************\n");
	printf("********  1. play    *******\n");
	printf("********  0. exit    *******\n");
	printf("****************************\n");
}

void game()
{
	// 掃雷游戲的具體實(shí)現(xiàn)
	// 存儲布置好的雷的信息
	char mine[ROWS][COLS] = { 0 };
	// 存放排查出來的雷的信息
	char show[ROWS][COLS] = { 0 };

	// 初始化棋盤
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');
	// 打印棋盤
	//show_board(mine, ROW, COL);
	// 布置雷
	set_mine(mine, ROW, COL);
	show_board(show, ROW, COL);
	// 排查雷
	find_mine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));

	do
	{
		menu();
		printf("請選擇(1/0):>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戲\n");
			break;
		default:
			printf("選擇錯(cuò)誤,重新選擇!\n");
			break;
		}
	} while (input);

	return 0;
}

以上就是C語言實(shí)現(xiàn)經(jīng)典windows游戲掃雷的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于C語言掃雷游戲的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言連續(xù)生成多個(gè)隨機(jī)數(shù)實(shí)現(xiàn)可限制范圍

    C語言連續(xù)生成多個(gè)隨機(jī)數(shù)實(shí)現(xiàn)可限制范圍

    這篇文章主要介紹了C語言連續(xù)生成多個(gè)隨機(jī)數(shù)實(shí)現(xiàn)可限制范圍,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C++數(shù)據(jù)結(jié)構(gòu)關(guān)于棧迷宮求解示例

    C++數(shù)據(jù)結(jié)構(gòu)關(guān)于棧迷宮求解示例

    這篇文章主要為大家介紹了C++數(shù)據(jù)結(jié)構(gòu)關(guān)于棧的迷宮求解示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • 淺談C++11中的幾種鎖

    淺談C++11中的幾種鎖

    本文主要介紹了C++11中的幾種鎖,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • QT讀寫Sqlite數(shù)據(jù)庫的三種方式

    QT讀寫Sqlite數(shù)據(jù)庫的三種方式

    Sqlite是一個(gè)比較小型的本地?cái)?shù)據(jù)庫,對于保存一些軟件配置參數(shù)或量不是很大的數(shù)據(jù)是相當(dāng)?shù)姆奖?Qt本身已經(jīng)自帶了Sqlite的驅(qū)動,直接使用相關(guān)的類庫即可,這篇我們主要來說明QT訪問Sqlite數(shù)據(jù)庫的三種方式,需要的朋友可以參考下
    2024-03-03
  • CRITICAL_SECTION用法案例詳解

    CRITICAL_SECTION用法案例詳解

    這篇文章主要介紹了CRITICAL_SECTION用法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C語言實(shí)現(xiàn)3*3數(shù)組對角線之和示例

    C語言實(shí)現(xiàn)3*3數(shù)組對角線之和示例

    今天小編就為大家分享一篇C語言實(shí)現(xiàn)3*3數(shù)組對角線之和示例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • 深入理解C/C++中的寫時(shí)拷貝

    深入理解C/C++中的寫時(shí)拷貝

    這篇文章主要給大家介紹了C/C++中寫時(shí)拷貝的相關(guān)資料,所謂寫時(shí)拷貝也就是拖延版的深拷貝,下面文章中介紹的非常清楚,需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。
    2017-03-03
  • C語言使用單鏈表實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)

    C語言使用單鏈表實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言使用單鏈表實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語言實(shí)現(xiàn)反彈球消磚塊游戲

    C語言實(shí)現(xiàn)反彈球消磚塊游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)反彈球消磚塊游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言中數(shù)據(jù)結(jié)構(gòu)之鏈?zhǔn)交鶖?shù)排序

    C語言中數(shù)據(jù)結(jié)構(gòu)之鏈?zhǔn)交鶖?shù)排序

    這篇文章主要介紹了C語言中數(shù)據(jù)結(jié)構(gòu)之鏈?zhǔn)交鶖?shù)排序的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09

最新評論