Skip to content

Commit

Permalink
added constraint satisfaction solving method and many other small things
Browse files Browse the repository at this point in the history
  • Loading branch information
danamlund committed Jan 25, 2012
1 parent 2d6e74a commit 2e76bc1
Show file tree
Hide file tree
Showing 7 changed files with 542 additions and 80 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,16 @@ minesweeper_curses: minesweeper_lib.c minesweeper_curses.c
-l$(CURSESLIB) \
-o minesweeper_curses

package_linux: minesweeper minesweeper_solver minesweeper_curses
rm -Rf minesweeper-solver
mkdir minesweeper-solver
cp minesweeper minesweeper_solver minesweeper_curses README \
minesweeper-solver
mkdir minesweeper-solver/src
cp minesweeper.c minesweeper_lib.c minesweeper_lib.h \
minesweeper_curses.c minesweeper_solver.c Makefile \
minesweeper-solver/src
tar czvf minesweeper-solver.tar.gz minesweeper-solver

clean:
rm -f minesweeper minesweeper_solver minesweeper_curses
8 changes: 4 additions & 4 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ A minesweeper solver and game.

Download binaries at http://danamlund.dk/minesweeper_solver

I have successfully compiled this in Ubuntu 11.04 (with ncurses) and
in MinGW (with pdcurses). The Makefile and source checks and adjusts
itself depending on system.
I have successfully compiled this using Ubuntu 11.04 (with ncurses)
and using MinGW (with pdcurses). The Makefile and source checks and
adjusts itself depending on which system you use.

Below is the "--help" output from the programs in this repository:

Expand Down Expand Up @@ -41,7 +41,7 @@ Legend of the symbols in the grid:
have lost

Example: Playing a game of minesweeper
Start a new game called using file 'foo':
Start a new game called using file 'foo.txt':
run 'minesweeper -n -b 1 foo.txt'
Play minesweeper:
1) Edit file foo.txt
Expand Down
84 changes: 78 additions & 6 deletions minesweeper.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,37 @@ char process_input(struct board* solution, struct board* input) {
return output;
}

void start_new_game(char *name, int x, int y, int mines) {
void fair_game(struct game *game) {
bool fair = false;
struct neighbor_it *it;
int first_0_x = -1, first_0_y = -1;
int x, y;
for (y = 0; y < game->y; y++) {
for (x = 0; x < game->x; x++) {
if (game->solution->adj_mines[x][y] == 0) {
first_0_x = x;
first_0_y = y;
for(it = new_neighbor_it(game->solution, x, y);
next_neighbor_it(it);) {
if (game->solution->adj_mines[it->x][it->y] == 0) {
fair = true;
game->input->adj_mines[x][y] = TILE_NOT_MINE;
break;
}
}
free_neighbor_it(it);
if (fair) break;
}
}
if (fair) break;
}
if (!fair && first_0_x != -1) {
game->input->adj_mines[first_0_x][first_0_y] = TILE_NOT_MINE;
}
process_input(game->solution, game->input);
}

void start_new_game(char *name, int x, int y, int mines, bool fair) {
struct game *game = new_game();;

game->x = x;
Expand All @@ -95,7 +125,11 @@ void start_new_game(char *name, int x, int y, int mines) {
game->input->adj_mines[xx][yy] = TILE_UNKNOWN;
}
}


if (fair) {
fair_game(game);
}

FILE *f;
if (NULL == name || 0 == strcmp(name, "-")) {
f = stdout;
Expand All @@ -106,6 +140,31 @@ void start_new_game(char *name, int x, int y, int mines) {
fclose(f);
}

bool game_won(struct game *game) {
int x, y;
for (x = 0; x < game->x; x++) {
for (y = 0; y < game->y; y++) {
if (game->solution->adj_mines[x][y] == TILE_MINE &&
game->solution->adj_mines[x][y] !=
game->input->adj_mines[x][y])
return false;
}
}
return true;
}

bool game_has_bad_mine(struct game *game) {
int x, y;
for (x = 0; x < game->x; x++) {
for (y = 0; y < game->y; y++) {
if (game->input->adj_mines[x][y] == TILE_MINE &&
game->solution->adj_mines[x][y] != TILE_MINE)
return true;
}
}
return false;
}

void process_game(char *file) {
struct game *game;
FILE *f;
Expand All @@ -122,7 +181,12 @@ void process_game(char *file) {
fprintf(stderr, "minesweeper: invalid game.\n");
exit(1);
}


if (game_has_bad_mine(game)) {
if (verbose) fprintf(stderr, "Game has incorrectly marked mine!\n");
exit(0);
}

int output;
output = process_input(game->solution, game->input);

Expand All @@ -134,6 +198,11 @@ void process_game(char *file) {
save_game(game, f);
fclose(f);

if (game_won(game)) {
if (verbose) fprintf(stderr, "Game won!\n");
exit(0);
}

switch (output) {
case OUT_INVALID:
if (verbose) fprintf(stderr, "You hit a mine!\n");
Expand All @@ -153,7 +222,8 @@ void print_help() {
"game from FILE or standard input.\n"
"\n"
" -n Start a new game.\n"
" -b INT Start a new game using a predefined board:\n"
" -f Start the new game fairly (reveal a hole)\n"
" -b INT Start the new game using a predefined board:\n"
" 0: 8x8 grid with 10 mines\n"
" 1: 16x16 grid with 40 mines\n"
" 2: 30x16 grid with 99 mines\n"
Expand All @@ -162,7 +232,7 @@ void print_help() {
" -y INT Set the height of the grid.\n"
" -m INT Set the number of mines.\n"
" -h, --help Show this help menu.\n"
" -v More output.\n"
" -v Verbose output (to stderr).\n"
"\n"
"The FILE contains information about the game and provide an\n"
"interface to the game. Only modify the file by overwriting\n"
Expand Down Expand Up @@ -194,6 +264,7 @@ void print_help() {
int game(int argc, char** args) {
char *file = NULL;
bool newgame = false;
bool fair = false;
int x = 0, y = 0, mines = 0, b = 0;

int i = 1;
Expand All @@ -211,6 +282,7 @@ int game(int argc, char** args) {
case 'm': mines = atoi(args[i+1]); i++; break;
case 'b': b = atoi(args[i+1]); i++; break;
case 'v': verbose = true; break;
case 'f': fair = true; break;
default: fprintf(stderr, "Unknown argument '%s'\n", args[i]); exit(1);
}
} else {
Expand All @@ -233,7 +305,7 @@ int game(int argc, char** args) {
if (y) gy = y;
if (mines) gmines = mines;

start_new_game(file, gx, gy, gmines);
start_new_game(file, gx, gy, gmines, fair);
} else {
process_game(file);
}
Expand Down
93 changes: 73 additions & 20 deletions minesweeper_curses.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
static char *window_id = NULL;
static int screenshot_id = 0;

static char *file_minesweeper = FILE_PREFIX "minesweeper";
static char *file_minesweeper_solver = FILE_PREFIX "minesweeper_solver -m";
static char *file_suffix = "";

struct game {
int x, y, mines;
char **input;
Expand Down Expand Up @@ -237,17 +241,17 @@ void save_char_board(char **b, int size_x, int size_y, char *filename) {
fclose(f);
}

void my_exec(char *prog, char *file) {
char cmd[100];
sprintf(cmd, "%s %s", prog, file);
void my_exec(char *prog, char *file, char *suffix) {
char cmd[1024];
sprintf(cmd, "%s %s %s", prog, file, suffix);
int suppress_warning = system(cmd);
if (suppress_warning);
}
void process_turn(char *file) {
my_exec(FILE_PREFIX "minesweeper", file);
my_exec(file_minesweeper, file, file_suffix);
}
void solve(char *file) {
my_exec(FILE_PREFIX "minesweeper_solver -m", file);
my_exec(file_minesweeper_solver, file, file_suffix);
}
void screenshot(char *file) {
if (NULL == window_id) {
Expand All @@ -266,7 +270,7 @@ void show_help() {
printw("\n"
"\n"
"\n"
" Keys:\n"
" ======= Keys =======\n"
" q: quit\n"
" Arrow keys: move cursor\n"
" Home/End/PgUp/PgDown: move cursor to edges\n"
Expand All @@ -276,6 +280,10 @@ void show_help() {
" s: Solve one turn\n"
" w: Have solver fill out tiles\n"
" e: Process solver's filled out tiles\n"
" 0: Start a new easy game\n"
" 1: Start a new normal game\n"
" 2: Start a new expert game\n"
" 3: Start a new insane game\n"
" h: Show help\n"
);
refresh();
Expand Down Expand Up @@ -317,10 +325,14 @@ void print_ui(char *file, struct game *game, int yadd, int xadd) {
refresh();
}

void start_new_game(char *file, int type) {
char args[100];
sprintf(args, "-n -b %d", type);
my_exec(file_minesweeper, file, args);
}

void game(char* file) {
printf("1\n");
struct game *game = read_game(file);
printf("2\n");

int x = game->x/2;
int y = game->y/2;
Expand Down Expand Up @@ -415,6 +427,18 @@ void game(char* file) {
refresh();
break;
case 'q': run = 0; break;
case '0': case '1': case '2': case '3':
start_new_game(file, c - '0');
free_game(game);
game = read_game(file);

x = game->x/2;
y = game->y/2;

print_ui(file, game, yadd, xadd);
print_board(game, yadd, xadd);
board_changed = true;
break;
case 'h':
show_help();
print_ui(file, game, yadd, xadd);
Expand All @@ -432,23 +456,32 @@ void game(char* file) {
}
}

bool file_exists(char *file) {
FILE *f = fopen(file, "r");
if (f != NULL) {
fclose(f);
return true;
}
return false;
}

void print_help() {
printf("Usage: minesweeper_curses FILE\n"
printf("Usage: minesweeper_curses [FILE]\n"
"Start a curses user interface using the minesweeper\n"
"game from FILE.\n"
"game from FILE or game.txt by default.\n"
"\n"
" -h, --help Show this help menu.\n"
" -w WINDOW-ID Set up recording using Imagemagick\n");
" -w WINDOW-ID Set up recording using Imagemagick\n"
" -m 'CMD' Use CMD instead of './minesweeper'\n"
" -s 'CMD' Use CMD instead of './minesweeper_solver -m'\n"
" -a 'ARGS' Append ARGS when running './minesweeper'\n"
" and './minesweeper_solver'\n");
}

int run(int argc, char **args) {
if (argc < 2) {
print_help();
return 0;
}

if (0 == strcmp("-h", args[1]) ||
0 == strcmp("--help", args[1])) {
if (argc > 1 &&
(0 == strcmp("-h", args[1]) ||
0 == strcmp("--help", args[1]))) {
print_help();
return 0;
}
Expand All @@ -462,6 +495,18 @@ int run(int argc, char **args) {
window_id = args[i+1];
i++;
break;
case 'm':
file_minesweeper = args[i+1];
i++;
break;
case 's':
file_minesweeper_solver = args[i+1];
i++;
break;
case 'a':
file_suffix = args[i+1];
i++;
break;
default:
printf("minesweeper_curses: unknown argument: '-%c'\n", args[i][1]);
return 1;
Expand All @@ -471,9 +516,17 @@ int run(int argc, char **args) {
}
}

printf("1\n");
if (NULL != file && !file_exists(file)) {
printf("minesweeper_curses: File '%s' doesn't exists.\n", file);
return 1;
}

if (NULL == file) {
print_help();
return 0;
file = "game.txt";
if (!file_exists(file)) {
start_new_game(file, 1);
}
}

init_curses();
Expand Down
9 changes: 9 additions & 0 deletions minesweeper_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,12 @@ void save_game(struct game *game, FILE *f) {
write_board(solution, f);
free_board(solution);
}

bool file_exists(char *file) {
FILE *f = fopen(file, "r");
if (f != NULL) {
fclose(f);
return true;
}
return false;
}
2 changes: 2 additions & 0 deletions minesweeper_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ void decrypt_board(struct board *b, int seed);
struct game* load_game(FILE *f);
void save_game(struct game *game, FILE *f);

bool file_exists(char *file);

#endif /* !MINESWEEPER_LIB_H_ */
Loading

0 comments on commit 2e76bc1

Please sign in to comment.