summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/flag.c26
-rw-r--r--src/flip.c105
-rw-r--r--src/init.c115
-rw-r--r--src/main.c290
-rw-r--r--src/move.c55
-rw-r--r--src/xSDL.c35
6 files changed, 626 insertions, 0 deletions
diff --git a/src/flag.c b/src/flag.c
new file mode 100644
index 0000000..9201cac
--- /dev/null
+++ b/src/flag.c
@@ -0,0 +1,26 @@
+/*
+** flag.c for in /home/gayot_o/prog/minesweeper
+**
+** Made by olivier gayot
+** Login <gayot_o@epitech.net>
+**
+** Started on Sun Apr 22 19:02:49 2012 olivier gayot
+** Last update Sun Apr 22 19:02:49 2012 olivier gayot
+*/
+
+#include "minesweeper.h"
+
+int flag(map_t *map, int *selection) {
+ case_t *case_ = &map->tab[*selection / BLOCK_W][*selection % BLOCK_W];
+
+ if (!case_->hidden)
+ return 0;
+ case_->flagged = (case_->flagged) ? false : true;
+ if (case_->flagged)
+ ++g_flags;
+ else
+ --g_flags;
+ dsp_ribbon_flags();
+ show_map(map);
+ return 0;
+}
diff --git a/src/flip.c b/src/flip.c
new file mode 100644
index 0000000..3ab50d5
--- /dev/null
+++ b/src/flip.c
@@ -0,0 +1,105 @@
+/*
+** flip.c for in /home/gayot_o/prog/minesweeper
+**
+** Made by olivier gayot
+** Login <gayot_o@epitech.net>
+**
+** Started on Sun Apr 22 17:49:25 2012 olivier gayot
+** Last update Sun Apr 22 17:49:25 2012 olivier gayot
+*/
+
+#include "minesweeper.h"
+
+static int get_flag_touch(case_t tab[BLOCK_H][BLOCK_W], int j, int i);
+static int rec(case_t map[BLOCK_H][BLOCK_W], int j, int i);
+static int flip_around(case_t tab[BLOCK_H][BLOCK_W], int j, int i);
+
+int flip(map_t *map, int *selection) {
+ case_t *case_ = &map->tab[*selection / BLOCK_W][*selection % BLOCK_W];
+ int ret;
+
+ if (!case_->hidden && get_flag_touch(map->tab,
+ *selection / BLOCK_W, *selection % BLOCK_W) == case_->touch)
+ ret = flip_around(map->tab, *selection / BLOCK_W, *selection % BLOCK_W);
+ else
+ ret = rec(map->tab, *selection / BLOCK_W, *selection % BLOCK_W);
+ show_map(map);
+ return ret;
+}
+
+static int rec(case_t tab[BLOCK_H][BLOCK_W], int j, int i) {
+ case_t *case_ = &tab[j][i];
+
+ if (!case_->hidden || case_->flagged)
+ return 0;
+ case_->hidden = false;
+ if (!case_->type)
+ ++discovered;
+ if (case_->type)
+ return -1;
+ if (case_->touch == 0) {
+ {
+ if (j + 1 < BLOCK_H && i + 1 < BLOCK_W)
+ rec(tab, j + 1, i + 1);
+ if (j + 1 < BLOCK_H)
+ rec(tab, j + 1, i);
+ if (j + 1 < BLOCK_H && i - 1 >= 0)
+ rec(tab, j + 1, i - 1);
+ if (j - 1 >= 0 && i + 1 < BLOCK_W)
+ rec(tab, j - 1, i + 1);
+ if (j - 1 >= 0)
+ rec(tab, j - 1, i);
+ if (j - 1 >= 0 && i - 1 >= 0)
+ rec(tab, j - 1, i - 1);
+ if (i - 1 >= 0)
+ rec(tab, j, i - 1);
+ if (i + 1 < BLOCK_W)
+ rec(tab, j, i + 1);
+ }
+ }
+ return 0;
+}
+
+static int get_flag_touch(case_t tab[BLOCK_H][BLOCK_W], int j, int i) {
+ int flags = 0;
+
+ if (j + 1 < BLOCK_H && i + 1 < BLOCK_W && tab[j + 1][i + 1].flagged)
+ ++flags;
+ if (j + 1 < BLOCK_H && tab[j + 1][i].flagged)
+ ++flags;
+ if (j + 1 < BLOCK_H && i - 1 >= 0 && tab[j + 1][i - 1].flagged)
+ ++flags;
+ if (j - 1 >= 0 && i + 1 < BLOCK_W&& tab[j - 1][i + 1].flagged)
+ ++flags;
+ if (j - 1 >= 0 && tab[j - 1][i].flagged)
+ ++flags;
+ if (j - 1 >= 0 && i - 1 >= 0 && tab[j - 1][i - 1].flagged)
+ ++flags;
+ if (i - 1 >= 0 && tab[j][i - 1].flagged)
+ ++flags;
+ if (i + 1 < BLOCK_W && tab[j][i + 1].flagged)
+ ++flags;
+ return flags;
+}
+
+static int flip_around(case_t tab[BLOCK_H][BLOCK_W], int j, int i) {
+ int ret = 0;
+
+ if (j + 1 < BLOCK_H && i + 1 < BLOCK_W)
+ if (rec(tab, j + 1, i + 1) == -1) ret = -1;
+ if (j + 1 < BLOCK_H)
+ if (rec(tab, j + 1, i) == -1) ret = -1;
+ if (j + 1 < BLOCK_H && i - 1 >= 0)
+ if (rec(tab, j + 1, i - 1) == -1) ret = -1;
+ if (j - 1 >= 0 && i + 1 < BLOCK_W)
+ if (rec(tab, j - 1, i + 1) == -1) ret = -1;
+ if (j - 1 >= 0)
+ if (rec(tab, j - 1, i) == -1) ret = -1;
+ if (j - 1 >= 0 && i - 1 >= 0)
+ if (rec(tab, j - 1, i - 1) == -1) ret = -1;
+ if (i - 1 >= 0)
+ if (rec(tab, j, i - 1) == -1) ret = -1;
+ if (i + 1 < BLOCK_W)
+ if (rec(tab, j, i + 1) == -1) ret = -1;
+ return ret;
+}
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..812598f
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,115 @@
+/*
+** init.c for in /home/gayot_o/prog/minesweeper
+**
+** Made by olivier gayot
+** Login <gayot_o@epitech.net>
+**
+** Started on Sun Apr 22 16:09:49 2012 olivier gayot
+** Last update Sun Apr 22 16:09:49 2012 olivier gayot
+*/
+
+#include <stdio.h>
+#include <sdl_digit.h>
+#include <strings.h>
+#include "minesweeper.h"
+
+static void rand_bombs(bool bombs[BLOCK_H][BLOCK_W]);
+static SDL_Surface *xSDL_LoadBMP(const char *path);
+
+void init_map(map_t *map) {
+ bool bombs[BLOCK_H][BLOCK_W];
+
+ rand_bombs(bombs); map->bombs = BOMBS;
+ for (int j = 0; j < BLOCK_H; ++j) {
+ for (int i = 0; i < BLOCK_W; ++i) {
+ if (!(map->tab[j][i].type = bombs[j][i]))
+ map->tab[j][i].touch = get_nbr_touch(bombs, j, i);
+ map->tab[j][i].x = i * BLOCK_SIZE;
+ map->tab[j][i].y = j * BLOCK_SIZE;
+ map->tab[j][i].hidden = true;
+ map->tab[j][i].selected = false;
+ map->tab[j][i].flagged = false;
+ }
+ }
+ map->tab[0][0].selected = true;
+}
+
+static void rand_bombs(bool bombs[BLOCK_H][BLOCK_W]) {
+ int i = 0;
+
+ memset((void *)bombs, 0, sizeof(bool) * BLOCK_H * BLOCK_W);
+ while (i < BOMBS) {
+ int id = rand() % (BLOCK_H * BLOCK_W);
+ if (bombs[id / BLOCK_W][id % BLOCK_W] == 0) {
+ bombs[id / BLOCK_W][id % BLOCK_W] = 1;
+ ++i;
+ }
+ }
+}
+
+void load_surfaces(void) {
+ char str[256];
+
+ for (int i = 0; i < 9; ++i) {
+ snprintf(str, 256, "img/%d.bmp", i);
+ surf_number[i] = xSDL_LoadBMP(str);
+ }
+ bmb_surf = xSDL_LoadBMP("img/b.bmp");
+ hidden_surf = xSDL_LoadBMP("img/hidden.bmp");
+ flag_surf = xSDL_LoadBMP("img/flag.bmp");
+ wrong_flag = xSDL_LoadBMP("img/wrong_flag.bmp");
+ selection_surf = xSDL_LoadBMP("img/selection.bmp");
+ SDL_SetColorKey(selection_surf, SDL_SRCCOLORKEY, 0);
+}
+
+void dsp_ribbon_flags(void) {
+ SDL_Surface *surf;
+ char str[256];
+ SDL_Rect rect;
+
+ surf = SDL_CreateRGBSurface(SDL_HWSURFACE, 90, 40, 32, 0, 0, 0, 0);
+ rect.x = BLOCK_SIZE * BLOCK_W - 90;
+ rect.y = BLOCK_SIZE * BLOCK_H + 5;
+ SDL_FillRect(surf, NULL, 0);
+ xSDL_BlitSurface(surf, NULL, scr, &rect);
+ if ((int)(BOMBS - g_flags) <= -100)
+ sprintf(str, "-%u", ABS((int)(BOMBS - g_flags)));
+ else if ((int)(BOMBS - g_flags) <= -10)
+ sprintf(str, "-0%u", ABS((int)(BOMBS - g_flags)));
+ else if ((int)(BOMBS - g_flags) < 0)
+ sprintf(str, "-00%u", ABS((int)(BOMBS - g_flags)));
+ else if ((int)(BOMBS - g_flags) < 10)
+ sprintf(str, " 00%u", ABS((int)(BOMBS - g_flags)));
+ else if ((int)(BOMBS - g_flags) < 100)
+ sprintf(str, " 0%u", ABS((int)(BOMBS - g_flags)));
+ else
+ sprintf(str, " %d", BOMBS - g_flags);
+ draw_string(surf, NULL, str, 0xff, 15);
+ xSDL_BlitSurface(surf, NULL, scr, &rect);
+ SDL_FreeSurface(surf);
+}
+
+int callback(void *param __attribute__((unused))) {
+ Uint32 base_ticks = SDL_GetTicks();
+
+ for (;;) {
+ dsp_clock(base_ticks);
+ SDL_Delay(200);
+ }
+ return 0;
+}
+
+SDL_Thread *start_clock(void) {
+ return (SDL_CreateThread(&callback, NULL));
+}
+
+static SDL_Surface *xSDL_LoadBMP(const char *path) {
+ SDL_Surface *surf;
+ char buffer[256];
+
+ if (!(surf = SDL_LoadBMP(path))) {
+ snprintf(buffer, 256, "Unable to load %s: %s\n", path, SDL_GetError());
+ exit(-1);
+ }
+ return (surf);
+}
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);
+}
diff --git a/src/move.c b/src/move.c
new file mode 100644
index 0000000..c14724c
--- /dev/null
+++ b/src/move.c
@@ -0,0 +1,55 @@
+/*
+** move.c for in /home/gayot_o/prog/minesweeper
+**
+** Made by olivier gayot
+** Login <gayot_o@epitech.net>
+**
+** Started on Sun Apr 22 17:08:59 2012 olivier gayot
+** Last update Sun Apr 22 17:08:59 2012 olivier gayot
+*/
+
+#include "minesweeper.h"
+
+static void incr_selection(int incr, map_t *map, int *selection);
+
+int move_left(map_t *map, int *selection) {
+ if (*selection % BLOCK_W)
+ incr_selection(-1, map, selection);
+ else /* beginning of the line */
+ incr_selection(BLOCK_W - 1, map, selection);
+ show_map(map);
+ return 0;
+}
+
+int move_right(map_t *map, int *selection) {
+ if (*selection % BLOCK_W != (BLOCK_W - 1))
+ incr_selection(+1, map, selection);
+ else /* beginning of the line */
+ incr_selection(-(BLOCK_W - 1), map, selection);
+ show_map(map);
+ return 0;
+}
+
+int move_up(map_t *map, int *selection) {
+ if (*selection / BLOCK_W)
+ incr_selection(-BLOCK_W, map, selection);
+ else /* beginning of the line */
+ incr_selection(BLOCK_W * (BLOCK_H - 1), map, selection);
+ show_map(map);
+ return 0;
+}
+
+int move_down(map_t *map, int *selection) {
+ if (*selection / BLOCK_W != (BLOCK_H - 1))
+ incr_selection(BLOCK_W, map, selection);
+ else /* beginning of the line */
+ incr_selection(-(BLOCK_W * (BLOCK_H - 1)), map, selection);
+ show_map(map);
+ return 0;
+}
+
+static void incr_selection(int incr, map_t *map, int *selection) {
+ map->tab[*selection / BLOCK_W][*selection % BLOCK_W].selected = false;
+ (*selection) += incr;
+ map->tab[*selection / BLOCK_W][*selection % BLOCK_W].selected = true;
+}
diff --git a/src/xSDL.c b/src/xSDL.c
new file mode 100644
index 0000000..3ee36cb
--- /dev/null
+++ b/src/xSDL.c
@@ -0,0 +1,35 @@
+/*
+** xSDL.c for in /home/gayot_o/prog/minesweeper/src
+**
+** Made by olivier gayot
+** Login <gayot_o@epitech.net>
+**
+** Started on Wed Apr 25 23:40:24 2012 olivier gayot
+** Last update Wed Apr 25 23:40:24 2012 olivier gayot
+*/
+
+#include "minesweeper.h"
+
+int xSDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dest, SDL_Rect *dstrect) {
+ int ret;
+ if (dest != scr)
+ ret = SDL_BlitSurface(src, srcrect, dest, dstrect);
+ else
+ {
+ if (SDL_mutexP(mutex) == -1)
+ fprintf(stderr, "Error during SDL_mutexP: %s\n", SDL_GetError());
+ ret = SDL_BlitSurface(src, srcrect, dest, dstrect);
+ if (SDL_mutexV(mutex) == -1)
+ fprintf(stderr, "Error during SDL_mutexV: %s\n", SDL_GetError());
+ }
+ return (ret);
+}
+
+void xSDL_Flip(SDL_Surface *surf) {
+ if (surf == scr)
+ SDL_mutexP(mutex);
+ SDL_Flip(surf);
+ if (surf == scr)
+ SDL_mutexV(mutex);
+}