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;  }  | 
