summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c290
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);
+}