C语言项目合集

sleeeeeping / 2024-07-05 / 原文

五子棋

#include <stdio.h>
#include <getch.h>
#include <stdbool.h>
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1};
char g[25][25];
void print() {
	system("clear");
	for (int i = 0; i < 15; ++i) {
		for (int j = 0; j < 15; ++j) {
			printf("%c ", g[i][j]);
		}
		puts("");
	}
}
bool win(int x, int y, char c) {
	int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
	for (int i = -2; i <= 2; ++i) if (x + i >= 0 && x + i < 15) {
		c1 += g[x + i][y] == c;
	}
	for (int i = -2; i <= 2; ++i) if (y + i >= 0 && y + i < 15) {
		c2 += g[x][y + i] == c;
	}
	for (int i = -2; i <= 2; ++i) if (y + i >= 0 && y + i < 15 && x + i >= 0 && x + i < 15) {
		c3 += g[x + i][y + i] == c;
	}
	for (int i = -2; i <= 2; ++i) if (x + i >= 0 && x + i < 15 && y - i <= 0 && y - i < 15) {
		c4 += g[x + i][y - i] == c;
	}
	return c1 == 5 || c2 == 5 || c3 == 5 || c4 == 5;
}
bool check() {
	for (int i = 0; i < 15; ++i) {
		for (int j = 0; j < 15; ++j) if (g[i][j] != '*') {
			if (win(i, j, g[i][j])) {
				return false;
			}
		}
	}
	return true;
}
int main() {
	memset(g, '*', sizeof g);
	print();
	int idx = 0, px = 1, py = 1;
	while (check()) {
		printf("\33[%d;%dH", px + 1, py * 2 + 2);
		while (true) {
			int get = getch() - 183;
			if (get + 183 == 10) {
				if (g[px][py] != '*') {
					print();
					printf("该位置上已经落子,请重下\n");
					continue;
				}
				g[px][py] = '0' + idx % 2;
				print();
				break;
			} else {
				px += dx[get], py += dy[get];
				if (px < 0) px = 0;
				if (py < 0) py = 0;
				if (px > 15) px = 14;
				if (py > 15) py = 14;
			}
			printf("\33[%d;%dH", px + 1, py * 2 + 2);
		}
		idx += 1;
	}
	if (idx % 2 == 1) {
		printf("黑子赢啦,共用%d步\n", idx / 2 + 1);
	} else {
		printf("白子赢啦,共用%d步\n", idx / 2);
	}
}

2048

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getch.h>
#include <string.h>
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1};
int d[4][4];
bool ok = false;
void print() {
	system("clear");
	for (int i = 0; i < 9; ++i) {
		if (i % 2 == 0) {
			puts("-----------------------------");
		} else {
			for (int j = 0; j < 4; ++j) if (d[i / 2][j] != 0) {
				printf("|%6d", d[i / 2][j]);
			} else {
				printf("|      ");
			}
			printf("|\n");
		}
	}
}
bool check() {
	int cnt = 0;
	ok = false;
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < 4; ++j) {
			cnt += d[i][j] == 0;
			for (int dir = 0; dir < 4; ++dir) {
				int fx = i + dx[dir], fy = j + dy[dir];
				if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && d[fx][fy] == d[i][j] && d[i][j]) {
					ok = true;
					return true;
				}
			}
		}
	}
	return cnt != 0;
}
void get() {
	if (ok) {
		return ;
	}
	int w = rand() % 2;
	w = 1 << w + 1;
	int x = rand() % 4, y = rand() % 4;
	while (d[x][y] != 0) {
		x = rand() % 4, y = rand() % 4;
	}
	d[x][y] = w;
}
int move() {
	int dir = getch() - 183, score = 0;
	int cpd[4][4], cp[4][4];
	memcpy(cp, d, sizeof d);
	if (dir == 0) {
		for (int j = 0; j < 4; ++j) {
			for (int k = 0; k < 4; ++k) {
				for (int i = 1; i < 4; ++i) if (d[i - 1][j] == 0 && d[i][j]) {
					d[i - 1][j] ^= d[i][j] ^= d[i - 1][j] ^= d[i][j];
				}
			}
		}
		memcpy(cpd, d, sizeof d);
		for (int j = 0; j < 4; ++j) {
			for (int i = 0; i < 4; ++i) {
				int fx = dx[dir] + i, fy = dy[dir] + j;
				if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
					d[fx][fy] += d[i][j];
					d[i][j] = 0;
					score += d[fx][fy];
				}

			}
		}
		for (int j = 0; j < 4; ++j) {
			for (int k = 0; k < 4; ++k) {
				for (int i = 1; i < 4; ++i) if (d[i - 1][j] == 0 && d[i][j]) {
					d[i - 1][j] ^= d[i][j] ^= d[i - 1][j] ^= d[i][j];
				}
			}
		}
	} else if (dir == 1) {
		for (int j = 3; j >= 0; --j) {
			for (int k = 0; k < 4; ++k) {
				for (int i = 2; i >= 0; --i) if (d[i + 1][j] == 0 && d[i][j]) {
					d[i + 1][j] ^= d[i][j] ^= d[i + 1][j] ^= d[i][j];
				}
			}
		}
		memcpy(cpd, d, sizeof d);
		for (int j = 3; j >= 0; --j) {
			for (int i = 3; i >= 0; --i) {
				int fx = dx[dir] + i, fy = dy[dir] + j;
				if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
					d[fx][fy] += d[i][j];
					d[i][j] = 0;
					score += d[fx][fy];
				}
			}
		}
		for (int j = 3; j >= 0; --j) {
			for (int k = 0; k < 4; ++k) {
				for (int i = 2; i >= 0; --i) if (d[i + 1][j] == 0 && d[i][j]) {
					d[i + 1][j] ^= d[i][j] ^= d[i + 1][j] ^= d[i][j];
				}
			}
		}
	} else if (dir == 2) {
		for (int i = 3; i >= 0; --i) {
			for (int k = 0; k < 4; ++k) {
				for (int j = 2; j >= 0; --j) if (d[i][j + 1] == 0 && d[i][j]) {
					d[i][j + 1] ^= d[i][j] ^= d[i][j + 1] ^= d[i][j];	
				}
			}
		}
		memcpy(cpd, d, sizeof d);
		for (int i = 3; i >= 0; --i) {
			for (int j = 3; j >= 0; --j) {
				int fx = dx[dir] + i, fy = dy[dir] + j;
				if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
					d[fx][fy] += d[i][j];
					d[i][j] = 0;
					score += d[fx][fy];
				}
			}
		}
		for (int i = 3; i >= 0; --i) {
			for (int k = 0; k < 4; ++k) {
				for (int j = 2; j >= 0; --j) if (d[i][j + 1] == 0 && d[i][j]) {
					d[i][j + 1] ^= d[i][j] ^= d[i][j + 1] ^= d[i][j];
				}
			}
		}
	} else if (dir == 3) {
		for (int i = 0; i < 4; ++i) {
			for (int k = 0; k < 4; ++k) {
				for (int j = 1; j < 4; ++j) if (d[i][j - 1] == 0 && d[i][j]) {
					d[i][j - 1] ^= d[i][j] ^= d[i][j - 1] ^= d[i][j];
				}
			}
		}
		memcpy(cpd, d, sizeof d);
		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 4; ++j) {
				int fx = dx[dir] + i, fy = dy[dir] + j;
				if (fx >= 0 && fy >= 0 && fx < 4 && fy < 4 && cpd[fx][fy] == cpd[i][j] && cpd[fx][fy]) {
					d[fx][fy] += d[i][j];
					d[i][j] = 0;
					score += d[fx][fy];
				}
			}
		}
		for (int i = 0; i < 4; ++i) {
			for (int k = 0; k < 4; ++k) {
				for (int j = 1; j < 4; ++j) if (d[i][j - 1] == 0 && d[i][j]) {
					d[i][j - 1] ^= d[i][j] ^= d[i][j - 1] ^= d[i][j];
				}
			}
		}
	}
	ok = true;
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < 4; ++j) if (cp[i][j] != d[i][j]) {
			ok = false;
		}
	}
	return score;
}
int main() {
	srand(time(0));
	get(), print();
	int score = 0, idx = 0;
	while (check()) {
		idx += 1, score += move();
		get(), print();
	}
	printf("游戏已经结束,您的得分是%d, 共用了%d步\n", score, idx);
}

电子通讯录

#include <stdio.h>
#include <stdbool.h>
#include <getch.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
char name[100][20], sex[100], tel[100][12];
size_t count = 0;
time_t sec = 2.2; // 提示信息显示时间
void clear_stdin() {
	stdin->_IO_read_ptr = stdin->_IO_read_end;
}
char get_op(const char start, const char end) {
	clear_stdin();
	printf("请输入指定选项[%c,%c]\n", start, end);
	while (true) {
		char op = getch();
		if (start <= op && op <= end) {
			printf("%c\n", op);
			return op;
		}
	}
}
char* get_str(char* str, size_t size) {
	clear_stdin();
	size_t len = strlen(fgets(str, size, stdin));
	if (str[len - 1] == '\n') str[len - 1] = '\0';
	return str;
}
char* sex_to_get(const char sex) {
	if (sex == 'w' || sex == 'W') {
		return "女";
	} else if (sex == 'm' || sex == 'M') {
		return "男";
	}
	return "性别未知";
}
char get_sex() {
	clear_stdin();
	printf("请输入性别(w女/m男):");
	while (true) {
		char sex = getch();
		if ('w' == sex || 'W' == sex || 'm' == sex || 'M' == sex) {
			printf("%s\n", sex_to_get(sex));
			return sex;
		}
	}
}
void put_str(const char* msg, float sec) {
	printf("%s\n", msg);
	usleep(1000000 * sec);
}
void anykey_continue() {
	clear_stdin();
	printf("请按任意键继续...");
	getch();
}
char menu() {
	system("clear");
	puts("===欢迎使用电子通讯录===");
	puts("1、添加          2、删除");
	puts("3、修改          4、查询");
	puts("5、遍历          6、退出");
	puts("========================");
	return get_op('1', '6');
}
void add() {
	if (count >= 100) {
		put_str("通讯录人数已满!", sec);
		return ;
	}
	for (int i = 0; i < 100; ++i) if (sex[i] == 0) {
		printf("请输入新联系人姓名:");
		get_str(name[i], sizeof name[0]);						
		sex[i] = get_sex();
		printf("请输入新联系人电话:");
		get_str(tel[i], sizeof tel[0]);
		put_str("添加联系人成功!",sec);
		count += 1;
		return ;
	}
}
void del() {
	if (count == 0) {
		put_str("通讯录为空!", sec);
		return ;
	}
	char key[20];
	printf("请输入想要删除的联系人姓名:");
	get_str(key, sizeof key);
	for (int i = 0; i < 100; ++i) if (sex[i]) {
		if (strcmp(key, name[i])) {
			printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
			sex[i] = 0;
			count -= 1;
			put_str("删除成功!", sec);
			return ;
		}
	}
	put_str("查无此人删除失败!", sec);
}
void modify() {
	if (count == 0) {
		put_str("通讯录为空!", sec);
		return ;
	}	
	char key[20];
	printf("请输入想要修改的联系人姓名:");
	get_str(key, sizeof key);
	for (int i = 0; i < 100; ++i) if (sex[i]) {
		if (strcmp(name[i], key) == 0) {	
			printf("请输入新的联系人姓名:");
			get_str(name[i], sizeof name[0]);						
			sex[i] = get_sex();
			printf("请输入新的联系人电话:");
			get_str(tel[i], sizeof tel[0]);
			put_str("修改联系人成功!",sec);
			return ;
		} 
	}
	put_str("查无此人删除失败!", sec);
}
void query() {
	char key[20];
	printf("请输入要查询的关键字:");
	get_str(key, sizeof key);
	bool suc = false;
	for (int i = 0; i < 100; ++i) if (sex[i]) {
		if (strstr(name[i], key) != NULL && strstr(tel[i], key) != NULL) {
			suc = true;
			printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
		}
	}
	if (suc) {
		anykey_continue();
	} else {
		put_str("查无此人!", sec);
	}
}
void show() {
	if (count == 0) {
		put_str("暂无联系人...",sec);
		return ;	
	}
	for (int i = 0; i < 100; ++i) if (sex[i]) {
		printf("%s %s %s\n", name[i], sex_to_get(sex[i]), tel[i]);
	}
	anykey_continue();
}
int main() {
	while (true) {
		int op = menu() - '0';
		if (op == 1) {
			add();
		} else if (op == 2) {
			del();
		} else if (op == 3) {
			modify();
		} else if (op == 4) {
			query();
		} else if (op == 5) {
			show();
		} else {
			break;
		}
	}	
}

某个系统的用户管理模块

#include <stdio.h>
#include <getch.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
typedef struct User {
	int id;
	char name[20], password[21], phone[12];
} User;
User users[100];
size_t cnt;
time_t msg_show_sec = 20.2; // 提示信息显示时间
int lg_index; // 登录成功的下标
void clear_stdin() {
	stdin->_IO_read_ptr = stdin->_IO_read_end;
}
char get_op(const char start, const char end) {
	clear_stdin();
	printf("请输入指定选项[%c,%c]\n", start, end);
	while (true) {
		char op = getch();
		if (start <= op && op <= end) {
			printf("%c\n", op);
			return op;
		}
	}
}
char* get_str(char* str, size_t size) {
	clear_stdin();
	size_t len = strlen(fgets(str, size, stdin));
	if (str[len - 1] == '\n') str[len - 1] = '\0';
	return str;
}
char* get_passwd(char* pwd, size_t size, bool is_show) {
	clear_stdin();
	size_t index = 0;
	while (index < size - 1) {
		pwd[index] = getch();
		if (pwd[index] == '\n') break;
		if (pwd[index] == 127) {
			if(index > 0) {
				index--;
				if(is_show) {
					printf("\b \b");//抹除一个显示字符
				}
			}
			continue;
		}
		if (is_show) {
			printf("*");
		}
		index++;
	}
	pwd[index] = '\0';
	printf("\n");
	return pwd;
}
int get_id(int len) {
	char* str = "0123456789";
	int id = str[rand() % 9 + 1] - '0';
	for (int i = 1; i < len; ++i) {
		id = id * 10 + str[rand() % 10] - '0';
	}
	return id;
}
void put_str(const char* msg, float sec) {
	printf("%s\n", msg);
	usleep(1000000 * sec);
}
void anykey_continue() {
	clear_stdin();
	printf("请按任意键继续...");
	getch();
}
int binary_search(int x) {
	int l = 0, r = cnt - 1;
	while (l < r) {
		int mid = l + r >> 1;
		if (users[mid].id < x) {
			l = mid + 1;
		} else {
			r = mid;
		}
	}
	return users[r].id == x ? r : -1;
}
void swap(User *x, User *y) {
	User temp = *x;
	*x = *y;
	*y = temp;
}
void quick_sort(User *q, int l, int r) {
	if (l >= r) return ;
	int i = l - 1, j = r + 1;
	int x = q[l + r >> 1].id;
	while (i < j) {
		do i++; while (q[i].id < x);
		do j--; while (q[j].id > x);
		if (i < j) swap(&q[i], &q[j]);
	}
	quick_sort(q, 1, j);
	quick_sort(q, j + 1, r);
}

char menu() {
	system("clear");
	puts("============用户登录=============");
	puts("1.用户注册         2.用户登录    ");
	puts("3.重置密码         4.遍历所有用户");
	puts("5.退出系统                       ");
	puts("=================================");
	return get_op('1', '5');
}
void sign_user() {
	if (cnt >= 100) {
		put_str("系统正在升级,暂停注册!", msg_show_sec);
		return;
	}
	while (true) {	
		users[cnt].id = get_id(8);
		if (binary_search(users[cnt].id) == -1) {
			break;
		}
	}
	printf("请输入昵称:");
	get_str(users[cnt].name,sizeof users[cnt].name);			
	printf("请输入手机号:");
	get_str(users[cnt].phone,sizeof users[cnt].phone);
	while (true) {
		printf("请输入密码(6~19位):");
		get_passwd(users[cnt].password, sizeof users[cnt].password, true);
		size_t len = strlen(users[cnt].password);
		if(6 > len) {
			printf("密码长度不足6位,请重新输入\n");
		} else break;
	}
	char pass_2[20] = {};
	printf("请确认密码:");
	get_passwd(pass_2, sizeof pass_2, true);
	if (strcmp(users[cnt].password,pass_2) != 0) {
		put_str("两次密码不同,注册失败\n", msg_show_sec);
		return;
	}
	quick_sort(&users, 0, cnt);
	cnt += 1;
	anykey_continue();
}
char menu_login() {
	system("clear");
	printf("===========欢迎%s登录系统===========\n", users[lg_index].name);
	puts("1.查看信息       2.修改信息");
	puts("3.修改密码       4.退出登录");
	return get_op('1', '4');
}
void show_user_info() {
	printf("%d %s %s %s\n",
			users[lg_index].id,
			users[lg_index].name,
			users[lg_index].password,
			users[lg_index].phone);
	anykey_continue();
}
void modify_user() {
	puts("=====请输入要修改的信息=====");
	puts("1.修改昵称      2.修改手机号");
	if (get_op('1', '2') - '0' == 1) {
		printf("请输入新的昵称:");
		get_str(users[lg_index].name, sizeof users[lg_index].name);
	} else {
		printf("请输入新的手机号:");
		get_str(users[lg_index].phone, sizeof users[lg_index].phone);
	}
	printf("修改后个人信息:\n");
	show_user_info();
}
void modify_password() {
	char pass[20];
	printf("请输入旧密码:");
	get_passwd(pass, sizeof pass, true);
	if (strcmp(users[lg_index].password, pass)) {
		put_str("密码验证失败,修改退出\n", msg_show_sec);
		return;
	}
	printf("请输入新密码:");
	get_passwd(pass, sizeof pass, true);
	char repass[20];
	printf("请确认密码:");
	get_passwd(repass, sizeof repass, true);
	if (0 == strcmp(pass, repass)) {
		strcpy(users[lg_index].password, pass);
		put_str("修改密码成功\n", msg_show_sec);
		return;
	}
	put_str("两次密码不同,修改失败\n", msg_show_sec);
}
void login_suc() {
	while (true) {
		int op = menu_login() - '0';
		if (op == 1) {
			show_user_info();
		} else if (op == 2) {
			modify_user();
		} else if (op == 3) {
			modify_password();
		} else break;
	}
}
void login_user() {
	int id = 0;
	printf("请输入用户ID:");
	clear_stdin();
	scanf("%d", &id);
	char pass[20];
	printf("请输入用户密码;");
	get_passwd(pass, sizeof pass, true);
	int index = binary_search(id);
	if (index >= 0 && strcmp(pass, users[index].password)) {
		put_str("登录成功\n", msg_show_sec);
		lg_index = index;
		login_suc();
		return; 
	}
	put_str("用户ID或者密码错误,请检查\n", msg_show_sec);
}
void reset_user() {
	clear_stdin();
	int id;
	printf("请输入用户ID:");
	scanf("%d",&id);
	char name[20];
	printf("请输入用户昵称:");
	get_str(name, sizeof name);
	char phone[12];
	printf("请输入用户手机号:");
	get_str(phone,sizeof phone);
	int index = binary_search(id);
	if (index >= 0 && 0 == strcmp(users[index].name,name) 
			&& 0 == strcmp(users[index].phone,phone)) {
		strcpy(users[index].password, "000000");
		put_str("重置密码成功\n", msg_show_sec);
		return;
	}
	put_str("数据信息有误,重置失败\n", msg_show_sec);
}
void show_user() {
	if (cnt <= 0) {
		puts("暂无普通用户!");
		anykey_continue();
		return ;
	}
	for (int i = 0; i < cnt; ++i) {
		printf("ID:%d 昵称:%s \n", users[i].id, users[i].name);
	}
	anykey_continue();
}
int main() {
	srand(time(NULL));
	while (true) {
		int op = menu() - '0';
		if (op == 1) {
			sign_user();
		} else if (op == 2) {
			login_user();
		} else if (op == 3) {
			reset_user();
		} else if (op == 4) {
			show_user();
		} else break;
	}
}

扫雷

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <getch.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
// 地图
#define MAX_ROW 20
#define MAX_COL 30
int map[MAX_ROW][MAX_COL] = {};
#define OPEN 1000
#define MARK 100
// 根据data这个值来判断当前位置的状态
#define IS_INIT(data) (data >= -1 && data <= 8)
#define IS_OPEN(data) (data >= -1 + OPEN && data <= 8 + OPEN)
#define IS_MARK(data) (data >= -1 + MARK && data <= 8 + MARK)

enum Stat{INIT, PLAY, DEAD, SUCCESS};
enum Stat stat = INIT; // 游戏状态

// 实际的行列和雷数
int row = 16, col = 16, mines = 40;
#define MINE -1
// 记录光标在二维数组中的下标位置
int mx = 7, my = 7;
enum KEY {
	KEY_OPEN = 10, // 用Enter键来表示打开或智能推导
	KEY_SIGN = 32, // 用Space键来表示标记
	KEY_QUIT = 'q', // q退出
	KEY_UP = 183, // 上					
	KEY_DOWN =  184, // 下				
	KEY_RIGHT = 185, // 右
	KEY_LEFT = 186 // 左
};

int aroundMines(int x, int y) {
	int cnt = 0;
	for (int i = x - 1; i <= x + 1; ++i) {
		for (int j = y - 1; j <= y + 1; ++j) {
			if (i >= 0 && i < row && j >= 0 && j < col) {
				cnt += map[i][j] == MINE;
			}
		}
	}
	return cnt;
}

bool checkLayMines(int x, int y) {
	if ((abs(x - mx) > 1 || abs(y - my) > 1) && map[x][y] != -1) return false;
	return true;
}
void layMines() {
	for (int i = 0; i < mines; ++i) {
		int x, y;
		do {
			x = rand() % row, y = rand() % col;
		} while (checkLayMines(x, y));
		map[x][y] = MINE;
	}
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) if (map[i][j] != MINE) {
			map[i][j] = aroundMines(i, j);
		}	
	}
}
void show_init_data() {
	system("clear");
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			printf("%d ", map[i][j]);
		}
		printf("\n");
	}

	printf("\033[%d;%dH\033[0m", mx + 1, my * 2 + 1); // 屏幕的光标位置
}
int init_data(int data) {
	if (IS_INIT(data)) {
		return data;
	}
	if (IS_OPEN(data)) {
		return data - OPEN;
	}
	return data - MARK;
}
void showPlay() {
	system("clear");
	int initCnt = 0, signCnt = 0;
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			// 根据情况显示
			// 如果没有被打开显示#
			// 这个位置如果用户标识地雷显示 &
			// 如果这个位置被打开显示原始数据
			if (IS_INIT(map[i][j])) {
				printf("# ");
				initCnt += 1;
			} else if (IS_OPEN(map[i][j])) {
				int data = init_data(map[i][j]);
				if (data == MINE) {
					printf("\033[31m* \033[0m");
				} else if (data == 0) {
					printf("  ");
				} else {
					printf("%d ", data);
				}	
			} else {
				signCnt += 1;
				printf("& ");
			}
		}
		printf("\n");
	}
	if (initCnt + signCnt == mines) {
		stat = SUCCESS;
	}
	if (stat == SUCCESS) {
		printf("恭喜你,press any key to restart...");
	} else {
		printf("\033[%d;%dH\033[0m", mx + 1, my * 2 + 1); // 屏幕的光标位置
	}
}
void showDead() {
	system("clear");
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			int data = init_data(map[i][j]);
			if (IS_OPEN(map[i][j])) {
				if (data == MINE) {
					printf("\033[31;44m* \033[0m");
				} else if (data == 0) {
					printf("  ");
				} else {
					printf("%d ", data);
				}
			} else if (IS_MARK(map[i][j])) {
				if (data == MINE) {
					printf("& ");
				} else {
					printf("\033[31;45m& \033[0m");
				}
			} else {
				if (data == MINE) {
					printf("\033[31m* \033[0m");
				} else {
					printf("# ");
				}
			}
		}
		printf("\n");
	}
	printf("Sorry, You Fail! Pess any key to restart...\n");
	printf("\033[%d;%dH\033[0m", mx + 1, my * 2 + 1); // 屏幕的光标位置
}
void autoOpen(int x, int y) {
	assert(x >= 0 && x < row && y >= 0 && y < col); 
	if (!IS_INIT(map[x][y])) return ;
	map[x][y] += OPEN;
	if (init_data(map[x][y]) != 0) return ; 
	for (int i = x - 1; i <= x + 1; ++i) {
		for (int j = y - 1; j <= y + 1; ++j) {
			if (i >= 0 && i < row && j >= 0 && j < col) {
				autoOpen(i, j);
			}
		}
	}
}
// 统计(x, y)周围玩家雷的数量
int aroundSignMines(int x, int y) {
	int cnt = 0;
	for (int i = x - 1; i <= x + 1; ++i) {
		for (int j = y - 1; j <= y + 1; ++j) {
			if (i >= 0 && i < row && j >= 0 && j < col) {
				cnt += IS_MARK(map[i][j]);
			}
		}
	}
	return cnt;
}
void openAround(int x, int y) {
	for (int i = x - 1; i <= x + 1; ++i) {
		for (int j = y - 1; j <= y + 1; ++j) {
			if (i >= 0 && i < row && j >= 0 && j < col && IS_INIT(map[i][j])) {
				if (map[i][j] == 0) {
					autoOpen(i, j);
				} else { 
					if (map[i][j] == MINE) { // 根据错误标记推导,打开了雷
						stat = DEAD;
					}
					map[i][j] += OPEN;
				}
			}	
		}
	}
}
void smartDeviration(int x, int y) {
	int signCnt = aroundSignMines(x, y); // 标记地雷的数量
	int mineCnt = init_data(map[x][y]);
	if (signCnt >= mineCnt) {
		openAround(x, y);
	}
}
void open() {
	if (stat == INIT) {
		layMines();
		stat = PLAY;
		open();
	}
	if (IS_INIT(map[mx][my])) {
		if (map[mx][my] == 0) {
			autoOpen(mx, my);
		} else {
			if (map[mx][my] == MINE) {
				stat = DEAD; 
			}
			map[mx][my] += OPEN;
		}
	} else if (IS_OPEN(map[mx][my])) {
		smartDeviration(mx, my);
	}
}	
void sign() {
	if (IS_INIT(map[mx][my])) {
		map[mx][my] += MARK;
	} else if (IS_MARK(map[mx][my])) {
		map[mx][my] -= MARK;
	}
}
// 扫雷
void sweepMine() {
	while (true) {
		if (stat == PLAY || stat == INIT) {
			showPlay();
			if (stat == SUCCESS) return ;
		} else if (stat == DEAD) {
			showDead(); // 显示死亡地图
			getch();
			return ;
		}
		int key = getch();
		if (key == KEY_OPEN) {
			open();
		} else if (key == KEY_SIGN) {
			sign();	
		} else if (key == KEY_QUIT) {
			exit(0);
		} else {
			if (key == KEY_UP) {
				mx -= mx > 0;
			} else if (key == KEY_DOWN) {
				mx += mx + 1 < row;
			} else if (key == KEY_LEFT) {
				my -= my > 0;
			} else if (key == KEY_RIGHT) {
				my += my + 1 < col;
			}
		}
	}
}

void run() {	
	while (true) {
		stat = INIT;
		sweepMine();
		memset(map, 0, sizeof map);
	}
}

int main() {
	srand(time(NULL));
	run();// 程序启动
}

推箱子

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getch.h>
// 关卡数量
#define MAX_LEVEL 3
// 文件名最大长度
#define FILE_NAME_LEN 128
// 地图最大行和列
#define MAX_ROW 15
#define MAX_COL 15

enum BT {
	ROAD = 0, // 可以自由行走的路 空白
	WALL = 1, // 障碍物 墙
	TERM = 2, // 终点 箱子最终要被推放的位置
	MOUSE = 3, // 小老鼠 控制小老鼠移动
	BOX = 4, // 箱子
	// 特殊的物体
	MINT = MOUSE + TERM, // 小老鼠站在终点上
	BINT = BOX + TERM // 箱子被推到终点上
};

// 键值
enum KEY {
	KEY_UP = 183, // 上
	KEY_DOWN =  184, // 下
	KEY_RIGHT = 185, // 右
	KEY_LEFT = 186, // 左
	KEY_RESET = 'r', // 复位
	KEY_QUIT = 'q', // 退出
	KEY_BACK = 'b' // 撤销最新的那一步动作
};

// 枚举类型,用来记录按下一个方向键后可能出现的三种情况
enum ActSts {
	NOTM = -1, // 没有任何东西移动
	ONLYM = 0, // 只有小老鼠移动
	ALLM = 2 // 小老鼠和箱子都移动了
};
typedef struct Act {
	int key; // key 移动的方向
	int bm;  //  bm箱子是否移动
} Act;

// 实际当前地图实际的大小
int row = 0, col = 0;
// 记录小老鼠的坐标位置
int mx = 0, my = 0;
// 地图的数据
int map[MAX_ROW][MAX_COL] = {};
// 箱子的个数
int bcnt = 0;
// 撤销动作时 数据
#define MAX_BACK_STEP 10
Act acts[MAX_BACK_STEP] = {};
int backStep = 0; // 记录目前可以回退的步数
// 加载数据
void load(int level) {
	bcnt = 0, backStep = 0;
	char filename[FILE_NAME_LEN] = {};
	// printf fprintf sprintf
	sprintf(filename, "./map/%d.txt", level); // 格式化输出到字符串中
	//puts(filename);
	// 以只读方式打开文件
	FILE* fp = fopen(filename, "r");
	if (fp == NULL) {
		printf("加载%s地图数据失败!\n", filename);
		exit(-1); // 退出程序
	}
	// 读取文件中的数据 
	// 读取地图的尺寸(行和列)
	if (fscanf(fp, "%d %d", &row, &col) < 2) {
		printf("加载%s地图数据失败!\n", filename);
		fclose(fp);
		exit(-1); 
	}
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			fscanf(fp, "%d", &map[i][j]); // 读取文件中的数据
			if (map[i][j] == BOX || map[i][j] == BINT) {
				bcnt += 1;
			}
			if (map[i][j] == MOUSE || map[i][j] == MINT) {
				mx = i, my = j;
			}
		}
	}
	fclose(fp);
}
// 每次显示地图的时候统计在终点上箱子的个数
int show() { //  打印数据
	/* 原样打印
	printf("row = %d, col = %d\n", row, col);
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			printf("%d%c", map[i][j], " \n"[j == col - 1]);
		}
	}
	*/
	system("clear");
	int tbox = 0;
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			int op = map[i][j];
			if (op == ROAD) {
				printf(" ");
			} else if (op == WALL) {
				printf("#");
			} else if (op == TERM) {
				printf("O");
			} else if (op == BINT || op == BOX) { // box in term
				if (op == BOX) {
					printf("@");
				} else {
					printf("\033[34m@\033[0m"); // \033开启颜色控制 30-39 字体颜色
					tbox += 1;
				}
			} else if (op == MOUSE || op == MINT) { // mouse in term
				if (op == MOUSE) {
					printf("&");
				} else {
					printf("\033[31m&\033[0m"); // \033开启颜色控制 30-39 字体颜色
				}
			}
		}
		printf("\n");
	}
	return tbox;
}

// 移动函数 stepx, stepy方向增量
// NOTM ONLYM ALLM
int move(int stepx, int stepy) {
	int nx = mx + stepx, ny = my + stepy;
	// 所有地图最外面肯定有一圈墙 防止越界
	if (map[nx][ny] == ROAD || map[nx][ny] == TERM) {
		map[mx][my] -= MOUSE; // 小老鼠从(mx, my)离开
		map[nx][ny] += MOUSE; // 小老鼠到达(nx, ny)位置
		mx = nx, my = ny; // 重新记录小老鼠位置
		return ONLYM; // 只有小老鼠移动了
	} else if (map[nx][ny] == BOX || map[nx][ny] == BINT) {
		// 需要考虑箱子前面的坐标
		int nnx = nx + stepx, nny = ny + stepy;
		// 老鼠推着箱子走
		if (map[nnx][nny] == ROAD || map[nnx][nny] == TERM) {
			map[nx][ny] -= BOX;
			map[nnx][nny] += BOX;
			map[mx][my] -= MOUSE;
			map[nx][ny] += MOUSE;
			mx = nx, my = ny;
			return ALLM; // 小老鼠推着箱子移动
		}
	}
	return NOTM; // 没有移动
}
void back(int stepx, int stepy, int bm) {
	int ox = mx - stepx, oy = my - stepy;
	map[mx][my] -= MOUSE; // 老鼠离开现在的位置
	map[ox][oy] += MOUSE; // 老鼠回到原来的位置
	if (bm == ALLM) { // 人和箱子都移动了
		int bx = mx + stepx, by = my + stepy;
		map[bx][by] -= BOX;
		map[mx][my] += BOX;
	}
	mx = ox, my = oy;
}
void moveback() {
	if (backStep > 0) {
		backStep -= 1;
		int key = acts[backStep].key, bm = acts[backStep].bm;
		if (key == KEY_UP) {
			back(-1, 0, bm);
		} else if (key == KEY_DOWN) {
			back(+1, 0, bm);
		} else if (key == KEY_LEFT) {
			back(0, -1, bm);
		} else {
			back(0, +1, bm);
		}
	}
}
// 玩游戏的过程
void play(int level) {
	while (true) {
		if (show() == bcnt) { // 1.显示地图
			printf("恭喜你,通关了, press any key to next level...");
			getch();
			break;
		}
		// 玩家交互
		int key = getch();
		if (key == KEY_RESET) { // 复位
			load(level); // 把地图数据重新加载
		} else if (key == KEY_QUIT) { // 退出游戏
			exit(-1);
		} else if (key == KEY_BACK) { // 返回上一步
			moveback();
		} else {
			int bm = NOTM; // 用于记录动作的结果
			if (key == KEY_UP) {
				bm = move(-1, 0);
			} else if (key == KEY_DOWN) {
				bm = move(+1, 0);
			} else if (key == KEY_LEFT) {
				bm = move(0, -1);
			} else if (key == KEY_RIGHT) {
				bm = move(0, +1);
			}
			if (bm != NOTM) { // 有效的动作
				Act act = {key, bm};
				// 把act有效动作放到全局数组中
				if (backStep < MAX_BACK_STEP) {
					acts[backStep++] = act;
				} else {
					for (int i = 1; i < MAX_BACK_STEP; ++i) {
						acts[i - 1] = acts[i];
					}
					acts[MAX_BACK_STEP - 1] = act;
				}
			}
		}
	}
}
// 推箱子 游戏
void run() { 
	// 闯关形式的
	for (int level = 1; level <= MAX_LEVEL; ++level) {
		// 第level关
		load(level); // 加载level关的地图数据 从文件中加载
		play(level); // 供玩家i闯关
	}
	printf("恭喜闯关成功!\n");
}

// main函数作为程序的入口,一般都不会写业务代码
int main() {
	run();
}

附1:#include "getch.h"头文件

#ifndef GETCH_H
#define GETCH_H

#include <termios.h>
#include <unistd.h>
#include <stdio.h>

// 修改终端的控制方式,1取消回显、确认 2获取数据 3还原
static int getch(void)
{
    // 记录终端的配置信息
    struct termios old;
    // 获取终端的配置信息
    tcgetattr(STDIN_FILENO,&old);
    // 设置新的终端配置   
    struct termios new_1 = old;
    // 取消确认、回显
    new_1.c_lflag &= ~(ICANON|ECHO);
    // 设置终端配置信息
    tcsetattr(STDIN_FILENO,TCSANOW,&new_1);

    // 在新模式下获取数据   
    int key_val = 0; 
    do{
    	key_val += getchar();
    }while(stdin->_IO_read_end - stdin->_IO_read_ptr);

    // 还原配置信息
    tcsetattr(STDIN_FILENO,TCSANOW,&old); 
    return key_val; 
}

#endif//GETCH_H

附2:推箱子地图

地图下载