/* * simple grid-based minesweeper (Daniel Jones daniel@danieljon.es) * * this program is free software: you can redistribute it and/or modify * it under the terms of the gnu general public license as published by * the free software foundation, either version 3 of the license, or * (at your option) any later version. * * this program is distributed in the hope that it will be useful, * but without any warranty; without even the implied warranty of * merchantability or fitness for a particular purpose. see the * gnu general public license for more details. * * you should have received a copy of the gnu general public license * along with this program. if not, see . */ #include #include #include #include #define WIDTH 10 #define HEIGHT 10 #define MINECOUNT 17 enum STATE { HIDDEN = 1 << 0, MINE = 1 << 1, FLAGGED = 1 << 2, BLANK = 1 << 3, }; struct tile { enum STATE state; int x, y; int neighbormines; }; struct tile board[WIDTH][HEIGHT] = {0}; void generateboard(); void drawboard(); int reveal(int x, int y); void revealmines(); struct tile *getneighbors(struct tile *tile, struct tile **neighbors); struct tile *gettileat(int x, int y); int checkwin(); struct tile *getneighbors(struct tile *tile, struct tile **neighbors) { int badup = 0, baddown = 0, badleft = 0, badright = 0; if (tile->x-1<0) badleft = 1; if (tile->x+1>WIDTH-1) badright = 1; if (tile->y-1<0) badup = 1; if (tile->y+1>HEIGHT-1) baddown = 1; if (!badleft && !badup) neighbors[0] = gettileat(tile->x-1, tile->y-1); if (!badup) neighbors[1] = gettileat(tile->x, tile->y-1); if (!badright && !badup) neighbors[2] = gettileat(tile->x+1, tile->y-1); if (!badleft) neighbors[3] = gettileat(tile->x-1, tile->y); if (!badright) neighbors[4] = gettileat(tile->x+1, tile->y); if (!badleft && !baddown) neighbors[5] = gettileat(tile->x-1, tile->y+1); if (!baddown) neighbors[6] = gettileat(tile->x, tile->y+1); if (!badright && !baddown) neighbors[7] = gettileat(tile->x+1, tile->y+1); return *neighbors; } int checkwin() { int allowedmines = MINECOUNT; int safetiles = (HEIGHT * WIDTH) - MINECOUNT; int correctflags = 0; int correcttiles = 0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { struct tile *tile = gettileat(x, y); if (tile->state & MINE && tile->state & FLAGGED) correctflags++; else if (!(tile->state & MINE) && !(tile->state & HIDDEN)) correcttiles++; } } return (correctflags == allowedmines) || (correcttiles == safetiles); } void generateboard() { srand(time(NULL)); /* place mines */ //printf("mines at: "); for (int x = 0; x < MINECOUNT; x++) { int mx, my; mx = rand() % WIDTH; my = rand() % HEIGHT; struct tile *tile = gettileat(mx ,my); tile->state |= MINE; //printf("%d, %d : ", mx, my); } puts(""); /* figure out neighbors */ for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { struct tile *tile = gettileat(x, y); tile->x = x; tile->y = y; tile->state |= HIDDEN; struct tile *neighbors[8] = {NULL}; getneighbors(tile, neighbors); tile->neighbormines = 0; for (int i = 0; i < 8; i++) if (neighbors[i] != NULL && neighbors[i]->state & MINE) tile->neighbormines += 1; //if (tile->neighbormines == 0 && !(tile->state & MINE)) //printf("%d,%d ", tile->x, tile->y); } } puts(""); } int main(void) { int dead = 0; generateboard(); puts("reveal every safe tile or flag every mine to win.\nto (un)flag the tile at 3,7 enter 'f 3 7'\n" \ "to reveal tile at 5,5 enter '5 5'\n"); drawboard(); while (dead == 0) { char input[512]; int desx = 0, desy = 0, flagging = 0, xset = 0; printf("> "); fgets(input, 412, stdin); char* token = strtok(input, " "); while (token) { if (strcmp(token, "f") == 0) { flagging = 1; } else if (xset == 0) { desx = atoi(token); xset = 1; } else if (xset == 1) { desy = atoi(token); } token = strtok(NULL, " "); } struct tile *tile = gettileat(desx, desy); if (flagging) { if (tile && tile->state & HIDDEN) gettileat(desx, desy)->state ^= FLAGGED; /* toggle flagged flag */ } else { if (tile && !(tile->state & FLAGGED)) dead = reveal(tile->x, tile->y); } printf("\033[15A"); printf("\033[J"); drawboard(); if (checkwin()) { revealmines(); printf("\033[15A"); printf("\033[J"); drawboard(); printf("you win\n"); break; } else if (dead == 1) { revealmines(); printf("\033[15A"); printf("\033[J"); drawboard(); printf("you lose\n"); } } return 1; } struct tile * gettileat(int x, int y) { if (x < 0 || x > WIDTH-1 || y < 0 || y > HEIGHT-1) return NULL; return &board[x][y]; } int reveal(int x, int y) { struct tile *tile = gettileat(x, y); tile->state &= ~HIDDEN; if (tile->state & MINE) return 1; if (tile->neighbormines == 0) { tile->state &= ~HIDDEN; struct tile *neighbors[8] = {NULL}; getneighbors(tile, neighbors); for (int nc = 0; nc < 8; nc++) { struct tile *neighbor = neighbors[nc]; if (neighbor != NULL && !(neighbor->state & MINE) && neighbor->state & HIDDEN) { neighbor->state &= ~HIDDEN; if (neighbor->neighbormines == 0) { reveal(neighbor->x, neighbor->y); } } } } return 0; } void revealmines() { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (gettileat(x, y)->state & MINE) reveal(x, y); } } } void drawboard() { printf(" "); for (int i = 0; i < WIDTH; i++) printf(" %d ", i); puts(""); printf(" "); for (int i = 0; i < WIDTH; i++) printf("---"); puts(""); for (int y = 0; y < HEIGHT; y++) { printf("%d |", y); for (int x = 0; x < WIDTH; x++) { struct tile *tile = gettileat(x, y); char neighbormines = (char)tile->neighbormines+'0'; if (neighbormines == '0') neighbormines = ' '; if (tile->state & FLAGGED) printf(" F "); else if (tile->state & HIDDEN) printf(" . "); else printf(" %c ", (tile->state & MINE) ? 'M' :neighbormines); } printf("| %d\n", y); } printf(" "); for (int i = 0; i < WIDTH; i++) printf("---"); puts(""); printf(" "); for (int i = 0; i < WIDTH; i++) printf(" %d ", i); puts(""); }