summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--22.c144
1 files changed, 99 insertions, 45 deletions
diff --git a/22.c b/22.c
index a4a687f..a021510 100644
--- a/22.c
+++ b/22.c
@@ -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;
}