#include "minesweeper.h" #define shift_args(argc, argv) *argv++ static void reveal_bombs(map_t *map) { SDL_Rect rect; for (int j = 0; j < BLOCK_H; ++j) { for (int i = 0; i < BLOCK_W; ++i) { case_t *case_ = &map->tab[j][i]; if (case_->type && case_->hidden && !case_->flagged) { rect.x = case_->x; rect.y = case_->y; xSDL_BlitSurface(bmb_surf, NULL, scr, &rect); } else if (!case_->type && case_->flagged) { rect.x = case_->x; rect.y = case_->y; xSDL_BlitSurface(wrong_flag, NULL, scr, &rect); } } } } static int finished(SDL_Thread **clock_thread, int won, map_t *map) { SDL_Event event; SDL_Rect rect; SDL_Surface *surf; char str[256]; int ret = 1; SDL_KillThread(*clock_thread); *clock_thread = NULL; reveal_bombs(map); sprintf(str, "You %s - press enter to continue", (won) ? "win" : "lose"); surf = new_string(str, 0xffffff, 10); rect.x = (BLOCK_W * BLOCK_SIZE) / 2 - surf->w / 2; rect.y = BLOCK_H * BLOCK_SIZE + 7; xSDL_BlitSurface(surf, NULL, scr, &rect); xSDL_Flip(scr); for (;;) { SDL_WaitEvent(&event); if (event.type == SDL_QUIT) { ret = 0; break; } else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_q) { ret = 0; break; } else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RETURN) break; } SDL_FillRect(surf, NULL, 0); xSDL_BlitSurface(surf, NULL, scr, &rect); xSDL_Flip(scr); SDL_FreeSurface(surf); return (ret); } static int quit(map_t *map __attribute__((unused)), int *selection __attribute__((unused))) { return 0; } static int (*keydown(SDLKey key))(map_t *, int *) { if (key == SDLK_ESCAPE || key == SDLK_q) return (&quit); else if (key == SDLK_h || key == SDLK_LEFT) return (&move_left); else if (key == SDLK_l || key == SDLK_RIGHT) return (&move_right); else if (key == SDLK_k || key == SDLK_UP) return (&move_up); else if (key == SDLK_j || key == SDLK_DOWN) return (&move_down); else if (key == SDLK_f || key == SDLK_SPACE) return (&flip); else if (key == SDLK_d || key == SDLK_RETURN) return (&flag); return (NULL); } static int mouseup(SDL_MouseButtonEvent *event, map_t *map) { int selection; if (!(event->x < BLOCK_W * BLOCK_SIZE && event->y < BLOCK_H * BLOCK_SIZE)) return 0; selection = event->x / BLOCK_SIZE + (event->y / BLOCK_SIZE) * BLOCK_W; if (event->button == SDL_BUTTON_LEFT) { return flip(map, &selection); } else if (event->button == SDL_BUTTON_RIGHT) { flag(map, &selection); } return 0; } static int game(void) { SDL_Event event; map_t map; int (*f_ptr)(map_t *, int *); int selection = 0; int ret = 1; discovered = 0; g_flags = 0; mutex = SDL_CreateMutex(); dsp_ribbon_flags(); init_map(&map); show_map(&map); SDL_Thread *clock_thread = start_clock(); for (;;) { if (discovered == BLOCK_W * BLOCK_H - BOMBS) { ret = finished(&clock_thread, 1, &map); break; } SDL_WaitEvent(&event); if (event.type == SDL_KEYDOWN) { if ((f_ptr = keydown(event.key.keysym.sym))) { if (f_ptr(&map, &selection) == -1) { ret = finished(&clock_thread, 0, &map); quit(&map, &selection); break; } else if (f_ptr == &quit) { ret = 0; break; } } } else if (event.type == SDL_QUIT) { quit(&map, &selection); ret = 0; break; } else if (event.type == SDL_MOUSEBUTTONUP) { if (mouseup(&event.button, &map) == -1) { ret = finished(&clock_thread, 0, &map); quit(&map, &selection); break; } } } if (clock_thread) SDL_KillThread(clock_thread); SDL_DestroyMutex(mutex); return ret; } int get_nbr_touch(bool tab[BLOCK_H][BLOCK_W], int j, int i) { int touch = 0; if (i + 1 < BLOCK_W && tab[j][i + 1]) ++touch; if (j + 1 < BLOCK_H && tab[j + 1][i]) ++touch; if (j + 1 < BLOCK_H && i + 1 < BLOCK_W && tab[j + 1][i + 1]) ++touch; if (j - 1 >= 0 && tab[j - 1][i]) ++touch; if (j - 1 >= 0 && i + 1 < BLOCK_W && tab[j - 1][i + 1]) ++touch; if (j - 1 >= 0 && i - 1 >= 0 && tab[j - 1][i - 1]) ++touch; if (i - 1 >= 0 && tab[j][i - 1]) ++touch; if (i - 1 >= 0 && j + 1 < BLOCK_H && tab[j + 1][i - 1]) ++touch; return (touch); } static void dsp_case(case_t *case_) { SDL_Surface *surf; SDL_Rect rect; if (case_->flagged) surf = flag_surf; else if (case_->hidden) surf = hidden_surf; else if (case_->type) surf = bmb_surf; else surf = surf_number[case_->touch]; rect.x = case_->x; rect.y = case_->y; xSDL_BlitSurface(surf, NULL, scr, &rect); if (case_->selected) xSDL_BlitSurface(selection_surf, NULL, scr, &rect); } void show_map(map_t *map) { for (int j = 0; j < BLOCK_H; ++j) { for (int i = 0; i < BLOCK_W; ++i) { dsp_case(&map->tab[j][i]); } } xSDL_Flip(scr); } void dsp_clock(Uint32 base_ticks) { static Uint32 previous = -1; Uint32 ticks = (SDL_GetTicks() - base_ticks) / 1000; if (ticks != previous) { SDL_Surface *surf = SDL_CreateRGBSurface(SDL_HWSURFACE, 100, 40, 32, 0, 0, 0, 0); SDL_Rect rect; char str[256]; rect.x = 0; rect.y = BLOCK_SIZE * BLOCK_H + 5; xSDL_BlitSurface(surf, NULL, scr, &rect); sprintf(str, "%d", ticks); draw_string(surf, NULL, (const char *)str, 0xff, 15); SDL_mutexP(mutex); SDL_BlitSurface(surf, NULL, scr, &rect); SDL_Flip(scr); SDL_mutexV(mutex); SDL_FreeSurface(surf); } previous = ticks; } static void main_loop(void) { load_surfaces(); while (game()); for (int i = 0; i < 9; ++i) SDL_FreeSurface(surf_number[i]); SDL_FreeSurface(hidden_surf); SDL_FreeSurface(selection_surf); SDL_FreeSurface(flag_surf); SDL_FreeSurface(bmb_surf); SDL_FreeSurface(wrong_flag); } static char **parse_opts(int *argc, char **argv) { (void) argc; (void) argv; return argv; } int main(int argc, char **argv) { const char *arg0 = shift_args(--argc, argv); argv = parse_opts(&argc, argv); if (argc > 1) goto usage; if (SDL_Init(SDL_INIT_VIDEO) == -1) { fprintf(stderr, "SDL_Init fail: %s\n", SDL_GetError()); return (-1); } atexit(SDL_Quit); if ((scr = SDL_SetVideoMode(BLOCK_W * BLOCK_SIZE, BLOCK_H * BLOCK_SIZE + 50, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL) { fprintf(stderr, "SDL_SetVideMode fail: %s\n", SDL_GetError()); return (-1); } srand(time(NULL)); SDL_EnableKeyRepeat(200, 50); SDL_WM_SetCaption("Minesweeper", "Minesweeper"); main_loop(); return 0; usage: printf("Usage: %s\n", arg0); printf(" %s --help\n", arg0); puts("Options:"); puts("--help Display this help"); exit(EX_USAGE); }