Linux下的字符界面扫雷游戏
Linux下的字符界面扫雷游戏
- 空间
转载请注明出处。http://www.cnblogs.com/dave_cn/
这段时间事情比较忙,好不容易抽出些时间再找点游戏练练手,这里献丑了。
我在Ubuntu 10.04下测试过,可以正常运行。
代码用到了NCURSES库。编译的时候链一下ncurses库就可以了,如:
cc -Wall -O2 -o mine mine.c -lncurses
首先放出界面欣赏一下,眼晕的看看外面再继续 ==!:
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <time.h>
#include <signal.h>
#include <unistd.h>
#include <ncurses.h>
/* 雷区的范围 */
#define MINEAREA_WIDTH 9
#define MINEAREA_LENGTH 9
/* 雷的个数 */
#define MINE_NUMBER 10
/*
* 将每个方块的状态分类:
* 1.初始状态
* 2.判定为雷(也就是通常的插旗)
* 3.排除(若周边有n个雷则显示为n,0则显示为空,用-1来表示雷)
*/
#define SQUARE_INIT 0
#define SQUARE_FLAG 1
#define SQUARE_CLEAN 2
#define SQUARE_ZERO 0
#define SQUARE_MINE -1
/* 显示图形 */
#define GRAPH_INIT '.'
#define GRAPH_MINE '@'
#define GRAPH_NULL ' '
#define GRAPH_FLAG 'F'
#define NEWLINE addch('\n')
#define _W(y) (y * 2 + 3)
#define _L(x) (x * 3 + 1)
/* 设置光标 */
#define SET_CURSOR(y, x) mvchgat(_W(y), _L(x), 2, A_REVERSE, 0, NULL)
#define CLEAN_CURSOR(y, x) mvchgat(_W(y), _L(x), 2, A_NORMAL, 0, NULL)
#define WPRINT_NUMBER(y, x, v) \
mvprintw(y, x, "%d", v)
#define WPRINT_CHAR(y, x, c) \
mvaddch(y, x, c)
/* 光标的位置 */
int g_cur_y = 0;
int g_cur_x = 0;
struct square_t {
int type;
int mine;
};
/* timer process function */
int timer_p();
void sig_refresh_time(int signum);
int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]);
int check_yx(int y, int x);
int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH]);
int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x);
/* window functions */
int win_init(int width, int length, int mine_num);
int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines);
int win_refresh_remine_mines(int mines);
int win_refresh_secs(int secs);
int win_mv_cursor(int delta_y, int delta_x, int width, int length);
int win_destroy();
int win_bang();
int win_win();
int win_game_over();
int main()
{
int pid_timer;
int pid_main;
switch (pid_timer = fork()) {
case 0:
/* timer进程,用作计时器 */
timer_p();
_exit(0);
case -1:
perror("fork() error!");
return -1;
default:
/* main process */
break;
}
pid_main = getpid();
/* SIGUSR1信号用来刷新显示时间 */
if (signal(SIGUSR1, sig_refresh_time) == SIG_ERR)
return -1;
struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH];
if (init_mine(square) == -1) return -1;
win_init(MINEAREA_WIDTH, MINEAREA_LENGTH, MINE_NUMBER);
/* 主循环 */
game_loop(square);
win_game_over();
/* 主进程结束前需要结束timer子进程 */
kill(pid_timer, SIGKILL);
int key = -1;
do {
key = getch();
}
while (key != 'y' && key != 'Y');
wait(NULL);
win_destroy();
return 0;
}
/* 初始化雷区信息 */
int init_mine(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH])
{
if (square == NULL)
return -1;
printf("waiting...\n");
int n,m;
for (n = 0; n < 9; ++n) {
for (m = 0; m < 9; ++m) {
square[n][m].type = 0;
square[n][m].mine = 0;
}
}
int i;
int y, x;
srandom((int)time(NULL));
for (i = 0; i < MINE_NUMBER; ++i) {
y = random() % MINEAREA_WIDTH;
x = random() % MINEAREA_LENGTH;
if (square[y][x].mine == SQUARE_MINE) {
--i;
}
else {
square[y][x].mine = SQUARE_MINE;
if (check_yx(y-1, x ) == 0 && square[y-1][x ].mine != SQUARE_MINE)
++square[y-1][x ].mine;
if (check_yx(y+1, x ) == 0 && square[y+1][x ].mine != SQUARE_MINE)
++square[y+1][x ].mine;
if (check_yx(y , x-1) == 0 && square[y ][x-1].mine != SQUARE_MINE)
++square[y ][x-1].mine;
if (check_yx(y , x+1) == 0 && square[y ][x+1].mine != SQUARE_MINE)
++square[y ][x+1].mine;
if (check_yx(y-1, x-1) == 0 && square[y-1][x-1].mine != SQUARE_MINE)
++square[y-1][x-1].mine;
if (check_yx(y+1, x-1) == 0 && square[y+1][x-1].mine != SQUARE_MINE)
++square[y+1][x-1].mine;
if (check_yx(y-1, x+1) == 0 && square[y-1][x+1].mine != SQUARE_MINE)
++square[y-1][x+1].mine;
if (check_yx(y+1, x+1) == 0 && square[y+1][x+1].mine != SQUARE_MINE)
++square[y+1][x+1].mine;
}
}
return 0;
}
int check_yx(int y, int x)
{
if (y >= 0
&& y < MINEAREA_WIDTH
&& x >= 0
&& x < MINEAREA_LENGTH)
{
return 0;
}
return -1;
}
/* 主循环 */
int game_loop(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH])
{
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(0, &rfd);
static int sweeped_mines = 0; /* 判定正确的雷数 */
int ret;
int input;
int remain_mines = MINE_NUMBER;
while (1) {
if ((ret = select(1, &rfd, NULL, NULL, NULL)) <= 0) {
//return -1; //当程序被信号中断时select可能会返回-1
continue;
}
switch (input = getch()) {
/* w,s,a,d方向键 */
case 'w':
case 'W':
win_mv_cursor(-1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);
break;
case 's':
case 'S':
win_mv_cursor(+1, 0, MINEAREA_WIDTH, MINEAREA_LENGTH);
break;
case 'a':
case 'A':
win_mv_cursor(0, -1, MINEAREA_WIDTH, MINEAREA_LENGTH);
break;
case 'd':
case 'D':
win_mv_cursor(0, +1, MINEAREA_WIDTH, MINEAREA_LENGTH);
break;
/* 插旗 */
case 'j':
case 'J':
if (square[g_cur_y][g_cur_x].type == SQUARE_INIT) {
square[g_cur_y][g_cur_x].type = SQUARE_FLAG;
--remain_mines;
if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)
++sweeped_mines;
}
else if (square[g_cur_y][g_cur_x].type == SQUARE_FLAG) {
square[g_cur_y][g_cur_x].type = SQUARE_INIT;
++remain_mines;
if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE)
--sweeped_mines;
}
else
break;
if (sweeped_mines == MINE_NUMBER) {
win_win();
goto GAME_OVER;
}
win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);
break;
/* 打开方块 */
case 'k':
case 'K':
if (square[g_cur_y][g_cur_x].type == SQUARE_CLEAN)
break;
else if (square[g_cur_y][g_cur_x].mine == SQUARE_MINE) {
win_bang();
int n, m;
for (n = 0; n < MINEAREA_WIDTH; ++n) {
for (m = 0; m < MINEAREA_LENGTH; ++m) {
square[n][m].type = SQUARE_CLEAN;
}
}
win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);
goto GAME_OVER;
}
square[g_cur_y][g_cur_x].type = SQUARE_CLEAN;
if (square[g_cur_y][g_cur_x].mine == SQUARE_ZERO)
clean_zero_squares(square, g_cur_y, g_cur_x);
win_refresh(square, MINEAREA_WIDTH, MINEAREA_LENGTH, remain_mines);
break;
/* 退出 */
case 'q':
case 'Q':
goto GAME_OVER;
default:
break;
}
}
GAME_OVER:
return 0;
}
/* 如果打开的方块下面是0,则自动打开所有周围为0的方块 */
int clean_zero_squares(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int cur_y, int cur_x)
{
if (check_yx(cur_y - 1, cur_x) == 0
&& square[cur_y - 1][cur_x].mine == SQUARE_ZERO
&& square[cur_y - 1][cur_x].type != SQUARE_CLEAN)
{
square[cur_y - 1][cur_x].type = SQUARE_CLEAN;
clean_zero_squares(square, cur_y - 1, cur_x);
}
if (check_yx(cur_y + 1, cur_x) == 0
&& square[cur_y + 1][cur_x].mine == SQUARE_ZERO
&& square[cur_y + 1][cur_x].type != SQUARE_CLEAN)
{
square[cur_y + 1][cur_x].type = SQUARE_CLEAN;
clean_zero_squares(square, cur_y + 1, cur_x);
}
if (check_yx(cur_y, cur_x - 1) == 0
&& square[cur_y][cur_x - 1].mine == SQUARE_ZERO
&& square[cur_y][cur_x - 1].type != SQUARE_CLEAN)
{
square[cur_y][cur_x - 1].type = SQUARE_CLEAN;
clean_zero_squares(square, cur_y, cur_x - 1);
}
if (check_yx(cur_y, cur_x + 1) == 0
&& square[cur_y][cur_x + 1].mine == SQUARE_ZERO
&& square[cur_y][cur_x + 1].type != SQUARE_CLEAN)
{
square[cur_y][cur_x + 1].type = SQUARE_CLEAN;
clean_zero_squares(square, cur_y, cur_x + 1);
}
return 0;
}
/*****************************************************************************/
/* 初始化显示界面 */
int win_init(int width, int length, int mine_num)
{
initscr();
raw();
noecho();
keypad(stdscr, TRUE);
curs_set(0);
refresh();
win_refresh_remine_mines(MINE_NUMBER);
win_refresh_secs(0);
int frame_width = width * 2 + 1;
int frame_length = length * 3 + 1;
char *line = NULL;
line = (char*)malloc((frame_length + 1) * sizeof(char));
memset(line, '-', frame_length);
*(line + frame_length) = '\0';
mvprintw(2, 0, line);NEWLINE;
int i, j;
for (j = 0; j < frame_width - 2; ++j) {
addch('|');
for (i = 0; i < length * 2 + 1 - 2; ++i) {
if (j % 2 == 0) {
if (i % 2 == 0) {
addch(GRAPH_INIT);addch(' ');
}
else {
addch('|');
}
}
else {
if (i % 2 == 0) {
addch('-');addch('-');
}
else {
addch('+');
}
}
}
addch('|');NEWLINE;
}
printw(line);NEWLINE;
/* set cursor position */
SET_CURSOR(g_cur_y, g_cur_x);
refresh();
return 0;
}
/* 刷新显示界面 */
int win_refresh(struct square_t square[MINEAREA_WIDTH][MINEAREA_LENGTH], int width, int length, int mines)
{
if (square == NULL)
return -1;
win_refresh_remine_mines(mines);
int j, i;
for (j = 0; j < width; ++j) {
for (i = 0; i < length; ++i) {
switch (square[j][i].type) {
case SQUARE_INIT:
WPRINT_CHAR(_W(j), _L(i), GRAPH_INIT);
break;
case SQUARE_FLAG:
WPRINT_CHAR(_W(j), _L(i), GRAPH_FLAG);
break;
case SQUARE_CLEAN:
switch (square[j][i].mine) {
case SQUARE_MINE:
WPRINT_CHAR(_W(j), _L(i), GRAPH_MINE);
break;
case SQUARE_ZERO:
WPRINT_CHAR(_W(j), _L(i), GRAPH_NULL);
break;
default:
WPRINT_NUMBER(_W(j), _L(i), square[j][i].mine);
break;
}
break;
default:
break;
}
}
}
refresh();
return 0;
}
int win_refresh_remine_mines(int mines)
{
mvprintw(0, 0, "Mines: %d", mines);
mvprintw(1, 0, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
refresh();
return 0;
}
int win_refresh_secs(int secs)
{
mvprintw(0, 15, "Seconds: %d", secs);
refresh();
return 0;
}
int win_mv_cursor(int delta_y, int delta_x, int width, int length)
{
CLEAN_CURSOR(g_cur_y, g_cur_x);
if (g_cur_y + delta_y < width && g_cur_y + delta_y >= 0)
g_cur_y += delta_y;
if (g_cur_x + delta_x < length && g_cur_x + delta_x >= 0)
g_cur_x += delta_x;
SET_CURSOR(g_cur_y, g_cur_x);
refresh();
return 0;
}
int win_destroy()
{
endwin();
return 0;
}
int win_bang()
{
mvprintw(0, 0, "BANG!!!!");
refresh();
return 0;
}
int win_win()
{
mvprintw(0, 0, "WIN!!!!");
refresh();
return 0;
}
int win_game_over()
{
mvprintw(1, 0, "Game Over!");
mvprintw(1, 0, "Press 'y' or 'Y' to end.");
refresh();
return 0;
}
/*****************************************************************************/
int timer_p()
{
/* 每秒钟给主进程发一次信号 */
do {
sleep(1);
kill(getppid(), SIGUSR1);
}
while (1);
return 0;
}
void sig_refresh_time(int signum)
{
static int secs = 0;
win_refresh_secs(++secs);
}
这里给出我自己编的一个可执行文件(ubuntu 10.4):
/Files/dave_cn/mine.zip
Linux下的字符界面扫雷游戏相关推荐
- linux下的图形界面扫雷游戏(Gtk+2.0)
linux下的图形界面扫雷游戏(Gtk+2.0) 空间 转载请注明出处.http://www.cnblogs.com/dave_cn/ 之前做了一个字符界面下的扫雷(http://www.cnblog ...
- 调linux纯字符界面分辨率,linux下设置字符界面的分辨率(转)
linux下设置字符界面的分辨率 部分变态的显卡安装linux后有时候字符界面下分辨率很变态,在此给出更改的弱智方法. 其实简单的很,就是grub即可,编辑grub.conf 在kernel /boo ...
- 字符界面运行mysql_详解linux系列之字符界面下MySQL+apache+php的源代码安装
详解linux系列之字符界面下MySQL+apache+php的源代码安装 在前面介绍了linux和在字符下安装,下面我来介绍一下程序包的安装. 大家也许都知道在linux安装程序的时候后用rpm包安 ...
- Linux下的图形界面编程
一.Qt和GTK+ 虽然Linux下的大多数开发是基于字符界面的,但在Linux环境下也可以开发出美观大方的图形界面.经过多年的发展,目前已经存在多种用于在Linux下开发图形界面程序的开发包,其中较 ...
- 在 windows 下使用 Xming+Putty 显示 Linux 下软件图形界面
From: http://www.blogjava.net/ivanwan/archive/2012/04/26/376670.html From: http://www.bubuko.com/inf ...
- 在windows下使用Xming+Putty显示Linux下软件图形界面
From: http://www.blogjava.net/ivanwan/archive/2012/04/26/376670.html From: http://www.bubuko.com/inf ...
- 怎么开发Linux图形界面程序,Linux下的图形界面编程
Linux下的图形界面编程 一.Qt和GTK+ 虽然Linux下的大多数开发是基于字符界面的,但在Linux环境下也可以开发出美观大方的图形界面.经过多年的发展,目前已经存在多种用于在Linux下开发 ...
- win10 使用Xming+Putty显示Linux下软件图形界面
在windows下使用Xming+Putty显示Linux下软件图形界面 转载 ############# 安装Xming 和 Putty: ############# Xming是一个在Micros ...
- linux下也有很多好游戏
linux下也有很多好游戏了,通过安装这些游戏,可以进一步熟悉LINUX呢. 甚至有些是开源的,可以自己编译修改耶 ^-^ 以下转帖自LINUX桌面中文网 http://linuxdesktop.cn ...
最新文章
- 星际战甲堕落轰击者结合目标_星际战甲-任务指南
- snapmix与Bi-Tempered Logistic Loss(自制数据集纯度不高效果好)
- 【matlab】元胞数组的创建
- golang变量的注意
- 树的存储_ 双亲表示法 及 双亲孩子表示法
- JDK有三种字体绘制系统
- 哪些业务场景不适合部署在虚拟机上?
- 射频识别技术漫谈(9)——动物标签HDX
- 2022华为杯研究生数学建模竞赛F题思路解析
- mysql主从 备份数据库脱敏_数据库脱敏有用吗?会不会损坏重要数据?
- 60道逻辑推理题及答案
- 解决idea工具下tomcat中文乱码问题
- 在阿里云注册域名后怎样进行网站的备案流程
- python数字排列组合去重_python解决排列组合问题的4种方式
- Pwn level题目
- c语言有理数字符形式,C语言设计实现抽象数据类型有理数基本操作包括有理数的加法,减法,乘法,除法,以及求有理数的分子,分...
- word自动更正关闭_如何在OS X中关闭自动更正文本替换
- VC浏览器的定制与扩展
- 帆软思迈特软件Smartbi两家区别在哪里?
- python opencv 图片缺陷检测!