How to Solve the Maze Runner in C
The challenge
Introduction
Task
The Maze array will look like
maze = [[1,1,1,1,1,1,1],
[1,0,0,0,0,0,3],
[1,0,1,0,1,0,1],
[0,0,1,0,0,0,1],
[1,0,1,0,1,0,1],
[1,0,0,0,0,0,1],
[1,2,1,0,1,0,1]]
..with the following key
directions = "NNNNNEEEEE" == "Finish" // (directions passed as a string)
Rules
The solution in C
Option 1:
#include <stddef.h>
char *maze_runner(const int *maze, size_t n, const char *directions)
{
int x, y, cur;
// locate the start
for (y = 0; y < n; y++) for (x = 0; x < n; x++) if (maze[y*n+x] == 2) goto moves;
moves:
for (char *d = directions; *d; d++)
{
switch (*d) {
case 'N': y--; break;
case 'S': y++; break;
case 'E': x++; break;
case 'W': x--; break;
}
if (x < 0 || y < 0 || y > n-1 || x > n-1) return "Dead"; // out of bounds
if ((cur = maze[y*n+x]) == 1) return "Dead"; // hit wall
if (cur == 3) return "Finish"; // found exit
}
return "Lost";
}
Option 2:
#include <stddef.h>
#include <iso646.h>
#define NORTH 'N'
#define SOUTH 'S'
#define EAST 'E'
#define WEST 'W'
#define START 2
#define WALL 1
#define FINISH 3
char *maze_runner(const int *maze, size_t n, const char *directions) {
size_t x, y;
for (size_t i = 0; i < n; i++){
for (size_t j = 0; j < n; j++)
if (maze[i * n + j] == START){
x = j;
y = i;
}
}
for (size_t i = 0; directions[i]; i++){
x += (directions[i] == EAST) - (directions[i] == WEST);
y += (directions[i] == SOUTH) - (directions[i] == NORTH);
if (maze[y * n + x] == WALL or x >= n or y >= n)
return "Dead";
if (maze[y * n + x] == FINISH)
return "Finish";
}
return "Lost";
}
Option 3:
#include <stddef.h>
#define DEAD(N, MAX) N < 0 || N > MAX - 1
void move(int *x, int *y, char dir) {
switch (dir) {
case 'N': *y -= 1; break;
case 'S': *y += 1; break;
case 'E': *x += 1; break;
case 'W': *x -= 1; break;
}
}
char *maze_runner(const int *maze, size_t n, const char *directions) {
int nums[n][n], x, y, i, *p;
for (p = maze, i = 0; i < n * n; i++) {
nums[i/n][i%n] = maze[i];
if (*p++ == 2) x = i%n, y = i/n;
}
while (*directions) {
move(&x, &y, *directions++);
if (DEAD(x, n) || DEAD(y, n) || nums[y][x] == 1) return "Dead";
if (nums[y][x] == 3) return "Finish";
}
return "Lost";
}
Test cases to validate our solution
#include <criterion/criterion.h>
void tester(const int *maze, size_t n, const char *directions, char *outcome);
Test(Example_Tests, should_pass_all_the_tests_provided) {
#define N 7
const int maze[N * N] = {1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 3,
1, 0, 1, 0, 1, 0, 1,
0, 0, 1, 0, 0, 0, 1,
1, 0, 1, 0, 1, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 2, 1, 0, 1, 0, 1};
// maze is passed in as a 1-D int array with length n
// directions are passed in as a null-terninated string
// do not allocate memory, instead return a string literal
{ const char *directions = "NNNNNEEEEE"; tester(maze, N, directions, "Finish"); }
{ const char *directions = "NNNNNEESSEENNE"; tester(maze, N, directions, "Finish"); }
{ const char *directions = "NNNNNEEEEEWW"; tester(maze, N, directions, "Finish"); }
{ const char *directions = "NEEEE"; tester(maze, N, directions, "Lost"); }
{ const char *directions = "NNNWW"; tester(maze, N, directions, "Dead"); }
{ const char *directions = "NNNNNEESSSSSS"; tester(maze, N, directions, "Dead"); }
}