aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-01-12 15:34:56 -0500
committerPaul Duncan <pabs@pablotron.org>2019-01-12 15:34:56 -0500
commit8d45b2b70143972f6b7862835b8ae9876f49e214 (patch)
treefff3580aea54b0b33e5f6649b6371676d02de9f8 /src
parent3d0b7418b2c1a87d44144749f5f055cfa0995f6c (diff)
downloadsok-8d45b2b70143972f6b7862835b8ae9876f49e214.tar.bz2
sok-8d45b2b70143972f6b7862835b8ae9876f49e214.zip
functioning sdl
Diffstat (limited to 'src')
-rw-r--r--src/sdl/action.c63
-rw-r--r--src/sdl/action.h27
-rw-r--r--src/sdl/main.c301
3 files changed, 390 insertions, 1 deletions
diff --git a/src/sdl/action.c b/src/sdl/action.c
new file mode 100644
index 0000000..a4dcb79
--- /dev/null
+++ b/src/sdl/action.c
@@ -0,0 +1,63 @@
+#include "../libsok/sok.h"
+#include "action.h"
+
+#define CASE_DIGIT \
+ case SDLK_0: \
+ case SDLK_1: \
+ case SDLK_2: \
+ case SDLK_3: \
+ case SDLK_4: \
+ case SDLK_5: \
+ case SDLK_6: \
+ case SDLK_7: \
+ case SDLK_8: \
+ case SDLK_9:
+
+static const sok_dir_t
+keycode_to_dir(const SDL_Keycode code) {
+ switch (code) {
+ case SDLK_UP: return SOK_DIR_UP;
+ case SDLK_LEFT: return SOK_DIR_LEFT;
+ case SDLK_DOWN: return SOK_DIR_DOWN;
+ case SDLK_RIGHT: return SOK_DIR_RIGHT;
+ default: return SOK_DIR_LAST;
+ }
+}
+
+action_t
+get_action(
+ const SDL_Keycode code
+) {
+ switch (code) {
+ case SDLK_ESCAPE:
+ case SDLK_q:
+ return (action_t) { .type = ACTION_QUIT };
+ case SDLK_UP:
+ case SDLK_DOWN:
+ case SDLK_LEFT:
+ case SDLK_RIGHT:
+ return (action_t) {
+ .type = ACTION_MOVE,
+ .data = keycode_to_dir(code)
+ };
+ case SDLK_u:
+ return (action_t) { .type = ACTION_UNDO };
+ case SDLK_n:
+ return (action_t) { .type = ACTION_NEXT };
+ CASE_DIGIT
+ return (action_t) {
+ .type = ACTION_WARP_BUF_PUSH,
+ .data = (code - SDLK_0),
+ };
+ case SDLK_DELETE:
+ return (action_t) { .type = ACTION_WARP_BUF_POP };
+ case SDLK_RETURN:
+ return (action_t) { .type = ACTION_WARP };
+ case 'r':
+ return (action_t) { .type = ACTION_RESET };
+ case 's':
+ return (action_t) { .type = ACTION_SOLVE };
+ default:
+ return (action_t) { .type = ACTION_NONE };
+ }
+}
diff --git a/src/sdl/action.h b/src/sdl/action.h
new file mode 100644
index 0000000..d6d9870
--- /dev/null
+++ b/src/sdl/action.h
@@ -0,0 +1,27 @@
+#ifndef ACTION_H
+#define ACTION_H
+
+#include <SDL.h>
+
+typedef enum {
+ ACTION_NONE,
+ ACTION_QUIT,
+ ACTION_MOVE,
+ ACTION_WARP,
+ ACTION_WARP_BUF_PUSH,
+ ACTION_WARP_BUF_POP,
+ ACTION_UNDO,
+ ACTION_NEXT,
+ ACTION_SOLVE,
+ ACTION_RESET,
+ ACTION_LAST,
+} action_type_t;
+
+typedef struct {
+ action_type_t type;
+ uint64_t data;
+} action_t;
+
+action_t get_action(const SDL_Keycode);
+
+#endif /* ACTION_H */
diff --git a/src/sdl/main.c b/src/sdl/main.c
index 0fb4389..831d3f7 100644
--- a/src/sdl/main.c
+++ b/src/sdl/main.c
@@ -1,3 +1,302 @@
+#include <stdbool.h> // bool
+#include <stdlib.h> // EXIT_{FAILURE,SUCCESS}
+#include <string.h> // strerror
+#include <errno.h> // errno
+#include <SDL.h>
+#include <SDL_image.h>
+#include "../text/levels.h"
+#include "../libsok/sok.h"
+#include "action.h"
+
+#define warn(...) do { \
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__); \
+} while (0)
+
+#define die(...) do { \
+ SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__); \
+ exit(EXIT_FAILURE); \
+} while (0)
+
+static void
+solve_on_error(
+ const char * const err
+) {
+ die("Error solving level: %s", err);
+}
+
+static void
+draw_moves(
+ const sok_ctx_t * const ctx,
+ const size_t skip_moves
+) {
+ printf("Solution (%zu moves): ", ctx->num_moves - skip_moves);
+ for (size_t i = skip_moves; i < ctx->num_moves; i++) {
+ if (ctx->moves[i].dir >= SOK_DIR_LAST) {
+ die("invalid move: %u", ctx->moves[i].dir);
+ }
+
+ fputs(SOK_DIR_TO_STR(ctx->moves[i].dir), stdout);
+ }
+ printf("\n");
+}
+
+static const SDL_Color
+RED = { .r = 0x00, .g = 0xFF, .b = 0x00, .a = 0xFF },
+BLACK = { .r = 0x00, .g = 0x00, .b = 0x00, .a = 0xFF };
+
+static SDL_Color
+get_bg(
+ const sok_ctx_t * const ctx
+) {
+ return (sok_ctx_is_done(ctx)) ? RED : BLACK;
+}
+
+bool draw_on_wall(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ void * const data
+) {
+ SDL_Renderer *renderer = data;
+ SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 };
+
+ SDL_SetRenderDrawColor(renderer, 0x66, 0x66, 0x66, 0xFF);
+
+ if (SDL_RenderFillRect(renderer, &rect)) {
+ die("SDL_RenderFillRect(): %s", SDL_GetError());
+ }
+
+ return true;
+}
+
+bool draw_on_goal(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_player,
+ const bool has_box,
+ void * const data
+) {
+ SDL_Renderer *renderer = data;
+ SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 };
+
+ SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
+
+ if (SDL_RenderFillRect(renderer, &rect)) {
+ die("SDL_RenderFillRect(): %s", SDL_GetError());
+ }
+
+ return true;
+}
+
+bool draw_on_home(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_goal,
+ void * const data
+) {
+ SDL_Renderer *renderer = data;
+ SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 };
+
+ SDL_SetRenderDrawColor(renderer, 0xFF, has_goal ? 0xFF : 0x00, 0x00, 0xFF);
+
+ if (SDL_RenderFillRect(renderer, &rect)) {
+ die("SDL_RenderFillRect(): %s", SDL_GetError());
+ }
+
+ return true;
+}
+
+bool draw_on_box(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_goal,
+ void * const data
+) {
+ SDL_Renderer *renderer = data;
+ SDL_Rect rect = { 32 * pos.x, 32 * pos.y, 32, 32 };
+
+ SDL_SetRenderDrawColor(renderer, 0x00, has_goal ? 0xFF : 0x00, 0xFF, 0xFF);
+
+ if (SDL_RenderFillRect(renderer, &rect)) {
+ die("SDL_RenderFillRect(): %s", SDL_GetError());
+ }
+
+ return true;
+}
+
+static sok_ctx_walk_cbs_t
+DRAW_CBS = {
+ .on_wall = draw_on_wall,
+ .on_goal = draw_on_goal,
+ .on_home = draw_on_home,
+ .on_box = draw_on_box,
+};
+/*
+ * typedef struct {
+ * sok_ctx_walk_pos_cb_t on_size,
+ * on_wall;
+ * sok_ctx_walk_tile_cb_t on_home,
+ * on_box;
+ * sok_ctx_walk_goal_cb_t on_goal;
+ * sok_ctx_walk_move_cb_t on_move;
+ * } sok_ctx_walk_cbs_t;
+ *
+ * _Bool sok_ctx_walk(
+ * const sok_ctx_t * const,
+ * const sok_ctx_walk_cbs_t * const,
+ * void * const
+ * );
+ */
+
+static void
+draw(
+ SDL_Renderer * const renderer,
+ const sok_ctx_t * const ctx,
+ const size_t level_num,
+ const level_t * const level
+) {
+ // clear
+ const SDL_Color c = get_bg(ctx);
+ SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a);
+ SDL_RenderClear(renderer);
+
+ sok_ctx_walk(ctx, &DRAW_CBS, renderer);
+
+ // flip
+ SDL_RenderPresent(renderer);
+}
+
int main(int argc, char *argv[]) {
- return 0;
+ size_t warp_buf = 0;
+ size_t level_num = (argc > 1) ? atoi(argv[1]) : 0;
+ const level_t *level = levels_get_level(level_num);
+
+ // init context
+ sok_ctx_t ctx;
+ sok_ctx_init(&ctx, NULL);
+
+ if (!sok_ctx_set_level(&ctx, level->data)) {
+ die("Couldn't load level %zu", level_num);
+ }
+
+ // init sdl
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
+ die("SDL_Init(): %s", SDL_GetError());
+ }
+
+ if (atexit(SDL_Quit)) {
+ die("atexit(): %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ // create window and renderer
+ SDL_Window *win;
+ SDL_Renderer *renderer;
+ if (SDL_CreateWindowAndRenderer(800, 600, SDL_WINDOW_RESIZABLE, &win, &renderer)) {
+ die("SDL_CreateWindowAndRenderer(): %s", SDL_GetError());
+ }
+
+ bool done = false;
+ SDL_Event ev;
+ while (!done) {
+ while (SDL_PollEvent(&ev)) {
+ switch (ev.type) {
+ case SDL_QUIT:
+ done = true;
+ break;
+ case SDL_KEYUP:
+ {
+ const action_t action = get_action(ev.key.keysym.sym);
+
+ switch (action.type) {
+ case ACTION_QUIT:
+ done = true;
+ break;
+ case ACTION_MOVE:
+ if (!sok_ctx_move(&ctx, (sok_dir_t) action.data)) {
+ warn("move %s failed", SOK_DIR_TO_STR((sok_dir_t) action.data));
+ }
+
+ break;
+ case ACTION_UNDO:
+ if (!sok_ctx_undo(&ctx)) {
+ warn("undo failed");
+ }
+
+ break;
+ case ACTION_NEXT:
+ if (sok_ctx_is_done(&ctx)) {
+ // advance level
+ level_num++;
+ level = levels_get_level(level_num);
+
+ // load next level
+ if (!sok_ctx_set_level(&ctx, level->data)) {
+ die("Couldn't load level %zu", level_num);
+ }
+ } else {
+ warn("cannot advance to next level");
+ }
+
+ break;
+ case ACTION_RESET:
+ // reset level
+ if (!sok_ctx_set_level(&ctx, level->data)) {
+ die("Couldn't load level %zu", level_num);
+ }
+
+ break;
+ case ACTION_WARP:
+ level_num = warp_buf;
+ level = levels_get_level(level_num);
+
+ // load level
+ if (!sok_ctx_set_level(&ctx, level->data)) {
+ die("Couldn't load level %zu", level_num);
+ }
+
+ warp_buf = 0;
+
+ break;
+ case ACTION_WARP_BUF_PUSH:
+ warp_buf = 10 * warp_buf + action.data;
+
+ break;
+ case ACTION_WARP_BUF_POP:
+ warp_buf /= 10;
+
+ break;
+ case ACTION_SOLVE:
+ {
+ // get current number of moves
+ const size_t old_num_moves = ctx.num_moves;
+
+ if (sok_solve(&ctx, solve_on_error)) {
+ // found solution, print it
+ draw_moves(&ctx, old_num_moves);
+ } else {
+ warn("Couldn't solve level");
+ }
+ }
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ break;
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ draw(renderer, &ctx, level_num, level);
+ }
+
+ // fini renderer, window
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(win);
+
+ // return success
+ return EXIT_SUCCESS;
}