aboutsummaryrefslogtreecommitdiff
path: root/src/libsok/sok-ctx.c
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-01-08 11:33:24 -0500
committerPaul Duncan <pabs@pablotron.org>2019-01-08 11:33:24 -0500
commitfa56925a5de7384c03f4775822444095d38bf3ac (patch)
tree9a99bf48267b679d8aea48258fca0b41125e8ddb /src/libsok/sok-ctx.c
parent9e8d15918e5f3317fc0f7980bc6d07aca8fbc12d (diff)
downloadsok-fa56925a5de7384c03f4775822444095d38bf3ac.tar.bz2
sok-fa56925a5de7384c03f4775822444095d38bf3ac.zip
simplify move logic, add cache and solver
Diffstat (limited to 'src/libsok/sok-ctx.c')
-rw-r--r--src/libsok/sok-ctx.c400
1 files changed, 87 insertions, 313 deletions
diff --git a/src/libsok/sok-ctx.c b/src/libsok/sok-ctx.c
index cc6b1ce..d9985d7 100644
--- a/src/libsok/sok-ctx.c
+++ b/src/libsok/sok-ctx.c
@@ -191,116 +191,37 @@ tile_is_floor(
);
}
-static bool
-tile_is_box(
- const sok_ctx_t * const ctx,
- const sok_pos_t pos
+static size_t
+pos_find(
+ const sok_pos_t pos,
+ const sok_pos_t * const set,
+ const size_t len
) {
- for (size_t i = 0; i < ctx->level.num_boxes; i++) {
- if (POINTS_EQUAL(ctx->boxes[i], pos)) {
- return true;
+ for (size_t i = 0; i < len; i++) {
+ if (POINTS_EQUAL(pos, set[i])) {
+ return i;
}
}
- return false;
+ return len;
}
static bool
-tile_is_goal(
+tile_is_box(
const sok_ctx_t * const ctx,
const sok_pos_t pos
) {
- for (size_t i = 0; i < ctx->level.num_goals; i++) {
- if (POINTS_EQUAL(pos, ctx->level.goals[i])) {
- return true;
- }
- }
-
- return false;
+ const size_t num_boxes = ctx->level.num_boxes;
+ return pos_find(pos, ctx->boxes, num_boxes) < num_boxes;
}
static bool
-sok_can_move(
- sok_ctx_t * const ctx,
- const sok_dir_t dir
+tile_is_goal(
+ const sok_ctx_t * const ctx,
+ const sok_pos_t pos
) {
- if (ctx->num_moves >= SOK_CTX_MAX_MOVES - 1) {
- // no more move slots available
- return false;
- }
-
- if (dir == SOK_DIR_UP) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x, .y = ctx->home.y - 1 },
- { .x = ctx->home.x, .y = ctx->home.y - 2 },
- };
-
- return ((
- (ctx->home.y > 0) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) || (
- (ctx->home.y > 1) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ));
- } else if (dir == SOK_DIR_DOWN) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x, .y = ctx->home.y + 1 },
- { .x = ctx->home.x, .y = ctx->home.y + 2 },
- };
-
- return ((
- (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 1) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) || (
- (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 2) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ));
- } else if (dir == SOK_DIR_LEFT) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x - 1, .y = ctx->home.y },
- { .x = ctx->home.x - 2, .y = ctx->home.y },
- };
-
- return ((
- (ctx->home.x > 0) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) || (
- (ctx->home.x > 1) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ));
- } else if (dir == SOK_DIR_RIGHT) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x + 1, .y = ctx->home.y },
- { .x = ctx->home.x + 2, .y = ctx->home.y },
- };
-
- return ((
- (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 1) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) || (
- (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 2) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ));
- }
-
- // return failure
- return false;
+ const size_t num_goals = ctx->level.num_goals;
+ return pos_find(pos, ctx->level.goals, num_goals) < num_goals;
}
static bool
@@ -349,11 +270,12 @@ sok_ctx_move_box(
const sok_pos_t old_pos,
const sok_pos_t new_pos
) {
- for (size_t i = 0; i < ctx->level.num_boxes; i++) {
- if (POINTS_EQUAL(ctx->boxes[i], old_pos)) {
- ctx->boxes[i] = new_pos;
- return true;
- }
+ const size_t num_boxes = ctx->level.num_boxes,
+ box_ofs = pos_find(old_pos, ctx->boxes, num_boxes);
+
+ if (box_ofs < num_boxes) {
+ ctx->boxes[box_ofs] = new_pos;
+ return true;
}
return false;
@@ -364,17 +286,7 @@ sok_ctx_is_done(
sok_ctx_t * const ctx
) {
for (size_t i = 0; i < ctx->level.num_goals; i++) {
- bool on_goal = false;
-
- for (size_t j = 0; !on_goal && j < ctx->level.num_boxes; j++) {
- if (POINTS_EQUAL(ctx->level.goals[i], ctx->boxes[j])) {
- // found box on this goal
- on_goal = true;
- }
- }
-
- if (!on_goal) {
- // no box on this goal, return false
+ if (!tile_is_box(ctx, ctx->level.goals[i])) {
return false;
}
}
@@ -388,186 +300,75 @@ sok_ctx_move(
sok_ctx_t * const ctx,
const sok_dir_t dir
) {
- if (!sok_can_move(ctx, dir)) {
+ if (ctx->num_moves >= SOK_CTX_MAX_MOVES - 1) {
+ // no more move slots available
return false;
}
- if (dir == SOK_DIR_UP) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x, .y = ctx->home.y - 1 },
- { .x = ctx->home.x, .y = ctx->home.y - 2 },
- };
-
- if (
- (ctx->home.y > 0) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, false)) {
- return false;
- }
-
- // update position
- ctx->home.y--;
-
- // return success
- return true;
- } else if (
- (ctx->home.y > 1) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, true)) {
- return false;
- }
-
- // move box
- if (!sok_ctx_move_box(ctx, ps[0], ps[1])) {
- return false;
- }
-
- // update position
- ctx->home.y--;
-
- // return success
- return true;
+ const sok_pos_t ps[2] = {{
+ .x = ctx->home.x + ((dir == SOK_DIR_LEFT) ? -1 : ((dir == SOK_DIR_RIGHT) ? 1 : 0)),
+ .y = ctx->home.y + ((dir == SOK_DIR_UP) ? -1 : ((dir == SOK_DIR_DOWN) ? 1 : 0))
+ }, {
+ .x = ctx->home.x + ((dir == SOK_DIR_LEFT) ? -2 : ((dir == SOK_DIR_RIGHT) ? 2 : 0)),
+ .y = ctx->home.y + ((dir == SOK_DIR_UP) ? -2 : ((dir == SOK_DIR_DOWN) ? 2 : 0))
+ }};
+
+ const bool can_move = (
+ (dir == SOK_DIR_UP) ? (ctx->home.y > 0) :
+ ((dir == SOK_DIR_DOWN) ? (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 1) :
+ ((dir == SOK_DIR_LEFT) ? (ctx->home.x > 0) :
+ ((dir == SOK_DIR_RIGHT) ? (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 1) :
+ false
+ ))));
+
+ const bool can_push = (
+ (dir == SOK_DIR_UP) ? (ctx->home.y > 1) :
+ ((dir == SOK_DIR_DOWN) ? (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 2) :
+ ((dir == SOK_DIR_LEFT) ? (ctx->home.x > 1) :
+ ((dir == SOK_DIR_RIGHT) ? (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 2) :
+ false
+ ))));
+
+ if (
+ can_move &&
+ tile_is_floor(ctx, ps[0]) &&
+ !tile_is_box(ctx, ps[0])
+ ) {
+ // push move
+ if (!sok_ctx_push_move(ctx, dir, false)) {
+ return false;
}
- } else if (dir == SOK_DIR_DOWN) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x, .y = ctx->home.y + 1 },
- { .x = ctx->home.x, .y = ctx->home.y + 2 },
- };
- if (
- (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 1) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, false)) {
- return false;
- }
-
- // update position
- ctx->home.y++;
-
- // return success
- return true;
- } else if (
- (ctx->home.y < SOK_LEVEL_MAX_HEIGHT - 2) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, true)) {
- return false;
- }
-
- // move box
- if (!sok_ctx_move_box(ctx, ps[0], ps[1])) {
- return false;
- }
-
- // update position
- ctx->home.y++;
-
- // return success
- return true;
+ // update position
+ ctx->home.x += (dir == SOK_DIR_LEFT) ? -1 : ((dir == SOK_DIR_RIGHT) ? 1 : 0);
+ ctx->home.y += (dir == SOK_DIR_UP) ? -1 : ((dir == SOK_DIR_DOWN) ? 1 : 0);
+
+ // return success
+ return true;
+ } else if (
+ can_push &&
+ tile_is_floor(ctx, ps[0]) &&
+ tile_is_box(ctx, ps[0]) &&
+ tile_is_floor(ctx, ps[1]) &&
+ !tile_is_box(ctx, ps[1])
+ ) {
+ // push move
+ if (!sok_ctx_push_move(ctx, dir, true)) {
+ return false;
}
- } else if (dir == SOK_DIR_LEFT) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x - 1, .y = ctx->home.y },
- { .x = ctx->home.x - 2, .y = ctx->home.y },
- };
-
- if (
- (ctx->home.x > 1) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, false)) {
- return false;
- }
-
- // update position
- ctx->home.x--;
-
- // return success
- return true;
- } else if (
- (ctx->home.x > 1) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, true)) {
- return false;
- }
- // move box
- if (!sok_ctx_move_box(ctx, ps[0], ps[1])) {
- return false;
- }
-
- // update position
- ctx->home.x--;
-
- // return success
- return true;
+ // move box
+ if (!sok_ctx_move_box(ctx, ps[0], ps[1])) {
+ return false;
}
- } else if (dir == SOK_DIR_RIGHT) {
- const sok_pos_t ps[2] = {
- { .x = ctx->home.x + 1, .y = ctx->home.y },
- { .x = ctx->home.x + 2, .y = ctx->home.y },
- };
-
- if (
- (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 1) &&
- tile_is_floor(ctx, ps[0]) &&
- !tile_is_box(ctx, ps[0])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, false)) {
- return false;
- }
-
- // update position
- ctx->home.x++;
-
- // return success
- return true;
- } else if (
- (ctx->home.x < SOK_LEVEL_MAX_WIDTH - 2) &&
- tile_is_floor(ctx, ps[0]) &&
- tile_is_box(ctx, ps[0]) &&
- tile_is_floor(ctx, ps[1]) &&
- !tile_is_box(ctx, ps[1])
- ) {
- // push move
- if (!sok_ctx_push_move(ctx, dir, true)) {
- return false;
- }
- // move box
- if (!sok_ctx_move_box(ctx, ps[0], ps[1])) {
- return false;
- }
+ // update position
+ ctx->home.x += (dir == SOK_DIR_LEFT) ? -1 : ((dir == SOK_DIR_RIGHT) ? 1 : 0);
+ ctx->home.y += (dir == SOK_DIR_UP) ? -1 : ((dir == SOK_DIR_DOWN) ? 1 : 0);
- // update position
- ctx->home.x++;
- // return success
- return true;
- }
+ // return success
+ return true;
}
// return failure
@@ -585,39 +386,12 @@ sok_ctx_undo(
}
if (move.is_push) {
- switch (move.dir) {
- case SOK_DIR_UP:
- {
- const sok_pos_t box_pos = { move.pos.x, move.pos.y - 2 };
- sok_ctx_move_box(ctx, box_pos, ctx->home);
- }
-
- break;
- case SOK_DIR_DOWN:
- {
- const sok_pos_t box_pos = { move.pos.x, move.pos.y + 2 };
- sok_ctx_move_box(ctx, box_pos, ctx->home);
- }
-
- break;
- case SOK_DIR_LEFT:
- {
- const sok_pos_t box_pos = { move.pos.x - 2, move.pos.y };
- sok_ctx_move_box(ctx, box_pos, ctx->home);
- }
-
- break;
- case SOK_DIR_RIGHT:
- {
- const sok_pos_t box_pos = { move.pos.x + 2, move.pos.y };
- sok_ctx_move_box(ctx, box_pos, ctx->home);
- }
+ const sok_pos_t box_pos = {
+ .x = move.pos.x + ((move.dir == SOK_DIR_LEFT) ? -2 : ((move.dir == SOK_DIR_RIGHT) ? 2 : 0)),
+ .y = move.pos.y + ((move.dir == SOK_DIR_UP) ? -2 : ((move.dir == SOK_DIR_DOWN) ? 2 : 0)),
+ };
- break;
- default:
- // never reached
- return false;
- }
+ sok_ctx_move_box(ctx, box_pos, ctx->home);
}
// update position