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>
#include "../libsok/sok.h"
#include "util.h"
#include "levels.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 (%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");
}
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 %zu", 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 %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 = action.data;
level = levels_get_level(level_num);
// load level
if (!sok_ctx_set_level(&ctx, level->data)) {
die("Couldn't load level %zu", 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;
}
|