diff options
author | Paul Duncan <pabs@pablotron.org> | 2019-01-15 09:16:56 -0500 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2019-01-15 09:16:56 -0500 |
commit | 3e658ed87b5795b2be8f50d683dc19241aba0111 (patch) | |
tree | 0bc3b6e61e476e7ecdcb3c20429b159ea5465ae2 /src/libsok/sok-ctx.c | |
parent | 914ca426630ccadcbb6f1ff02a599bdaf10b6cb2 (diff) | |
download | sok-3e658ed87b5795b2be8f50d683dc19241aba0111.tar.bz2 sok-3e658ed87b5795b2be8f50d683dc19241aba0111.zip |
s/libsok/core/g
Diffstat (limited to 'src/libsok/sok-ctx.c')
-rw-r--r-- | src/libsok/sok-ctx.c | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/src/libsok/sok-ctx.c b/src/libsok/sok-ctx.c deleted file mode 100644 index e278af1..0000000 --- a/src/libsok/sok-ctx.c +++ /dev/null @@ -1,636 +0,0 @@ -#include <stdbool.h> -#include <string.h> // memset() -#include "sok.h" - -#define UNUSED(a) ((void) (a)) - -#define VALID_POS(pos) ( \ - (pos).x < SOK_LEVEL_MAX_WIDTH && \ - (pos).y < SOK_LEVEL_MAX_HEIGHT \ -) - -#define POINTS_EQUAL(a, b) ( \ - ((a).x == (b).x) && \ - ((a).y == (b).y) \ -) - -static bool -ctx_is_wall( - const sok_ctx_t * const ctx, - const sok_pos_t pos -) { - return ctx->level.walls[pos.y * ctx->level.size.x + pos.x]; -} - -static void -ctx_set_wall( - sok_ctx_t * const ctx, - const sok_pos_t pos -) { - ctx->level.walls[pos.y * ctx->level.size.x + pos.x] = true; -} - -static void -ctx_clear_walls( - sok_ctx_t * const ctx -) { - memset(ctx->level.walls, 0, SOK_LEVEL_MAX_WIDTH * SOK_LEVEL_MAX_HEIGHT); -} - -static bool -on_size( - const sok_level_parser_t * const parser, - const sok_pos_t pos -) { - sok_ctx_t *ctx = (sok_ctx_t*) parser->user_data; - - if (!VALID_POS(pos)) { - // size out of bounds - return false; - } - - // save width and height - ctx->level.size = pos; - - // return success - return true; -} - -static bool -on_home( - const sok_level_parser_t * const parser, - const sok_pos_t pos -) { - sok_ctx_t *ctx = (sok_ctx_t*) parser->user_data; - - if (!VALID_POS(pos)) { - // position out of bounds - return false; - } - - // save start position - ctx->level.home = pos; - - // return success - return true; -} - -static bool -on_wall( - const sok_level_parser_t * const parser, - const sok_pos_t pos -) { - sok_ctx_t *ctx = (sok_ctx_t*) parser->user_data; - - if (!VALID_POS(pos)) { - // position out of bounds - return false; - } - - // save wall - ctx_set_wall(ctx, pos); - - // return sucess - return true; -} - -static bool -on_goal( - const sok_level_parser_t * const parser, - const sok_pos_t pos -) { - sok_ctx_t *ctx = (sok_ctx_t*) parser->user_data; - - if (!VALID_POS(pos)) { - // position out of bounds - return false; - } - - if (ctx->level.num_goals >= SOK_LEVEL_MAX_GOALS - 1) { - // too many goals - return false; - } - - // save goal - ctx->level.goals[ctx->level.num_goals++] = pos; - - // return sucess - return true; -} - -static bool -on_box( - const sok_level_parser_t * const parser, - const sok_pos_t pos -) { - sok_ctx_t *ctx = (sok_ctx_t*) parser->user_data; - - if (!VALID_POS(pos)) { - // position out of bounds - return false; - } - - if (ctx->level.num_boxes >= SOK_LEVEL_MAX_BOXES - 1) { - // too many boxes - return false; - } - - // save box - ctx->level.boxes[ctx->level.num_boxes++] = pos; - - // return sucess - return true; -} - -static bool -on_junk( - const sok_level_parser_t * const parser, - const size_t ofs, - const char tile -) { - UNUSED(parser); - UNUSED(ofs); - UNUSED(tile); - - // TODO - - // return sucess - return true; -} - -static const sok_level_parser_cbs_t -LEVEL_PARSER_CBS = { - .on_size = on_size, - .on_home = on_home, - .on_wall = on_wall, - .on_goal = on_goal, - .on_box = on_box, - .on_junk = on_junk, -}; - -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 < len; i++) { - if (POINTS_EQUAL(pos, set[i])) { - return i; - } - } - - return len; -} - -static size_t -sok_ctx_count_goals_left( - sok_ctx_t * const ctx -) { - const size_t num_boxes = ctx->level.num_boxes; - size_t r = 0; - - for (size_t i = 0; i < ctx->level.num_goals; i++) { - r += pos_find( - ctx->level.goals[i], - ctx->boxes, - num_boxes - ) < num_boxes ? 0 : 1; - } - - return r; -} - -/* - * static bool - * sok_ctx_has_corner_boxes( - * const sok_ctx_t * const ctx - * ) { - * for (size_t i = 0; i < ctx->level.num_boxes; i++) { - * // right - * const bool r = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x + 1, - * .y = ctx->boxes[i].y, - * }); - * - * // top-right - * const bool tr = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x + 1, - * .y = ctx->boxes[i].y - 1, - * }); - * - * // top - * const bool t = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x, - * .y = ctx->boxes[i].y - 1, - * }); - * - * // top-left - * const bool tl = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x - 1, - * .y = ctx->boxes[i].y - 1, - * }); - * - * // left - * const bool l = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x - 1, - * .y = ctx->boxes[i].y, - * }); - * - * // bottom-left - * const bool bl = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x - 1, - * .y = ctx->boxes[i].y + 1, - * }); - * - * // bottom - * const bool b = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x, - * .y = ctx->boxes[i].y + 1, - * }); - * - * const bool br = ctx_is_wall(ctx, (sok_pos_t) { - * .x = ctx->boxes[i].x + 1, - * .y = ctx->boxes[i].y + 1, - * }); - * - * if ( - * (r && tr && t) || // top-right - * (t && tl && l) || // top-left - * (l && bl && b) || // bottom-left - * (b && br && r) // bottom-right - * ) { - * // return - * return true; - * } - * } - * - * return false; - * } - */ - -void -sok_ctx_init(sok_ctx_t * const ctx, void *user_data) { - memset(ctx, 0, sizeof(sok_ctx_t)); - ctx->user_data = user_data; -} - -bool -sok_ctx_set_level( - sok_ctx_t * const ctx, - const char * const str -) { - - // clear level - ctx->level.num_goals = 0; - ctx->level.num_boxes = 0; - ctx_clear_walls(ctx); - - // parse level - sok_level_parser_t parser; - sok_level_parser_init(&parser, &LEVEL_PARSER_CBS, ctx); - if (!sok_level_parser_parse(&parser, str, strlen(str))) { - // return failure - return false; - } - - // init moves, player, and boxes - ctx->num_moves = 0; - ctx->home = ctx->level.home; - memcpy(ctx->boxes, ctx->level.boxes, ctx->level.num_boxes * sizeof(sok_pos_t)); - - // count number of goals left and check whether there are - ctx->num_goals_left = sok_ctx_count_goals_left(ctx); - // ctx->is_lost = sok_ctx_is_lost(ctx); - - // return success - return true; -} - -static bool -tile_is_floor( - const sok_ctx_t * const ctx, - const sok_pos_t pos -) { - return ( - (pos.x < SOK_LEVEL_MAX_WIDTH - 1) && - (pos.y < SOK_LEVEL_MAX_HEIGHT - 1) && - !ctx_is_wall(ctx, pos) - ); -} - -static bool -tile_is_box( - const sok_ctx_t * const ctx, - const sok_pos_t pos -) { - const size_t num_boxes = ctx->level.num_boxes; - return pos_find(pos, ctx->boxes, num_boxes) < num_boxes; -} - -static bool -tile_is_goal( - const sok_ctx_t * const ctx, - const sok_pos_t pos -) { - const size_t num_goals = ctx->level.num_goals; - return pos_find(pos, ctx->level.goals, num_goals) < num_goals; -} - -static bool -sok_ctx_push_move( - sok_ctx_t * const ctx, - const sok_dir_t dir, - const bool is_push -) { - if (ctx->num_moves >= SOK_CTX_MAX_MOVES - 1) { - return false; - } - - ctx->moves[ctx->num_moves].pos = ctx->home; - ctx->moves[ctx->num_moves].dir = dir; - ctx->moves[ctx->num_moves].is_push = is_push; - ctx->num_moves++; - - return true; -} - -static bool -sok_ctx_pop_move( - sok_ctx_t * const ctx, - sok_move_t * const ret -) { - if (!ctx->num_moves) { - // return failure - return false; - } - - // decriment moves - ctx->num_moves--; - - if (ret) { - // save popped move - *ret = ctx->moves[ctx->num_moves]; - } - - // return success - return true; -} - -static bool -sok_ctx_move_box( - sok_ctx_t * const ctx, - const sok_pos_t old_pos, - const sok_pos_t new_pos -) { - const size_t num_boxes = ctx->level.num_boxes, - box_ofs = pos_find(old_pos, ctx->boxes, num_boxes); - - if (box_ofs < num_boxes) { - // update box and goal count - ctx->boxes[box_ofs] = new_pos; - ctx->num_goals_left = sok_ctx_count_goals_left(ctx); - // ctx->is_lost = sok_ctx_has_corner_boxes(ctx); - - // return success - return true; - } - - // return failure - return false; -} - -bool -sok_ctx_is_done( - const sok_ctx_t * const ctx -) { - return ctx->num_goals_left == 0; -} - -/* - * bool - * sok_ctx_is_lost( - * const sok_ctx_t * const ctx - * ) { - * return ctx->is_lost; - * } - */ - -bool -sok_ctx_move( - sok_ctx_t * const ctx, - const sok_dir_t dir -) { - if (ctx->num_moves >= SOK_CTX_MAX_MOVES - 1) { - // no more move slots available - return false; - } - - 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; - } - - // 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; - } - - // 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); - - - // return success - return true; - } - - // return failure - return false; -} - -bool -sok_ctx_undo( - sok_ctx_t * const ctx -) { - sok_move_t move; - if (!sok_ctx_pop_move(ctx, &move)) { - // return failure - return false; - } - - if (move.is_push) { - 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)), - }; - - sok_ctx_move_box(ctx, box_pos, ctx->home); - } - - // update position - ctx->home = move.pos; - - // return success - return true; -} - -bool sok_ctx_walk( - const sok_ctx_t * const ctx, - const sok_ctx_walk_cbs_t * const cbs, - void * const data -) { - if (!cbs) { - return false; - } - - if (cbs->on_size) { - // emit size - if (!cbs->on_size(ctx, ctx->level.size, data)) { - return false; - } - } - - if (cbs->on_walls_start && !cbs->on_walls_start(ctx, data)) { - return false; - } - - if (cbs->on_wall) { - // walk walls - for (size_t i = 0; i < (ctx->level.size.x * ctx->level.size.y); i++) { - const sok_pos_t pos = { - .y = i / ctx->level.size.x, - .x = i % ctx->level.size.x, - }; - - if (ctx_is_wall(ctx, pos)) { - // emit wall - if (!cbs->on_wall(ctx, pos, data)) { - return false; - } - } - } - } - - if (cbs->on_walls_end && !cbs->on_walls_end(ctx, data)) { - return false; - } - - if (cbs->on_goals_start && !cbs->on_goals_start(ctx, data)) { - return false; - } - - if (cbs->on_goal) { - // walk goals - for (size_t i = 0; i < ctx->level.num_goals; i++) { - const bool has_player = POINTS_EQUAL(ctx->level.goals[i], ctx->home); - const bool has_box = tile_is_box(ctx, ctx->level.goals[i]); - - // emit goal - if (!cbs->on_goal(ctx, ctx->level.goals[i], has_player, has_box, data)) { - return false; - } - } - } - - if (cbs->on_goals_end && !cbs->on_goals_end(ctx, data)) { - return false; - } - - if (cbs->on_boxes_start && !cbs->on_boxes_start(ctx, data)) { - return false; - } - - if (cbs->on_home) { - const bool has_goal = tile_is_goal(ctx, ctx->home); - - // emit home - if (!cbs->on_home(ctx, ctx->home, has_goal, data)) { - return false; - } - } - - if (cbs->on_box) { - // walk boxes - for (size_t i = 0; i < ctx->level.num_boxes; i++) { - const bool has_goal = tile_is_goal(ctx, ctx->boxes[i]); - - // emit box - if (!cbs->on_box(ctx, ctx->boxes[i], has_goal, data)) { - return false; - } - } - } - - if (cbs->on_boxes_end && !cbs->on_boxes_end(ctx, data)) { - return false; - } - - if (cbs->on_moves_start && !cbs->on_moves_start(ctx, data)) { - return false; - } - - if (cbs->on_move) { - // walk moves - for (size_t i = 0; i < ctx->num_moves; i++) { - // emit move - if (!cbs->on_move(ctx, ctx->moves[i], data)) { - return false; - } - } - } - - if (cbs->on_moves_end && !cbs->on_moves_end(ctx, data)) { - return false; - } - - // return success - return true; -} |