RosettaCodeData/Task/Minesweeper-game/C/minesweeper-game-2.c
Ingy döt Net db842d013d A-M baby
2013-04-10 21:29:02 -07:00

184 lines
3.6 KiB
C

#include <ncurses.h>
#include <locale.h>
#include <stdlib.h>
int width = 0, height = 0;
int mine_ratio = 10, n_mines;
int reveal = 0;
WINDOW *win, *wrap;
enum {
M_NONE = 0,
M_CLEARED = 1 << 0,
M_MARKED = 1 << 1,
M_MINED = 1 << 2,
M_BOMBED = 1 << 3,
};
typedef struct { unsigned short flag, cnt; } mine_t;
#define for_i for (int i = 0; i < height; i++)
#define for_j for (int j = 0; j < width; j++)
void init_mines(void * ptr)
{
mine_t (*m)[width] = ptr;
for_i for_j
if (rand() % mine_ratio)
m[i][j].flag = M_NONE;
else {
m[i][j].flag = M_MINED;
n_mines ++;
}
for_i for_j {
m[i][j].cnt = 0;
for (int x = j - 1; x <= j + 1; x++) {
if (x < 0 || x > width) continue;
for (int y = i - 1; y <= i + 1; y++) {
if (y < 0 || y >= width) continue;
m[i][j].cnt += 1 && (m[y][x].flag & M_MINED);
}
}
}
}
int mine_clear(void *ptr, int x, int y, int mass_clear)
{
mine_t (*m)[width] = ptr;
unsigned short flag;
if (x < 0 || x >= width || y < 0 || y >= height)
return 1;
flag = m[y][x].flag;
if (((flag & M_CLEARED) && 1) != mass_clear) return 1;
if ((flag & M_MINED) && !(flag & M_MARKED)) {
m[y][x].flag |= M_BOMBED;
reveal = 1;
return 0;
}
if (!(flag & M_MARKED))
flag = (m[y][x].flag |= M_CLEARED);
if (m[y][x].cnt && !mass_clear) return 1;
if (flag & M_MARKED) return 1;
for (int i = y - 1; i <= y + 1; i++)
for (int j = x - 1; j <= x + 1; j++)
if (!mine_clear(ptr, j, i, 0)) return 0;
return 1;
}
void mine_mark(void *ptr, int x, int y)
{
mine_t (*m)[width] = ptr;
if (m[y][x].flag & M_CLEARED) return;
if (m[y][x].flag & M_MARKED)
n_mines ++;
else
n_mines --;
m[y][x].flag ^= M_MARKED;
}
int check_wining(void *ptr)
{
mine_t (*m)[width] = ptr;
int good = 1;
for_i for_j {
int f = m[i][j].flag;
if ((f & M_MINED) && !(f & M_MARKED)) {
m[i][j].flag = M_BOMBED;
good = 0;
}
}
mvwprintw(wrap, height + 1, 0, good ? "All clear! " : "BOOM! ");
reveal = 1;
return good;
}
void repaint(void *ptr)
{
mine_t (*m)[width] = ptr, *p;
box(win, 0, 0);
for_i for_j {
char c;
p = &m[i][j];
int f = p->flag;
if (reveal)
c = (f & M_BOMBED) ? 'X' : (f & M_MINED) ? 'o' : ' ';
else if (p->flag & M_BOMBED)
c = 'X';
else if (p->flag & M_MARKED)
c = '?';
else if (p->flag & M_CLEARED)
c = p->cnt ? p->cnt + '0' : ' ';
else
c = '.';
mvwprintw(win, i + 1, 2 * j + 1, " %c", c);
}
if (reveal);
else if (n_mines)
mvwprintw(wrap, height + 1, 0, "Mines:%6d ", n_mines);
else
mvwprintw(wrap, height + 1, 0, "Claim victory? ");
wrefresh(wrap);
wrefresh(win);
}
int main(int c, char **v)
{
MEVENT evt;
printf("%d\n", c);
if (c >= 3) {
height = atoi(v[1]);
width = atoi(v[2]);
}
if (height < 3) height = 15;
if (width < 3) width = 30;
initscr();
int mines[height][width];
init_mines(mines);
win = newwin(height + 2, 2 * width + 2, 0, 0);
wrap = newwin(height + 3, 2 * width + 2, 1, 0);
keypad(wrap, 1);
mousemask(BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED, 0);
while (1) {
int ch;
repaint(mines);
if ((ch = wgetch(wrap)) != KEY_MOUSE) {
if (ch != 'r') break;
reveal = !reveal;
continue;
}
if (getmouse(&evt) != OK) continue;
if ((evt.bstate & BUTTON1_CLICKED)) {
if (evt.y == height + 2 && !n_mines) {
check_wining(mines);
break;
}
if (!mine_clear(mines, (evt.x - 1) / 2, evt.y - 1, 0))
break;
}
else if ((evt.bstate & BUTTON2_CLICKED)) {
if (!mine_clear(mines, (evt.x - 1) / 2, evt.y - 1, 1))
break;
}
else if ((evt.bstate & BUTTON3_CLICKED))
mine_mark(mines, (evt.x - 1)/2, evt.y - 1);
}
repaint(mines);
mousemask(0, 0);
keypad(wrap, 0);
endwin();
return 0;
}