aboutsummaryrefslogtreecommitdiff
path: root/src/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/text')
-rw-r--r--src/text/main.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/text/main.c b/src/text/main.c
new file mode 100644
index 0000000..bcf53a1
--- /dev/null
+++ b/src/text/main.c
@@ -0,0 +1,190 @@
+#include <stdbool.h> // bool
+#include <string.h> // atoi()
+#include <stdlib.h> // EXIT_{FAILURE,SUCCESS}
+#include <stdio.h>
+#include "../libsok/sok.h"
+
+#define UNUSED(a) ((void) (a))
+
+static const char * const
+LEVELS[] = {
+ "5#|#@$.#|5#",
+ "7#|3#.3#|3#$3#|#.$@$.#|3#$3#|3#.3#|7#",
+};
+#define NUM_LEVELS (sizeof(LEVELS) / sizeof(char*))
+
+static char print_buf[(SOK_LEVEL_MAX_WIDTH + 1) * SOK_LEVEL_MAX_HEIGHT + 1];
+
+static bool
+on_size(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t size,
+ void * const data
+) {
+ UNUSED(ctx);
+ UNUSED(data);
+
+ // fprintf(stderr, "size: x = %u, y = %u\n", size.x, size.y);
+
+ memset(print_buf, ' ', sizeof(print_buf));
+ print_buf[(size.x + 1) * size.y + 1] = '\0';
+ for (size_t i = 0; i < size.y; i++) {
+ print_buf[(i + 1) * (size.x + 1) - 1] = '\n';
+ }
+
+ return true;
+}
+
+static bool
+on_home(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_goal,
+ void * const data
+) {
+ UNUSED(data);
+ print_buf[pos.y * (ctx->level.size.x + 1) + pos.x] = has_goal ? '+' : '@';
+ return true;
+}
+
+static bool
+on_wall(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ void * const data
+) {
+ // fprintf(stderr, "wall: x = %u, y = %u\n", pos.x, pos.y);
+ UNUSED(data);
+ print_buf[pos.y * (ctx->level.size.x + 1) + pos.x] = '#';
+ return true;
+}
+
+static bool
+on_goal(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_player,
+ const bool has_box,
+ void * const data
+) {
+ UNUSED(data);
+ const char c = has_player ? '+' : (has_box ? '*' : '.');
+ print_buf[pos.y * (ctx->level.size.x + 1) + pos.x] = c;
+ return true;
+}
+
+static bool
+on_box(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos,
+ const bool has_goal,
+ void * const data
+) {
+ UNUSED(data);
+ print_buf[pos.y * (ctx->level.size.x + 1) + pos.x] = has_goal ? '*' : '$';
+ return true;
+}
+
+static sok_ctx_walk_cbs_t PRINT_CBS = {
+ .on_size = on_size,
+ .on_home = on_home,
+ .on_wall = on_wall,
+ .on_goal = on_goal,
+ .on_box = on_box,
+};
+
+static void
+print_level(
+ const sok_ctx_t * const ctx
+) {
+ // fill buffer
+ if (!sok_ctx_walk(ctx, &PRINT_CBS, NULL)) {
+ fprintf(stderr, "Couldn't print level\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // print level
+ printf("%s\n", print_buf);
+}
+
+int main(int argc, char *argv[]) {
+ size_t level = (argc > 1) ? atoi(argv[1]) : 0;
+
+ // init context
+ sok_ctx_t ctx;
+ sok_ctx_init(&ctx, NULL);
+
+ if (!sok_ctx_set_level(&ctx, LEVELS[level])) {
+ fprintf(stderr, "Couldn't load level %zu\n", level);
+ return EXIT_FAILURE;
+ }
+
+ char buf[1024];
+ bool done = false;
+ while (!done) {
+ print_level(&ctx);
+ printf("%zu%s> ", ctx.num_moves, sok_ctx_is_done(&ctx) ? " (won!)" : "");
+
+ if (!fgets(buf, sizeof(buf), stdin)) {
+ done = true;
+ break;
+ }
+
+ switch (buf[0]) {
+ case EOF:
+ case 'q':
+ done = true;
+ break;
+ case 'k':
+ if (!sok_ctx_move(&ctx, SOK_DIR_UP)) {
+ fprintf(stderr, "W: move up failed\n");
+ }
+
+ break;
+ case 'h':
+ if (!sok_ctx_move(&ctx, SOK_DIR_LEFT)) {
+ fprintf(stderr, "W: move left failed\n");
+ }
+
+ break;
+ case 'j':
+ if (!sok_ctx_move(&ctx, SOK_DIR_DOWN)) {
+ fprintf(stderr, "W: move down failed\n");
+ }
+
+ break;
+ case 'l':
+ if (!sok_ctx_move(&ctx, SOK_DIR_RIGHT)) {
+ fprintf(stderr, "W: move right failed\n");
+ }
+
+ break;
+ case 'u':
+ if (!sok_ctx_undo(&ctx)) {
+ fprintf(stderr, "W: undo failed\n");
+ }
+
+ break;
+ case 'n':
+ if (sok_ctx_is_done(&ctx)) {
+ // advance level
+ level = (level + 1) % NUM_LEVELS;
+
+ // load next level
+ if (!sok_ctx_set_level(&ctx, LEVELS[level])) {
+ fprintf(stderr, "Couldn't load level %zu\n", level);
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "W: cannot advance to next level\n");
+ }
+
+ break;
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ return 0;
+}