diff options
author | Paul Duncan <pabs@pablotron.org> | 2019-01-07 22:05:19 -0500 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2019-01-07 22:05:19 -0500 |
commit | c31caa18f969199a3fb91995ae08b29368cf010d (patch) | |
tree | ce48c67b8394db3e9d5c6077ea06f5244785940f /src/libsok/sok-level-parser.c | |
parent | ad4c3bf0154aae2adedd4ecf7239e30e2d5f9e1c (diff) | |
download | sok-c31caa18f969199a3fb91995ae08b29368cf010d.tar.bz2 sok-c31caa18f969199a3fb91995ae08b29368cf010d.zip |
reorganize src/, add support for RLE
Diffstat (limited to 'src/libsok/sok-level-parser.c')
-rw-r--r-- | src/libsok/sok-level-parser.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/libsok/sok-level-parser.c b/src/libsok/sok-level-parser.c new file mode 100644 index 0000000..75ac133 --- /dev/null +++ b/src/libsok/sok-level-parser.c @@ -0,0 +1,192 @@ +#include <stdbool.h> +#include <stddef.h> // size_t +#include "sok.h" + +#define UNUSED(a) ((void) (a)) + +#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') +#define CASE_DIGIT \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9': + +void +sok_level_parser_init( + sok_level_parser_t * const parser, + const sok_level_parser_cbs_t * const cbs, + void * const user_data +) { + parser->cbs = cbs; + parser->user_data = user_data; +} + +bool +sok_level_parser_parse( + sok_level_parser_t * const parser, + const char * const buf, + const size_t buf_len +) { + sok_pos_t size = { .x = 0, .y = 0 }; + + for (size_t i = 0, ofs = 0, w = 0; i < buf_len; i++) { + if (buf[i] == '|') { + if (w > size.x) { + size.x = w; + } + + // reset column position, increment row count + w = 0; + size.y++; + } else if (IS_DIGIT(buf[i])) { + ofs = 10 * ofs + (buf[i] - '0'); + } else if (ofs > 0) { + w += ofs; + ofs = 0; + } else { + w++; + } + } + + // increment row count + size.y++; + + // emit level size + if ( + parser->cbs->on_size && + !parser->cbs->on_size(parser, size) + ) { + // return failure + return false; + } + + sok_pos_t pos = { 0, 0 }; + for (size_t i = 0, ofs = 0; i < buf_len; i++) { + switch (buf[i]) { + case '|': + // new line + pos.x = 0; + pos.y++; + + break; + CASE_DIGIT + ofs = 10 * ofs + (buf[i] - '0'); + break; + case '-': + case '_': + case ' ': + // advance + pos.x += (ofs > 0) ? ofs : 1; + + break; + case '+': + // emit goal + if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { + // return failure + return false; + } + + // emit home + if (parser->cbs->on_home && !parser->cbs->on_home(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + + break; + case '@': + // emit home + if (parser->cbs->on_home && !parser->cbs->on_home(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + + break; + case '#': + for (size_t j = (ofs > 0) ? ofs : 1; j; j--) { + // emit wall + if (parser->cbs->on_wall && !parser->cbs->on_wall(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + } + ofs = 0; + + break; + case '*': + for (size_t j = (ofs > 0) ? ofs : 1; j--;) { + // emit goal + if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { + // return failure + return false; + } + + // emit box + if (parser->cbs->on_box && !parser->cbs->on_box(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + } + ofs = 0; + + break; + case '.': + for (size_t j = (ofs > 0) ? ofs : 1; j--;) { + // emit goal + if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + } + ofs = 0; + + break; + case '$': + for (size_t j = (ofs > 0) ? ofs : 1; j--;) { + // emit box + if (parser->cbs->on_box && !parser->cbs->on_box(parser, pos)) { + // return failure + return false; + } + + // advance + pos.x++; + } + ofs = 0; + + break; + default: + // emit junk + if (parser->cbs->on_junk && !parser->cbs->on_junk(parser, i, buf[i])) { + // return failure + return false; + } + + // return failure + return false; + } + } + + // return success + return true; +} |