需要后续版本(丕定有)可以留言催更~
就不贴图了,感兴趣的自己自然会拿来跑的对吧~
/**
* 扫雷极速版!!!
*
* 支持 MSVC,GCC ~ Win32,Linux 平台!
* (初版,部分汉化)
*
* @author Ervoconite
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/**
* cross-platform.h
*/
#ifdef _WIN32
// 以下字符串均为以 GBK 编码的字节串:
const char* clear_cmds = "cls";
const char* title = // 扫雷极速版!!!
"\xc9\xa8\xc0\xd7\xbc\xab\xcb\xd9\xb0\xe6";
const char* circle_c = // ●
"\xa1\xf1";
const char* square_c = // ■
"\xa1\xf6";
const char* e_square_c = // □
"\xa1\xf5";
const char* win_c = // 你赢了
"\xc4\xe3\xd3\xae\xc1\xcb";
const char* over_c = // 游戏结束
"\xd3\xce\xcf\xb7\xbd\xe1\xca\xf8";
const char* prompt_c = // 输入扫雷坐标:
"\xca\xe4\xc8\xeb\xd7\xf8\xb1\xea(\xd0\xd0 \xc1\xd0)";
char overflow[] = // 坐标超出边界
"\xd7\xf8\xb1\xea\xb3\xac\xb3\xf6\xb1\xdf\xbd\xe7 !";
#elif __unix__
// 以下字符串均为以 UTF-8 编码的字节串:
const char* clear_cmds = "clear";
const char* title = // 扫雷极速版!!!
"\xe6\x89\xab\xe9\x9b\xb7\xe6\x9e\x81\xe9\x80\x9f\xe7\x89\x88";
const char* circle_c = // ●
"\xe2\x97\x8f";
const char* square_c = // ■
"\xe2\x96\xa0";
const char* e_square_c = // □
"\xe2\x96\xa1";
const char* win_c = // 你赢了
"\xe4\xbd\xa0\xe8\xb5\xa2\xe4\xba\x86";
const char* over_c = // 游戏结束
"\xe6\xb8\xb8\xe6\x88\x8f\xe7\xbb\x93\xe6\x9d\x9f";
const char* prompt_c = // 输入扫雷坐标:
"\xe8\xbe\x93\xe5\x85\xa5\xe5\x9d\x90\xe6\xa0\x87(\xe8\xa1\x8c \xe5\x88\x97)";
char overflow[] = // 坐标超出边界
"\xe5\x9d\x90\xe6\xa0\x87\xe8\xb6\x85\xe5\x87\xba\xe8\xbe\xb9\xe7\x95"
"\x8c !";
#endif
void initLocale() {
// #include <locale.h>
// #include <wchar.h>
#ifdef _WIN32
// setlocale(LC_ALL, "en_US.UTF8");
#elif __unix__
// setlocale(LC_ALL, "en_US.UTF8");
#else
puts("Unknown operating system.");
exit(1);
#endif
}
void clearScreen() { system(clear_cmds); }
void prompt(char* warning) {
static char tip[] = "Enter(0 0)to exit";
static char* prompt_prefix = (char*)&tip;
if (warning) {
prompt_prefix = warning;
return;
}
printf("%s\n%s: ", prompt_prefix, prompt_c);
prompt_prefix = (char*)&tip;
}
void stepMine() { printf("\n >>> %s! <<<\n", over_c); }
void win() { printf("\n >>> %s! <<<\n", win_c); }
void clearStdin() {
while (getchar() != '\n')
;
}
//
//
//
//
//
//
/**
* game.h
*/
// 地雷记号,改动无效。
#define MINE '*'
// 稀疏度:3最合适,不要超过5,不然容易玩不了。
#define MINE_sparsity 3
// #include "cross-platform.h"
typedef unsigned char byte;
typedef void _;
typedef struct GameBoard {
int size; // 扩展的地图大小,真实地图从1开始到border-1。
int border; // 扩展后的右边框下标,值为size+1。
int min; // 最小下标
int max; // 最大下标
int n_total; // 地图总大小,值为(size-2)*(size-2)。
int n_mine; // 地雷数量
int n_shown; // unveil数量。
byte** map; // 地图,每个元素为地雷或者周围地雷数量。
byte** unveil; // 掀开的点的地图。
byte** tempMap; // 用于搜索算法的缓存。
} Board;
Board createBoard(unsigned size) {
Board board;
board.n_total = size * size;
board.n_mine = board.n_shown = 0;
board.min = 1;
board.max = size;
board.size = board.max + 2;
board.border = board.max + 1;
board.map = (byte**)malloc(board.size * sizeof(byte*));
board.unveil = (byte**)malloc(board.size * sizeof(byte*));
for (int i = 0; i < board.size; i++) {
board.map[i] = (byte*)calloc(board.size, sizeof(byte));
board.unveil[i] = (byte*)calloc(board.size, sizeof(byte));
}
return board;
}
bool isOverFlow(Board* board, int x, int y) {
if (x < board->min || x > board->max || y < board->min || y > board->max)
return true;
else
return false;
}
bool isComplete(Board* board) {
return board->n_mine + board->n_shown >= board->n_total ? true : false;
}
_ cleanTemp(Board* board) {
for (int i = 0; i < board->size; i++) {
memset(board->tempMap[i], 0, board->size * sizeof(byte));
}
}
_ destroyBoard(Board* board) {
for (int i = 0; i < board->size; i++) {
free(board->map[i]);
free(board->unveil[i]);
}
free(board->map);
free(board->unveil);
board->map = board->unveil = NULL;
}
byte __initBoard_surroundings(int i, int j, byte** map) {
byte count = 0;
count += map[i][j - 1] == MINE; // 左 ←
count += map[i][j + 1] == MINE; // 右 →
count += map[i - 1][j] == MINE; // 上 ↑
count += map[i + 1][j] == MINE; // 下 ↓
count += map[i - 1][j - 1] == MINE; // 左上 ↖
count += map[i - 1][j + 1] == MINE; // 左下 ↙
count += map[i + 1][j - 1] == MINE; // 右上 ↗
count += map[i + 1][j + 1] == MINE; // 右下 ↘
return count;
}
_ initBoard(Board* board, int init_x, int init_y) {
// 布置地雷
srand((unsigned)time(NULL));
for (int i = 1; i < board->border; i++) {
for (int j = 1; j < board->border; j++) {
board->map[i][j] =
(rand() % MINE_sparsity ? 0 : (board->n_mine++, MINE));
}
}
// 确保第一次点击的地方不是地雷
if (board->map[init_x][init_y] == MINE) {
board->map[init_x][init_y] = 0;
board->n_mine--;
}
// 确保至少一颗地雷
int x2 = init_x;
while (x2 == init_x) {
x2 = 1 + rand() % board->max;
}
init_y = 1 + rand() % board->max;
if (board->map[x2][init_y] != MINE) {
board->map[x2][init_y] = (board->n_mine++, MINE);
}
// 计算周边
for (int i = 1; i < board->border; i++) {
for (int j = 1; j < board->border; j++) {
if (board->map[i][j] == MINE) continue;
board->map[i][j] = __initBoard_surroundings(i, j, board->map);
}
}
}
_ printBoard(bool inGame, Board* board) {
if (inGame)
clearScreen();
else
puts("");
// 打印顶部坐标轴
printf(" ");
for (int i = 1; i < board->border; i++) {
printf("%2d", i);
}
putchar('\n');
// 横线
printf(" ");
for (int i = 1; i < board->border; i++) {
printf("--");
}
putchar('\n');
// 打印棋盘
for (int i = 1; i < board->border; i++) {
// 左侧坐标轴
printf("%2d|", i);
// 每行
for (int j = 1; j < board->border; j++) {
// 非游戏中,完全打印:
if (!inGame) {
if (board->map[i][j] == MINE) {
printf(" %s", circle_c);
} else if (board->map[i][j] == 0) {
// printf(" %s", e_square_c);
printf(" %c", ' ');
} else {
printf(" %c", board->map[i][j] + '0');
}
}
// 游戏中,按 unveil 打印:
else if (board->unveil[i][j]) {
if (board->map[i][j] == 0)
// printf(" %s", e_square_c);
printf(" %c", ' ');
else
printf(" %c", board->map[i][j] + '0');
} else {
printf(" %s", square_c);
}
}
puts("|");
}
// 横线
printf(" ");
for (int i = 1; i < board->border; i++) {
printf("--");
}
putchar('\n');
}
/** @attention 不能是炸弹,该函数会修改 n_shown */
_ stirUp(Board* board, int x, int y) {
// 搜索连续空白
if (isOverFlow(board, x, y) || board->map[x][y] == MINE) {
return;
}
byte** map = board->map;
byte** unveil = board->unveil;
unveil[x][y] = 1;
board->n_shown++;
// 上 ↑
if (map[x - 1][y] != MINE && unveil[x - 1][y] == 0) stirUp(board, x - 1, y);
// 下 ↓
if (map[x + 1][y] != MINE && unveil[x + 1][y] == 0) stirUp(board, x + 1, y);
// 左 ←
if (map[x][y - 1] != MINE && unveil[x][y - 1] == 0) stirUp(board, x, y - 1);
// 右 →
if (map[x][y + 1] != MINE && unveil[x][y + 1] == 0) stirUp(board, x, y + 1);
}
#define Wins 2
#define OK 1
#define Boom 0
#define Breaks -1
#define OverFlow -2
int sweep(bool first, Board* board) {
int x, y;
prompt(NULL);
int sret = scanf("%d%d", &x, &y);
clearStdin();
if (sret == EOF || (x == y && y == 0)) return Breaks;
if (isOverFlow(board, x, y)) {
return OverFlow;
} else if (first) {
initBoard(board, x, y);
stirUp(board, x, y);
// 判断排完
if (isComplete(board))
return Wins;
else
return OK;
} else if (board->map[x][y] == MINE) {
board->map[x][y] = 'X' - '0';
return Boom;
} else {
stirUp(board, x, y);
// 判断排完
if (isComplete(board))
return Wins;
else
return OK;
}
}
#define BOARD_SIZE_MIN 5
#define BOARD_SIZE_MAX 88
_ play(int size) {
if (size < BOARD_SIZE_MIN || size > BOARD_SIZE_MAX) {
fprintf(stderr, "Func[Play]: ValueError(size has error value %d!)",
size);
exit(1);
}
// 初始化,置零
Board board = createBoard(size);
int state;
bool first = true;
// 开始游戏
while (true) {
printBoard(true, &board);
state = sweep(first, &board);
first = false;
if (state == Wins) {
printBoard(false, &board);
win();
} else if (state == Boom) {
printBoard(false, &board);
stepMine();
} else if (state == Breaks) {
if (board.n_mine) printBoard(false, &board);
} else if (state == OverFlow) {
prompt(overflow);
continue;
} else if (state == OK) {
continue;
}
break;
}
// 释放
destroyBoard(&board);
printf("\n\n Press enter to continue...");
getchar();
}
//
//
//
//
//
//
/**
* main.c
*/
#define LVL_SIMPLE 5
#define LVL_NORMAL 11
#define LVL_HARD 24
// #include "game.h"
void printMenu(char* prompt[]) {
clearScreen();
printf("\n %s ! ! !\n\n", title);
puts("***********************************");
puts("****** 1. Simple Mode (5) ******");
puts("****** 2. Normal Mode (11) ******");
puts("****** 3. Hard Mode (24) ******");
puts("****** 4. Custom (5~88) ******");
puts("****** 5. Exit ******");
puts("***********************************");
puts("");
printf("%s", *prompt);
*prompt = "";
printf("Select(1~5) >> ");
}
int main(int argc, char** argv) {
initLocale();
int choice;
char* prompt = "";
printMenu(&prompt);
while (EOF != scanf("%d", &choice)) {
clearStdin();
if (choice == 5)
break;
else if (choice == 1) {
play(LVL_SIMPLE);
} else if (choice == 2) {
play(LVL_NORMAL);
} else if (choice == 3) {
play(LVL_HARD);
} else if (choice == 4) {
unsigned size;
printf("Input Size: ");
scanf("%u", &size);
clearStdin();
if (size < BOARD_SIZE_MIN || size > BOARD_SIZE_MAX) {
prompt = "Invalid size!!!\n";
} else {
play(size);
}
}
printMenu(&prompt);
}
// puts("\n\n Press any key to exit\n\n");
// getchar();
return 0;
}