C++扫雷

搞OI打代码闲暇时间的小作品 2019 / 6 / 11

Windows 10环境下需要将cmd环境改为旧版命令行环境
#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#define N 135
using namespace std;

HANDLE hOut, hIn;
INPUT_RECORD mouseRec;
DWORD res, mode;

//boom_map, opened_map, marked_map
bool bm[N][N], od[N][N], md[N][N];
int im[N][N], mcnt, ocnt;

bool sub_end, fal_end;
int n = 15, boom, blank;

//cursor_position ==> map_position
struct m_pos{ int x, y; } mp;

bool get_mp(COORD *c_pos) {
	if(c_pos -> X & 1) {
		mp.y = c_pos -> X >> 1;
		mp.x = c_pos -> Y - 1;
		if(mp.x < n && mp.y < n) return 0;
	} return 1;
}

/**
		地雷密度::
				______初级:					0.12345679
				______中级:					0.15625
				______高级:					0.20625
*/
const char* difcc[] = {"简单", "中等", "困难"};
const double difity[] = {0.12345679, 0.15625, 0.20625};
int dif = 0;	//难度

void cls() {
	system("cls");
	SetConsoleMode(hIn, mode);
}

void draw(short y, int len, char ch) {
	SetConsoleCursorPosition(hOut, COORD{0, y});
	printf("		");
	while(len--) putchar(ch);
}

int choose(int num, const char* title, const char* choices[]) {
	cls();
	printf("	%s:\n\n", title);
	for(int i = 0;i < num;i++)
		printf("		%s\n\n", choices[i]);
	
	int id = -1, len = 0;
	short ly = 0, y = 0;
	while(1) {
			ReadConsoleInput(hIn, &mouseRec, 1, &res);
			y = mouseRec.Event.MouseEvent.dwMousePosition.Y;
			if(!(y & 1)) {
				id = (y >> 1) - 1;
				if(!(~id && id < num)) continue;
				if(ly != y) {
					draw(ly + 1, len, ' ');
					ly = y;
					len = strlen(choices[id]);
					draw(y + 1, len, '~');
				}
				if(mouseRec.Event.MouseEvent.dwEventFlags == 0)
					if(mouseRec.Event.MouseEvent.dwButtonState == 1)
						return id;
			}
	}
}

void show() {
	cls();
	printf("共有%d个炸弹,还剩%d个.\n", boom, boom - mcnt);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (md[i][j]) putchar(' '), putchar('X');
			else if(!od[i][j]) putchar(' '), putchar('#');
			else if(!im[i][j]) putchar(' '), putchar(' ');
			else printf(" %d", im[i][j]);
		} putchar('\n');
	}
}

void show_all() {
	cls();
	printf("	Map:\n");
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (bm[i][j]) putchar(' '), putchar('*');
			else if(!im[i][j]) putchar(' '), putchar(' ');
			else printf(" %d", im[i][j]);
		} putchar('\n');
	}
}

void reset() {
	memset(bm, 0, sizeof(bm));
	memset(od, 0, sizeof(od));
	memset(md, 0, sizeof(md));
	memset(im, 0, sizeof(im));
	boom = n * n * difity[dif];
	blank = n * n - boom;
	fal_end = sub_end = 0;
	mcnt = ocnt = 0;
	mp = m_pos{0, 0};
}

void c_map() {
	reset();
	m_pos ls;
	for (int cnt = 0;cnt < boom;) {
		ls.x = rand() % n;
		ls.y = rand() % n;
		if (!bm[ls.x][ls.y]) {
			bm[ls.x][ls.y] = 1;
			for (int i = max(ls.x - 1, 0); i < min(ls.x + 2, n); i++)
				for (int j = max(ls.y - 1, 0); j < min(ls.y + 2, n); j++)
					im[i][j]++;
			cnt++;
		}
	}
	show();
}

void start() {
	putchar('.');
	srand(time(NULL));
	putchar('.');
	hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	putchar('.');
	hIn = GetStdHandle(STD_INPUT_HANDLE);
	putchar('.');
	GetConsoleMode(hIn, &mode);
	putchar('.');
	mode |= ENABLE_MOUSE_INPUT;
	putchar('.');
}

void end() {
	sub_end = 1;
	show_all();
	Sleep(2000);
}

void win() {
	end();
	static const char* cwin[] = {"再来一次", "我已经很满足了"};
	if(choose(2, "你赢了", cwin)) fal_end = 1;
}

void fail() {
	end();
	static const char* clse[] = {"我不甘心", "没意思"};
	if(choose(2, "你输了", clse)) fal_end = 1;
}

void ez(int x, int y) {
	for (int i = max(x - 1, 0); i < min(x + 2, n); i++)
		for (int j = max(y - 1, 0); j < min(y + 2, n); j++)
			if (!od[i][j]) {
				od[i][j] = 1;
				ocnt++;
				if (!im[i][j]) ez(i, j);
			}
}

void open() {
	if(md[mp.x][mp.y] || od[mp.x][mp.y]) return;
	if(bm[mp.x][mp.y]) {
		fail();
		return;
	} else {
		od[mp.x][mp.y] = 1;
		ocnt++;
		if(!im[mp.x][mp.y]) ez(mp.x, mp.y);
	}
	if(ocnt == blank) {
		win();
		return;
	}
	show();
}

void mark() {
	if(od[mp.x][mp.y]) return;
	md[mp.x][mp.y] = !md[mp.x][mp.y];
	if(md[mp.x][mp.y]) mcnt++;
	else mcnt--;
	show();
}

void dset() {
	cls();
	static char difc[30];
	sprintf(difc, "难度设置(目前难度:%s)", difcc[dif]);
	dif = choose(3, difc, difcc);
}

void nset() {
	cls();
	printf("目前地图大小: %d\n", n);
	printf("请输入一个合法的值(10 ~ %d): ", N - 5);
	int ls;
	scanf("%d", &ls);
	if(10 <= ls && ls <= N - 5) {
		n = ls;
		return;
	}
	printf("非法的值!");
	Sleep(1000); 
	exit(0);
} 

void main_page() {
	while(1) {
		cls();
		static const char* menu[] = {"开始", "难度设置", "地图大小", "退出"};
		int cres = choose(4, "Mine_Sweeping", menu);
		switch(cres) {
			case 0: {
				return;
				break;
			}
			case 1: {
				dset();
				break;
			}
			case 2: {
				nset();
				break;
			}
			case 3: {
				exit(0);
				break;
			}
		} 
	}
	
}

int main() {
	printf("	Loading, please wait");
	start();
	while(1) {
		main_page();
		while(1) {
			c_map();
			while(1) {
				ReadConsoleInput(hIn, &mouseRec, 1, &res);
				//SetConsoleCursorPosition(hOut, mouseRec.Event.MouseEvent.dwMousePosition);
				if(mouseRec.Event.MouseEvent.dwEventFlags == 0) {
					if(!get_mp(&mouseRec.Event.MouseEvent.dwMousePosition)) {
						switch(mouseRec.Event.MouseEvent.dwButtonState) {
							case 1: {
								open();
								break;
							} 
							case 2: {
								mark();
								break;
							}
						}
					} 
				} if(sub_end) break;
			} if(fal_end) break;
		}
	}
	return 0;
}

/*
*	program name:	mine_sweeping
*	programmer:		saxiy
*	lastest update:	2019/6/11
*/
版权声明:
  • 允许自由转载和使用,但必须保留作者信息及出处

© saxiy 2019.6.11 保留所有权利

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值