C语言伪图形与键盘操作加扫雷实例

这篇具有很好参考价值的文章主要介绍了C语言伪图形与键盘操作加扫雷实例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


大家好,这一篇博客讲的是我对C语言伪图形与键盘操作的理解。如果有错误,还请读者大大们指出。
    准备test.c源文件,game.c源文件,game.h头文件。

界面选择与坐标绑定

在game.h头文件中:

#pragma once

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <conio.h> // getch()函数需要的头文件
#include <Windows.h> // gotoxy()函数与HideCursor()函数需要的头文件

void gotoxy(int a, int b);

void game();

在test.c源文件中:

#include "game.h"

void gotoxy(int a, int b) // 固定画面位置
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = a;
	pos.Y = b;
	SetConsoleCursorPosition(handle, pos);
}

void HideCursor() // 隐藏光标
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void menuPrint(int y)
{
	char arr[2][13] = { "开始游戏", "退出游戏" };

	printf("********************\n");
	// 坐标与数组连接
	if (y == 0) // 传首元素地址
		printf("****%12s****\n", &arr[0][0]); // %12s占12格右对齐
	else
		printf("****%-12s****\n", &arr[0][0]); // %-12s占12格左对齐

	if (y == 1)
		printf("****%12s****\n", &arr[1][0]);
	else
		printf("****%-12s****\n", &arr[1][0]);

	printf("********************\n");
}

void menuOperate(char ch, int* y)
{
	switch (ch)
	{
	case 0x48: // 0x48对应向上方向键
		*y = (*y - 1 + 2) % 2; // 加2后%2,可防止成为负数这两个范围
		break;
	case 0x50: // 0x50对应向下方向键
		*y = (*y + 1) % 2; // %2防止超出数组最大下标 
		break;
	case 'a':
		//game();
		break;
	}
}

void menu()
{
	int y = 0; // 只支持纵向移动
	char ch = 0; // 接收字符
	while (1)
	{
		gotoxy(0, 0);
		menuPrint(y); // 1.菜单打印
		ch = _getch(); // 2.输入字符(getch函数不需要输入回车即可执行)
		menuOperate(ch, &y); // 3.菜单操作
	}
}

int main()
{
	HideCursor(); // 隐藏光标
	menu(); // 菜单选择
	return 0;
}

程序展示:

QQ录屏20231221184108

加入 \033特殊转义字符方式改变颜色

void menuPrint(int y)
{
	char arr[2][13] = { "开始游戏", "退出游戏" };

	printf("********************\n");
	// 坐标与数组连接
	if (y == 0) // 传首元素地址
		printf("****\033[41m%12s\033[0m****\n", &arr[0][0]); // 红色
	else
		printf("****%-12s****\n", &arr[0][0]); // %-12s占12格左对齐

	if (y == 1)
		printf("****\033[41m%12s\033[0m****\n", &arr[1][0]); // 红色
	else
		printf("****%-12s****\n", &arr[1][0]);

	printf("********************\n");
}

程序展示:

QQ111

进入游戏与操作执行

在game.h头文件中:

#pragma once

#define HIGH 5 // 设置游戏画面高度
#define WIGHT 5 // 设置游戏画面宽度

#include <stdio.h>
#include <conio.h> // getch()函数需要的头文件
#include <Windows.h> // gotoxy()函数与HideCursor()函数需要的头文件

void gotoxy(int a, int b);

void game();

在test.c源文件中:

#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

void gotoxy(int a, int b) // 固定画面位置
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = a;
	pos.Y = b;
	SetConsoleCursorPosition(handle, pos);
}

void HideCursor() // 隐藏光标
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void menuPrint(int y)
{
	char arr[2][13] = { "开始游戏", "退出游戏" };

	printf("********************\n");
	// 坐标与数组连接
	if (y == 0) // 传首元素地址
		printf("****\033[41m%12s\033[0m****\n", &arr[0][0]); // %12s占12格右对齐
	else
		printf("****%-12s****\n", &arr[0][0]); // %-12s占12格左对齐

	if (y == 1)
		printf("****\033[41m%12s\033[0m****\n", &arr[1][0]);
	else
		printf("****%-12s****\n", &arr[1][0]);

	printf("********************\n");
}

void menuOperate(char ch, int* y)
{
	switch (ch)
	{
	case 0x48:	// 0x48对应向上方向键
		*y = (*y - 1 + 2) % 2; // 加2后%2,可防止成为负数这两个范围
		break;
	case 0x50:	// 0x50对应向下方向键
		*y = (*y + 1) % 2; // %2防止超出数组最大下标 
		break;
	case 'a':
		system("cls"); // 清屏一次
		game();
		break;
	}
}

void menu()
{
	int y = 0; // 只支持纵向移动
	char ch = 0; // 接收字符
	while (1)
	{
		gotoxy(0, 0);
		menuPrint(y); // 1.菜单打印
		ch = _getch(); // 2.输入字符(getch函数不需要输入回车即可执行)
		menuOperate(ch, &y); // 3.菜单操作
	}
}

int main()
{
	HideCursor(); // 隐藏光标
	menu(); // 菜单选择
	return 0;
}

在game.c源文件中:

#include "game.h"

void init(char arr[HIGH][WIGHT])
{
	for (int i = 0; i < HIGH; i++)
		for (int j = 0; j < WIGHT; j++)
			arr[i][j] = '*';
}

void game()
{
	char arr[HIGH][WIGHT] = { 0 };
	init(arr);
	int y = 0;
	int x = 0;
	char ch = 0;
	while (1)
	{
		gotoxy(0, 0);
		// 1.游戏打印
		for (int i = 0; i < HIGH; i++)
		{
			for (int j = 0; j < WIGHT; j++)
			{
				if (i == y && j == x) // 若对应坐标y, x,则打印背景色
				{
					printf("\033[42m%c\033[0m ", arr[i][j]); // 背景色绿色
				}
				else // 其它正常打印
				{
					printf("%c ", arr[i][j]);
				}
			}
			printf("\n");
		}
		// 2.输入字符
		ch = _getch();
		// 3.游戏操作
		switch (ch)
		{
		case 0x48:// 0x48对应向上方向键
			y = (y - 1 + HIGH) % HIGH; // 成为负数时转到HIGH - 1坐标
			break;
		case 0x50:// 0x50对应向下方向键
			y = (y + 1) % HIGH; // 超过HIGH - 1时转到0坐标
			break;
		case 0x4b:// 0x4b对应向左方向键
			x = (x - 1 + WIGHT) % WIGHT; // 成为负数时转到WIGHT - 1坐标
			break;
		case 0x4d:// 0x4d对应向右方向键
			x = (x + 1) % WIGHT; // 超过WIGHT - 1时转到0坐标
			break;
		case 'a': // 输入小写字母a将'*'转为'#'
			if (arr[y][x] == '*')
				arr[y][x] = '#';
				break;
		case 's': // 输入小写字母s将'#'转为'*'
			if (arr[y][x] == '#')
				arr[y][x] = '*';
			break;
		}
	}
}

程序展示:

程序展示3

总结

想要使用伪图形,首先准备gotoxy()函数固定画面,HideCursor()函数隐藏光标(也可以只使用system(“cls”)清屏函数,不过效果不如前两者),随后确定坐标要移动的方向,字符变量与其他要准备的条件,最后在循环中执行1.打印2.输入3.操作即可。

实例:将C语言扫雷实现伪图形与键盘操作

(注:以下的代码和被修改的代码来自本人上一篇博客《C语言扫雷小游戏(VS2022版)》)

开始菜单

void menu1()
{
	char a = 0;
	int y = 0; // 只限纵轴移动
	while (1)
	{
		gotoxy(0, 0);
		// 1.打印
		char arr[2][13] = { "开始游戏", "退出游戏" };
		printf("*************************\n");
		if (y == 0)
			printf("****   \033[41m->%-10s  \033[0m****\n", &arr[0][0]);
		else
			printf("****   %-12s  ****\n", &arr[0][0]);
		if (y == 1)
			printf("****   \033[41m->%-10s  \033[0m****\n", &arr[1][0]);
		else
			printf("****   %-12s  ****\n", &arr[1][0]);
		printf("*************************\n");
		printf("操作说明:>\n");
		printf("上下方向键选择\n");
		printf("小写字母a确定键\n");
		// 2.输入
		a = _getch();
		// 3.操作
		switch (a)
		{
		case 0x48:
			y = (y - 1 + 2) % 2;
			break;
		case 0x50:
			y = (y + 1 + 2) % 2;
			break;
		case 'a':
			if (y == 0)
			{
				system("cls"); // 先清屏
				game();
			}
			else
			{
				system("cls");// 先清屏
				printf("%s\n", "退出游戏");
				exit(0);
			}
			break;
		}
	}
}

选择难度界面

int option(int* rows, int* cols)
{
	char a = 0;
	int y = 0; // 只限纵轴移动
	while (1)
	{
		gotoxy(0, 0); // 固定画面
		// 1.打印画面
		char arr[4][20] = { "1.初级(9×9)", "2.中级(16×16)", "3.高级(16×30)", "4.自定义" };

		printf("*************************\n");
		if (y == 0)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[0][0]);
		else
			printf("****   %-15s****\n", &arr[0][0]);
		if (y == 1)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[1][0]);
		else
			printf("****   %-15s****\n", &arr[1][0]);
		if (y == 2)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[2][0]);
		else
			printf("****   %-15s****\n", &arr[2][0]);
		if (y == 3)
			printf("****   \033[41m%-14s\033[0m****\n", &arr[3][0]);
		else
			printf("****   %-14s****\n", &arr[3][0]);
		printf("*************************\n");
		printf("操作说明:>\n");
		printf("上下方向键选择\n");
		printf("小写字母a确定键\n");
		// 2.输入字符
		a = _getch();
		// 3.移动操作
		switch (a)
		{
		case 0x48:
			y = (y - 1 + 4) % 4;
			break;
		case 0x50:
			y = (y + 1 + 4) % 4;
			break;
		case 'a':
			if (y == 0)
			{
				*rows = 11;
				*cols = 11;
				return 1;
			}
			else if (y == 1)
			{
				*rows = 18;
				*cols = 18;
				return 2;
			}
			else if (y == 2)
			{
				*rows = 18;
				*cols = 32;
				return 3;
			}
			else if (y == 3)
			{
				system("cls");// 先清屏
				myApply(rows, cols);
				return 4;
			}
			break;
		}
	}
	return 1;
}

打印画面

对于findMine函数:

void findMine(char** mine, char** show, int row, int col)
{
	// 注:由于扫雷下标从1开始,在 3.游戏操作 中需要变通一下
	int x = 1; // 横轴移动
	int y = 1; // 纵轴移动
	int time1 = (int)time(NULL); // 获取进入游戏的时间
	int win = 0;
	int first = 1;
	while (win < row * col - getMineCount && win >= 0) // 当win为负数意思为被雷炸死
	{
		char ch = 0;
		// 1.打印

		int FCount = display(show, row, col, y, x, &time1);

		// 2.输入
		
		// kbhit()函数是为防止 程序停在getch()函数接收字符时 导致时间不流逝
		if (_kbhit()) 
			ch = _getch();

		// 3.游戏操作
		switch (ch)
		{
		case 'a':
			if (show[y][x] == '*')                    // 判断输入的坐标是否被占用
			{
				if (first)
				{
					setMine(mine, row, col, y, x);
					first = 0;
				}
				if (mine[y][x] == '1')                // 判断输入的坐标是否是雷
				{
					win = -9;
				}
				else
				{
					int count = mineCount(mine, y, x);
					show[y][x] = count + '0';
					win++;
					spread(mine, show, y, x, &win, row, col);
				}
			}
			break;
		case 's':
			// 扫雷游戏有一个细节:当旗子数与雷数对应就不可插旗了
			if (show[y][x] == '*' && FCount < getMineCount) 
				show[y][x] = 'F';
			break;
		case 'd':
			if (show[y][x] == 'F')
				show[y][x] = '*';
			break;
		case 'f':
			if (show[y][x] >= '1' && show[y][x] <= '7')
				numberSpread(mine, show, y, x, show[y][x] - '0', &win, row, col);
			break;
		case 0x48: // 向下移动
			if (y > 1) // y大于1
				y = y - 1;
			else
				y = row; // y不大于1直接转到row
			break;
		case 0x50: // 向上移动
			if (y < row) // y小与row
				y = y + 1;
			else
				y = 1; // y等于row直接转到1
			break;
		case 0x4b: // 向左移动
			if (x > 1) 
				x = x - 1; 
			else
				x = col; // x不大于1直接转到col
			break;
		case 0x4d: // 向右移动
			if (x < col)
				x = x + 1;
			else
				x = 1; // x等于col直接转到1
			break;
		case 27:
			system("cls");
			return ;
		}
	}
	if (win == row * col - getMineCount)
	{
		printf("**********************\n");
		printf("******  你赢了  ******\n");
		printf("**********************\n");
		printf("按任意键返回:>\n");
		char winTime = _getch();
		system("cls");
	}
	else
	{
		display(mine, row, col, y, x, &time1);
		printf("**********************\n");
		printf("**很遗憾,你被炸死了**\n");
		printf("**********************\n");
		printf("按任意键返回:>\n");
		char falseTime = _getch();
		system("cls");
	}
}

对于display函数:

int display(char** arr, int row, int col, int y, int x, int* time1)
{
	gotoxy(0, 0);
	int count = 0;
//游戏进行时间 为   当前时间    减去 进入游戏的时间  
	int time2 = (int)time(NULL) - *time1;
	int i, j;
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("time:%d", time2); // 打印游戏时间
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++) // 打印扫雷内容
		{
			if (i == y && j == x)
			{
				printf("\033[42m%c\033[0m ", arr[i][j]);
				if (arr[i][j] == 'F')
					count++;
			}
			else
			{
				if (arr[i][j] == '*')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == '0')
					printf("\033[30m%c\033[0m ", arr[i][j]); // 黑色
				if (arr[i][j] == '1')
					printf("\033[36m%c\033[0m ", arr[i][j]); // 浅蓝色
				if (arr[i][j] == '2')
					printf("\033[34m%c\033[0m ", arr[i][j]); // 蓝色
				if (arr[i][j] == '3')
					printf("\033[33m%c\033[0m ", arr[i][j]); // 黄色
				if (arr[i][j] == '4')
					printf("\033[31m%c\033[0m ", arr[i][j]); // 红色
				if (arr[i][j] == '5')
					printf("\033[35m%c\033[0m ", arr[i][j]); // 紫色
				if (arr[i][j] == '6')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == '7')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == 'F')
				{
					printf("\033[32m%c\033[0m ", arr[i][j]); // 绿色
					count++;
				}
			}
		}
		printf("\n"); // 换行
	}
	if (count > getMineCount) // 防止雷数量成为负数
		count = getMineCount;
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("雷:\033[31m%d\033[0m", getMineCount - count); // 表示当前雷的数量
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("\n");

	printf("********************操作说明**********************\n");
	printf("**** Esc.返回 a.查找 s.插旗 d.取旗 f.数字展开 ****\n");
	printf("**************************************************\n");
	return count; // 获得当前F的数量
}

伪图形C语言扫雷源代码

在game.h头文件中:

#pragma once

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <time.h> // time 函数需要的头文件
#include <stdlib.h> // rand、 srand、malloc 函数需要的头文件
#include <conio.h>
#include <windows.h>

void initBoard(char** arr, int rows, int cols, char set);

int display(char** arr, int row, int col, int y, int x, int* time);

void setMine(char** mine, int row, int col, int y, int x);

void findMine(char** mine, char** show, int row, int col);

void spread(char** mine, char** show, int y, int x, int* win, int row, int col);

void numberSpread(char** mine, char** show, int y, int x, int num, int* win, int row, int col);

// 动态扫雷实现
char** apply(int* rows, int* cols);

void release(char** arr, int rows, int cols);

int getMine();

void myApply(int* rows, int* cols);

int myGetMine();

// 伪图形扫雷实现
void game();

void gotoxy(int a, int b);

void HideCursor();

在test.c源文件中:

#include "game.h"

int getMineCount = 0;

void menu1()
{
	char a = 0;
	int y = 0; // 只限纵轴移动
	while (1)
	{
		gotoxy(0, 0);
		// 1.打印
		char arr[2][13] = { "开始游戏", "退出游戏" };
		printf("*************************\n");
		if (y == 0)
			printf("****   \033[41m->%-10s  \033[0m****\n", &arr[0][0]);
		else
			printf("****   %-12s  ****\n", &arr[0][0]);
		if (y == 1)
			printf("****   \033[41m->%-10s  \033[0m****\n", &arr[1][0]);
		else
			printf("****   %-12s  ****\n", &arr[1][0]);
		printf("*************************\n");
		printf("操作说明:>\n");
		printf("上下方向键选择\n");
		printf("小写字母a确定键\n");
		// 2.读取
		a = _getch();
		// 3.选择
		switch (a)
		{
		case 0x48:
			y = (y - 1 + 2) % 2;
			break;
		case 0x50:
			y = (y + 1 + 2) % 2;
			break;
		case 'a':
			if (y == 0)
			{
				system("cls"); // 先清屏
				game();
			}
			else
			{
				system("cls");// 先清屏
				printf("%s\n", "退出游戏");
				exit(0);
			}
			break;
		}
	}
}

int option(int* rows, int* cols)
{
	char a = 0;
	int y = 0; // 只限纵轴移动
	while (1)
	{
		gotoxy(0, 0); // 固定画面
		// 1.打印画面
		char arr[4][20] = { "1.初级(9×9)", "2.中级(16×16)", "3.高级(16×30)", "4.自定义" };

		printf("*************************\n");
		if (y == 0)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[0][0]);
		else
			printf("****   %-15s****\n", &arr[0][0]);
		if (y == 1)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[1][0]);
		else
			printf("****   %-15s****\n", &arr[1][0]);
		if (y == 2)
			printf("****   \033[41m%-15s\033[0m****\n", &arr[2][0]);
		else
			printf("****   %-15s****\n", &arr[2][0]);
		if (y == 3)
			printf("****   \033[41m%-14s\033[0m****\n", &arr[3][0]);
		else
			printf("****   %-14s****\n", &arr[3][0]);
		printf("*************************\n");
		printf("操作说明:>\n");
		printf("上下方向键选择\n");
		printf("小写字母a确定键\n");
		// 2.输入字符
		a = _getch();
		// 3.移动操作
		switch (a)
		{
		case 0x48:
			y = (y - 1 + 4) % 4;
			break;
		case 0x50:
			y = (y + 1 + 4) % 4;
			break;
		case 'a':
			if (y == 0)
			{
				*rows = 11;
				*cols = 11;
				return 1;
			}
			else if (y == 1)
			{
				*rows = 18;
				*cols = 18;
				return 2;
			}
			else if (y == 2)
			{
				*rows = 18;
				*cols = 32;
				return 3;
			}
			else if (y == 3)
			{
				system("cls");// 先清屏
				myApply(rows, cols);
				return 4;
			}
			break;
		}
	}
	return 1;
}

void game()
{
	int rows = 0;
	int cols = 0;
	int num = option(&rows, &cols);
	char** mine = apply(&rows, &cols);
	char** show = apply(&rows, &cols);
	getMineCount = getMine(num);
	int row = rows - 2;
	int col = cols - 2;
	initBoard(mine, rows, cols, '0');
	initBoard(show, rows, cols, '*');
	system("cls");// 先清屏
	findMine(mine, show, row, col);
	release(mine, rows, cols);
	release(show, rows, cols);
}

void test()
{
	HideCursor();
	srand((unsigned int)time(NULL)); // 使rand函数产生伪随机数
	menu1();
}

int main()
{
	test();
	return 0;
}

在game.c源文件中:

#include "game.h"

extern int getMineCount;

void gotoxy(int a, int b)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = a;
	pos.Y = b;
	SetConsoleCursorPosition(handle, pos);
}

void HideCursor()
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), & cursor_info);
}

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

int display(char** arr, int row, int col, int y, int x, int* time1)
{
	gotoxy(0, 0);
	int count = 0;
//游戏进行时间 为   当前时间    减去 进入游戏的时间  
	int time2 = (int)time(NULL) - *time1;
	int i, j;
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("time:%d", time2);
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++) // 打印扫雷内容
		{
			if (i == y && j == x)
			{
				printf("\033[42m%c\033[0m ", arr[i][j]);
				if (arr[i][j] == 'F')
					count++;
			}
			else
			{
				if (arr[i][j] == '*')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == '0')
					printf("\033[30m%c\033[0m ", arr[i][j]); // 黑色
				if (arr[i][j] == '1')
					printf("\033[36m%c\033[0m ", arr[i][j]); // 浅蓝色
				if (arr[i][j] == '2')
					printf("\033[34m%c\033[0m ", arr[i][j]); // 蓝色
				if (arr[i][j] == '3')
					printf("\033[33m%c\033[0m ", arr[i][j]); // 黄色
				if (arr[i][j] == '4')
					printf("\033[31m%c\033[0m ", arr[i][j]); // 红色
				if (arr[i][j] == '5')
					printf("\033[35m%c\033[0m ", arr[i][j]); // 紫色
				if (arr[i][j] == '6')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == '7')
					printf("%c ", arr[i][j]);
				if (arr[i][j] == 'F')
				{
					printf("\033[32m%c\033[0m ", arr[i][j]); // 绿色
					count++;
				}
			}
		}
		printf("\n"); // 换行
	}
	if (count > getMineCount) // 防止雷数量成为负数
		count = getMineCount;
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("雷:\033[31m%d\033[0m", getMineCount - count); // 表示当前雷的数量
	for (i = 0; i <= col / 2 - 2; i++)
		printf("--");
	printf("\n");

	printf("********************操作说明**********************\n");
	printf("**** Esc.返回 a.查找 s.插旗 d.取旗 f.数字展开 ****\n");
	printf("**************************************************\n");
	return count; // 获得当前F的数量
}

void setMine(char** mine, int row, int col, int y, int x)
{
	int count = 0;
	int i, j;
	// 记录输入行和旁边的两行
	int judgeRow[3] = { 0 };
	for (int k = -1, a = 0; k <= 1; k++, a++)
		judgeRow[a] = k + y;

	// 记录输入列和旁边的两列
	int judgeCol[3] = { 0 };
	for (int k = -1, a = 0; k <= 1; k++, a++)
		judgeCol[a] = k + x;

	while (count < getMineCount) // 布置雷的数量,数量到达时则跳出循环
	{
		i = rand() % row + 1; // 行

		// 当输入行且旁边两行与布置行不同时
		if (i != judgeRow[0] && i != judgeRow[1] && i != judgeRow[2])
			j = rand() % col + 1; // 列

		// 当输入行或旁边两行与布置行相同时
		else
		{
			do
			{
				j = rand() % col + 1;
				// 若输入列或旁边两列与布置列相同则进入循环
			} while (j == judgeCol[0] || j == judgeCol[1] || j == judgeCol[2]);
		}
		if (mine[i][j] == '0') // 若为 '0',则放置雷
		{
			mine[i][j] = '1';
			count++;
		}
	}
}

int mineCount(char** mine, int y, int x)
{
	int count = 0;
	for (int i = -1; i <= 1; i++)
		for (int j = -1; j <= 1; j++)
			if (mine[y + i][x + j] == '1')
				count++;

	return count;
}

void findMine(char** mine, char** show, int row, int col)
{
	// 注:由于扫雷下标从1开始,在 3.游戏操作 中需要变通一下
	int x = 1; // 横轴移动
	int y = 1; // 纵轴移动
	int time1 = (int)time(NULL); // 获取进入游戏的时间
	int win = 0;
	int first = 1;
	while (win < row * col - getMineCount && win >= 0) // 当win为负数意思为被雷炸死
	{
		char ch = 0;
		// 1.打印

		int FCount = display(show, row, col, y, x, &time1);

		// 2.输入
		
		// kbhit()函数是为防止 程序停在getch()函数接收字符时 导致的时间不流逝
		if (_kbhit()) 
			ch = _getch();

		// 3.游戏操作
		switch (ch)
		{
		case 'a':
			if (show[y][x] == '*')                    // 判断输入的坐标是否被占用
			{
				if (first)
				{
					setMine(mine, row, col, y, x);
					first = 0;
				}
				if (mine[y][x] == '1')                // 判断输入的坐标是否是雷
				{
					win = -9;
				}
				else
				{
					int count = mineCount(mine, y, x);
					show[y][x] = count + '0';
					win++;
					spread(mine, show, y, x, &win, row, col);
				}
			}
			break;
		case 's':
			// 扫雷游戏有一个细节:当旗子数与雷数对应就不可插旗了
			if (show[y][x] == '*' && FCount < getMineCount) 
				show[y][x] = 'F';
			break;
		case 'd':
			if (show[y][x] == 'F')
				show[y][x] = '*';
			break;
		case 'f':
			if (show[y][x] >= '1' && show[y][x] <= '7')
				numberSpread(mine, show, y, x, show[y][x] - '0', &win, row, col);
			break;
		case 0x48: // 向下移动
			if (y > 1) // y大于1
				y = y - 1;
			else
				y = row; // y不大于1直接转到row
			break;
		case 0x50: // 向上移动
			if (y < row) // y小与row
				y = y + 1;
			else
				y = 1; // y等于row直接转到1
			break;
		case 0x4b: // 向左移动
			if (x > 1) 
				x = x - 1; 
			else
				x = col; // x不大于1直接转到col
			break;
		case 0x4d: // 向右移动
			if (x < col)
				x = x + 1;
			else
				x = 1; // x等于col直接转到1
			break;
		case 27:
			system("cls");
			return ;
		}
	}
	if (win == row * col - getMineCount)
	{
		printf("**********************\n");
		printf("******  你赢了  ******\n");
		printf("**********************\n");
		printf("按任意键返回:>\n");
		char winTime = _getch();
		system("cls");
	}
	else
	{
		display(mine, row, col, y, x, &time1);
		printf("**********************\n");
		printf("**很遗憾,你被炸死了**\n");
		printf("**********************\n");
		printf("按任意键返回:>\n");
		char falseTime = _getch();
		system("cls");
	}
}

void spread(char** mine, char** show, int y, int x, int* win, int row, int col)
{
	if (show[y][x] == '0')       // 若周围没有雷才进入
	{
		for (int i = -1; i <= 1; i++) // 行
		{
			for (int j = -1; j <= 1; j++) // 列
			{
				if (y + i >= 1 && y + i <= row && x + j >= 1 && x + j <= col) // 防止超出9×9的范围
				{
					if (show[y + i][x + j] == '*')        // 防止反复递归同一个坐标
					{
						int count = mineCount(mine, y + i, x + j);
						show[y + i][x + j] = count + '0'; // 将已经递归过的坐标显示它周围雷的数量,防止反复递归同一个坐标
						(*win)++;     // 增加查找非雷坐标的数量
						spread(mine, show, y + i, x + j, win, row, col); // 进入下一次递归
					}
				}
			}
		}
	}
}

void numberSpread(char** mine, char** show, int y, int x, int num, int* win, int row, int col)
{
	int unknown = 0;     // 未知坐标的数量
	int unknownBlank = 0;// 未知坐标且未插旗的数量
	int FCount = 0;		 // 插旗坐标的数量
	// 记录周围三者的数量
	for (int i = -1; i <= 1; i++)
	{
		for (int j = -1; j <= 1; j++)
		{
			if (show[y + i][x + j] == '*' || show[y + i][x + j] == 'F')
				unknown++;
			if (show[y + i][x + j] == 'F')
				FCount++;
			if (show[y + i][x + j] == '*')
				unknownBlank++;
		}
	}

	if (unknown > num && FCount >= num && unknownBlank != 0) // 周围未知的坐标的数量要大于周围雷的数量
	{
		for (int i = -1; i <= 1; i++) // 行
		{
			for (int j = -1; j <= 1; j++) // 列
			{
				// 防止进入边框坐标
				if (y + i >= 1 && y + i <= row && x + j >= 1 && x + j <= col)
				{
					// 数字展开时扫到雷
					if (show[y + i][x + j] == '*' && mine[y + i][x + j] == '1')
					{
						(*win) = -9;
					}
					// 数字展开扫到非雷
					else if (show[y + i][x + j] == '*' && mine[y + i][x + j] == '0')
					{
						int count = mineCount(mine, y + i, x + j);
						show[y + i][x + j] = count + '0';
						(*win)++;
						spread(mine, show, y + i, x + j, win, row, col);
					}
				}
			}
		}
	}
}

char** apply(int* rows, int* cols)
{
	// 申请二级指针(二维数组)行的数量
	char** arr = (char**)malloc(sizeof(char*) * (*rows));
	if (NULL == arr)
	{
		printf("游戏异常,已退出\n");
		exit(-1);
	}

	// 申请每行之中列的数量
	for (int i = 0; i < *rows; i++)
	{
		arr[i] = (char*)malloc(sizeof(char) * (*cols));
		if (NULL == arr[i])
		{
			printf("游戏异常,已退出\n");
			exit(-1);
		}
	}

	// 返回首元素地址
	return arr;
}

void release(char** arr, int rows, int cols)
{
	// 先释放一级指针空间
	for (int i = 0; i < rows; i++)
		free(arr[i]);
	// 后释放二级指针的空间
	free(arr);
}

int getMine(int num)
{
	switch (num)
	{
	case 1:
		return 10;
	case 2:
		return 40;
	case 3:
		return 99;
	case 4:
		return myGetMine();
	}
	return 0;
}

void myApply(int* rows, int* cols)
{
	printf("***********************************************\n");
	printf("****************** 提前声明:******************\n");
	printf("*自定义行和列建议至少全部都大于3,否者后果自负*\n");
	printf("***********************************************\n");
	printf("请输入行数:>");
	scanf("%d", rows);
	getchar();
	if (*rows < 1)
	{
		*rows = 4;
		printf("行数小于1,自动改成4行\n");
	}
	printf("请输入列数:>");
	scanf("%d", cols);
	getchar();
	if (*cols < 1)
	{
		*cols = 4;
		printf("列数小于1,自动改成4列\n");
	}
	(*rows) = (*rows) + 2;
	(*cols) = (*cols) + 2;
}

int myGetMine()
{
	int n = 0;
	printf("***********************************************\n");
	printf("****************** 提前声明:******************\n");
	printf("******自定义雷的数量建议最多:行 × 列 - 9 *****\n");
	printf("*****************否者后果自负******************\n");
	printf("请布置雷的数量:>");
	scanf("%d", &n);
	getchar();
	if (n < 0)
	{
		printf("数量小于1,改为0");
		n = 0;
	}
	return n;
}

程序展示:

petal_20231221_221540

结语

以上便是所有内容,若文章有错误或游戏有Bug,请联系我,我会及时更改。

谢谢观看文章来源地址https://www.toymoban.com/news/detail-783543.html

到了这里,关于C语言伪图形与键盘操作加扫雷实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言实战——扫雷游戏

    1.1扫雷游戏的功能说明 使用控制台实现经典的扫雷游戏 游戏可以通过菜单实现继续玩或者退出游戏 扫雷的棋盘是9*9的格子 默认随机布置10个雷 可以排查雷 如果位置不是雷,就显示周围有几个雷 如果位置是雷,就炸死游戏结束 把除10个雷之外的所有⾮雷都找出来,排雷成功

    2024年03月15日
    浏览(47)
  • 【C语言】实现扫雷游戏

    详细介绍扫雷游戏的思路和实现过程,并用随机数实现埋雷。 • 使用控制台实现经典的扫雷游戏 • 游戏可以通过菜单实现继续玩或者退出游戏 • 扫雷的棋盘是9*9的格⼦ • 默认随机布置10个雷 • 可以排查雷 ◦ 如果位置不是雷,就显示周围有几个雷 ◦ 如果位置是雷,就炸

    2024年02月04日
    浏览(45)
  • C语言(扫雷游戏)

                          Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~                              💥 个人主页 :小羊在奋斗                         💥 所属专栏 :C语言             本

    2024年04月23日
    浏览(33)
  • C语言扫雷小游戏

    扫雷的玩法:在一个9×9(初级)、16×16(中级)、16×30(高级)或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个),再由玩家逐个翻开方块,翻开的地方将显示周围八个雷的个数。以找出所有地雷为最终游戏目标。如果玩家翻开的方块

    2024年02月05日
    浏览(61)
  • 扫雷小游戏【C语言】

    目录 前言 一、基本实现逻辑 二、实现步骤 1. 我们希望在进入游戏时有一个菜单让我们选择 2. 我们希望可以重复的玩(一把玩完了还可以接着玩) 3. 采用多文件形式编程  4.要扫雷先得有棋盘(创建棋盘R*N) 5.初始化棋盘  6.打印棋盘 7.设置雷 8.排查雷 三、全部源码: 上期

    2024年02月11日
    浏览(62)
  • C语言:扫雷小游戏

    文接上一篇博文C语言:三子棋小游戏。本篇博文是使用C语言来实现扫雷小游戏的。这里不对扫雷的规则进行赘述。玩家通过键盘输入坐标来探雷。博主在实现扫雷之前从未看过扫雷实现的相关视频,所以这里实现的扫雷完全是博主的原生思路,具有逻辑性。下面详细介绍一

    2024年02月09日
    浏览(62)
  • C语言小游戏——扫雷

            结合前边我们所学的C语言知识,本期我们将使用C语言实现一个简单的小游戏——扫雷 目录 前言 总体框架设计 多文件分装程序 各功能模块化实现 初始化棋盘  棋盘打印 埋雷  判赢与排雷 游戏逻辑安排 总结         和三子棋相同,游戏开始时不需要任何判

    2024年02月06日
    浏览(54)
  • 扫雷游戏的实现(C语言)

    对于扫雷游戏,大家应该都很熟悉吧,下面让我们来看看它是如何实现的。 目录 一、游戏规则及设计思想 二、各功能的代码实现 1.创建菜单 2、主函数的实现  3、创建棋盘并初始化 4、打印棋盘  5、布置雷的位置 (埋雷) 6、排查雷   三、代码汇总 1、game.h文件 2、game.c文

    2024年02月03日
    浏览(38)
  • 初阶c语言:趣味扫雷游戏

    目录 前言  制作菜单 构建游戏选择框架 实现游戏功能 模块化编程:查看前节三子棋的内容 初始化雷区 ​编辑 优化棋盘 随机埋入地雷 点击后的决策  实现此功能代码 game();的安排   《扫雷》是一款大众类的益智小游戏,于1992年发行。游戏目标是在最短的时间内根据点

    2024年02月11日
    浏览(38)
  • c语言小游戏之扫雷

    目录 一:游戏设计理念及思路 二:初步规划的游戏界面 三:开始扫雷游戏的实现 注:1.创建三个文件,test.c用来测试整个游戏的运行,game.c用来实现扫雷游戏的主体,game.h用来函数声明和包含头文件 2.为方便定位坐标,在展示数组时添加行号和列号 四:谢谢观看  听说看到

    2024年01月23日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包