diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..d2ef531 --- /dev/null +++ b/src/main.c @@ -0,0 +1,290 @@ +#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); +} |