diff options
author | Adam Spragg <adam@spra.gg> | 2023-01-12 14:02:27 +0000 |
---|---|---|
committer | Adam Spragg <adam@spra.gg> | 2023-01-12 14:03:33 +0000 |
commit | 5e0e0d306116c348336a872e105d4396de7b0cfe (patch) | |
tree | 32f1161566541d92e46ba51de209545ab0b71446 | |
parent | fa82470db34f39f5c1f1df9e4524f727fbb819c2 (diff) |
Puzzle 22: Create an abstraction for "map"
This will help with some future changes
-rw-r--r-- | 22.c | 144 |
1 files changed, 99 insertions, 45 deletions
@@ -39,6 +39,85 @@ direction_name(enum direction dir) } +struct map { + char * _buf; + int cols; + int rows; + enum map_type type; +}; + + +// Initialise a map from a buffer. +// +// The map takes ownership of the buffer from when it's called, whether +// or not the initialisation is successful +struct map * +map_init(struct map * map, char * buf, size_t buflen, enum map_type type) +{ + char * beg, * end; + long pos; + + map->_buf = NULL; + map->cols = 0; + map->rows = 0; + map->type = type; + + // Work out max lines and longest line. + for (beg = buf; beg < buf + buflen; beg = end + 1, ++map->rows) { + end = memchr(beg, '\n', buf + buflen - beg); + if (end - beg > map->cols) + map->cols = end - beg; + } + if (map->cols == 0 || map->rows == 0) { + fprintf(stderr, "Unexpected map size (%d,%d)\n", map->cols, map->rows); + free(buf); + return NULL; + } + ++map->cols; // Also count the newline on the end of each line. + + // Resize the map data buffer to hold a full grid of data + if ((map->_buf = realloc(buf, map->cols * map->rows)) == NULL) { + fprintf(stderr, "Bad realloc(%d)\n", map->cols * map->rows); + free(buf); + return NULL; + } + memset(map->_buf + buflen, ' ', map->cols * map->rows - buflen); + + // Move the map data so that it fits the grid properly + for (end = map->_buf + buflen, pos = map->rows - 1; pos >= 0; end = beg, --pos) { + beg = memrchr(map->_buf, '\n', (end - map->_buf) - 1); + beg = beg ? beg + 1 : map->_buf; + memmove(map->_buf + pos * map->cols, beg, (end - beg)); + memset(map->_buf + (pos * map->cols) + (end - beg) - 1, ' ', map->cols - (end - beg) + 1); + map->_buf[pos * map->cols + map->cols - 1] = '\n'; + } + + return map; +} + + +void +map_tidy(struct map * map) +{ + if (!map) + return; + + free(map->_buf); + return; +} + + +int +map_elem(struct map const * map, int x, int y) +{ + if (x < 0 || x >= map->cols - 1 + || y < 0 || y >= map->rows) + return ' '; + + return map->_buf[x + y * map->cols]; +} + + struct elf { int x; int y; @@ -84,7 +163,7 @@ elf_turn(struct elf * elf, char turn) int -elf_move(struct elf * elf, char const * map, int cols, int rows, enum map_type mtype, int distance) +elf_move(struct elf * elf, struct map const * map, int distance) { while (distance > 0) { int dx = 0, dy = 0, elem; @@ -100,18 +179,18 @@ elf_move(struct elf * elf, char const * map, int cols, int rows, enum map_type m return -1; } - switch (mtype) { + switch (map->type) { case M_FLAT: - newelf.x = modulo(elf->x + dx, cols); - newelf.y = modulo(elf->y + dy, rows); + newelf.x = modulo(elf->x + dx, map->cols); + newelf.y = modulo(elf->y + dy, map->rows); newelf.dir = elf->dir; - elem = map[newelf.x + newelf.y * cols]; + elem = map_elem(map, newelf.x, newelf.y); // Just keep going until we wrap around to a non-blank position while (elem == ' ' || elem == '\n') { - newelf.x = modulo(newelf.x + dx, cols); - newelf.y = modulo(newelf.y + dy, rows); - elem = map[newelf.x + newelf.y * cols]; + newelf.x = modulo(newelf.x + dx, map->cols); + newelf.y = modulo(newelf.y + dy, map->rows); + elem = map_elem(map, newelf.x, newelf.y); } break; @@ -120,7 +199,7 @@ elf_move(struct elf * elf, char const * map, int cols, int rows, enum map_type m return -1; default: - fprintf(stderr, "Unknown map type %d\n", mtype); + fprintf(stderr, "Unknown map type %d\n", map->type); return -1; } @@ -147,9 +226,10 @@ elf_move(struct elf * elf, char const * map, int cols, int rows, enum map_type m int main(int argc, char ** argv) { - char * buf = NULL, * beg, * end; + char * buf = NULL; + struct map map; enum map_type mtype = M_FLAT; - long bufsiz = 0, buflen = 0, maxline = 0, lines = 0; + long bufsiz = 0, buflen = 0; long pos; struct elf elf; char distance[8]; @@ -217,42 +297,16 @@ main(int argc, char ** argv) buflen += strlen(buf + buflen); } - // Work out max lines and longest line. - for (beg = buf, lines = 0; beg < buf + buflen; beg = end + 1, ++lines) { - end = memchr(beg, '\n', buf + buflen - beg); - if (end - beg > maxline) - maxline = end - beg; - } - if (maxline == 0 || lines == 0) { - fprintf(stderr, "Unexpected map size (%ld,%ld)\n", maxline, lines); - free(buf); + if (map_init(&map, buf, buflen, mtype) == NULL) { + fprintf(stderr, "Failed to initialise map\n"); return -1; } - ++maxline; // Also count the newline on the end of each line. - - // Resize the map data buffer to hold a full grid of data - if ((beg = realloc(buf, lines * maxline)) == NULL) { - fprintf(stderr, "Bad realloc(%ld)\n", bufsiz); - free(buf); - return -1; - } - buf = beg; - memset(buf + buflen, ' ', lines * maxline - buflen); - - // Move the map data so that it fits the grid properly - for (end = buf + buflen, pos = lines - 1; pos >= 0; end = beg, --pos) { - beg = memrchr(buf, '\n', (end - buf) - 1); - beg = beg ? beg + 1 : buf; - memmove(buf + pos * maxline, beg, (end - beg)); - memset(buf + (pos * maxline) + (end - beg) - 1, ' ', maxline - (end - beg) + 1); - buf[pos * maxline + maxline - 1] = '\n'; - } // Set initial position elf.x = 0; elf.y = 0; elf.dir = D_EAST; - while (elf.x < maxline && buf[elf.x] != '.') + while (elf.x < map.cols && map_elem(&map, elf.x, elf.y) != '.') ++elf.x; // Read and follow the movement instructions. @@ -263,7 +317,7 @@ main(int argc, char ** argv) else if (c == 'L' || c == 'R') { distance[dlen] = '\0'; - if (elf_move(&elf, buf, maxline, lines, mtype, atoi(distance)) != 0) + if (elf_move(&elf, &map, atoi(distance)) != 0) elf.x = -1; if (elf_turn(&elf, c) != 0) elf.x = -1; @@ -273,18 +327,18 @@ main(int argc, char ** argv) else if (c == '\n') { // Cover last bit of distance, if any distance[dlen] = '\0'; - if (elf_move(&elf, buf, maxline, lines, mtype, atoi(distance)) != 0) + if (elf_move(&elf, &map, atoi(distance)) != 0) elf.x = -1; break; } else { fprintf(stderr, "Unexpected movement instruction (%c)\n", c); - free(buf); + map_tidy(&map); return -1; } } if (elf.x < 0) { - free(buf); + map_tidy(&map); return -1; } @@ -294,7 +348,7 @@ main(int argc, char ** argv) 1 + elf.x, 1 + elf.y, elf.dir); // Tidy and exit. - free(buf); + map_tidy(&map); return 0; } |