aboutsummaryrefslogtreecommitdiff
path: root/src/sok-level-parser.c
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-01-07 19:46:00 -0500
committerPaul Duncan <pabs@pablotron.org>2019-01-07 19:46:00 -0500
commit6c5f348397d092fb2630496d22f4328404d762d5 (patch)
treeb31f8181e8540c01cff1127865643b6b59101d31 /src/sok-level-parser.c
downloadsok-6c5f348397d092fb2630496d22f4328404d762d5.tar.bz2
sok-6c5f348397d092fb2630496d22f4328404d762d5.zip
initial commit
Diffstat (limited to 'src/sok-level-parser.c')
-rw-r--r--src/sok-level-parser.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/sok-level-parser.c b/src/sok-level-parser.c
new file mode 100644
index 0000000..eec08c3
--- /dev/null
+++ b/src/sok-level-parser.c
@@ -0,0 +1,159 @@
+#include <stdbool.h>
+#include <stddef.h> // size_t
+#include "sok.h"
+
+#define UNUSED(a) ((void) (a))
+
+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, 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 {
+ 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; i < buf_len; i++) {
+ switch (buf[i]) {
+ case '|':
+ // new line
+ pos.x = 0;
+ pos.y++;
+
+ break;
+ case '-':
+ case '_':
+ case ' ':
+ // advance
+ pos.x++;
+
+ 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 '#':
+ // emit wall
+ if (parser->cbs->on_wall && !parser->cbs->on_wall(parser, pos)) {
+ // return failure
+ return false;
+ }
+
+ // advance
+ pos.x++;
+
+ break;
+ case '*':
+ // 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++;
+
+ break;
+ case '.':
+ // emit goal
+ if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) {
+ // return failure
+ return false;
+ }
+
+ // advance
+ pos.x++;
+
+ break;
+ case '$':
+ // emit box
+ if (parser->cbs->on_box && !parser->cbs->on_box(parser, pos)) {
+ // return failure
+ return false;
+ }
+
+ // advance
+ pos.x++;
+
+ 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;
+}