aboutsummaryrefslogtreecommitdiff
path: root/src/text/main.c
blob: 8e89beda13486fffedf8457eb61154cfe7cae600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <stdbool.h> // bool
#include <string.h> // atoi()
#include <stdlib.h> // EXIT_{FAILURE,SUCCESS}
#include <stdio.h> // printf(), fputs()
#include "../core/sok.h"
#include "../levels/levels.h"
#include "util.h"
#include "action.h"
#include "draw.h"

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 (%d moves): ", (int) (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");
}

int main(int argc, char *argv[]) {
  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 %d", (int) level_num);
  }

  bool done = false;
  while (!done) {
    // draw screen
    draw(&ctx, level_num, level);

    // read input, check for error
    const action_t action = get_action();

    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 %d", (int) 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 %d", (int) level_num);
      }

      break;
    case ACTION_WARP:
      level_num = action.data;
      level = levels_get_level(level_num);

      // load level
      if (!sok_ctx_set_level(&ctx, level->data)) {
        die("Couldn't load level %d", (int) level_num);
      }

      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");
        }
      }

      break;
    default:
      // ignore
      break;
    }
  }

  // return success
  return EXIT_SUCCESS;
}