DEV Community

Discussion on: Daily Challenge #288 - Maze Runner

Collapse
 
willsmart profile image
willsmart • Edited

One with full typing info in typescript...

// Input
type Maze = MazeSquare[][];
type Directions = Direction[];
// Output
type FinishState = 'Finish' | 'Dead' | 'Lost';

// component types
enum MazeSquare {
  space = 0,
  wall = 1,
  start = 2,
  end = 3,
}
type Direction = 'N' | 'E' | 'W' | 'S';
type Coor = { row: number; col: number };

// Functions to move a coor around
const coorUpdaterByDirection = {
  N: (coor: Coor) => {
    coor.row--;
  },
  E: (coor: Coor) => {
    coor.col++;
  },
  W: (coor: Coor) => {
    coor.col--;
  },
  S: (coor: Coor) => {
    coor.row++;
  },
};


function mazeRunner(maze: Maze, directions: Directions): FinishState {
  // Find starting point
  const coor_row = maze.findIndex(v => v.indexOf(MazeSquare.start) !== -1);
  if (coor_row === -1) throw new Error('Maze has no starting point');

  const coor: Coor = {
    row: coor_row,
    col: maze[coor_row].indexOf(MazeSquare.start),
  };


  let foundEnd = false; // The closure will set this if it finds the end

  // Iterate through the directions array until we finish or hit a wall/boundary
  // I'll use `findIndex` since it can early-stop as needed
  return directions.findIndex(direction => {
    // move the coor based on direction
    coorUpdaterByDirection[direction](coor);

    const square = maze[coor.row]?.[coor.col];
    // (note that square will be undefined if coor is off the map)

    foundEnd = square === MazeSquare.end;
    // return true if we want to keep going (i.e. are on a clear square)
    return square !== MazeSquare.space && square !== MazeSquare.start;
  }) === -1
    ? 'Lost'
    : foundEnd
    ? 'Finish'
    : 'Dead';
}

Some sanity checking


const testMaze: 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],
  ],
  tests: [Directions, FinishState][] = [
    [['N', 'N', 'N', 'N', 'N', 'E', 'E', 'E', 'E', 'E'], 'Finish'],
    [['N', 'N', 'N', 'N', 'N', 'E', 'E', 'S', 'S', 'E', 'E', 'N', 'N', 'E'], 'Finish'],
    [['N', 'N', 'N', 'N', 'N', 'E', 'E', 'E', 'E', 'E', 'W', 'W'], 'Finish'],
    [['N', 'N', 'N', 'W', 'W'], 'Dead'],
    [['N', 'N', 'N', 'N', 'N', 'E', 'E', 'S', 'S', 'S', 'S', 'S', 'S'], 'Dead'],
    [['N', 'E', 'E', 'E', 'E'], 'Lost'],
  ];

tests.forEach(([directions, expectation], testi) => {
  const actual = mazeRunner(testMaze, directions);
  console.log(`Test #${testi}: ${directions.join(', ')}
  Result: ${actual}, expected ${expectation}, which is a ${expectation === actual ? 'pass! woop' : 'FAILURE rofl'})
`);
});

/* -->

Test #0: N, N, N, N, N, E, E, E, E, E
  Result: Finish, expected Finish, which is a pass! woop)

a.ts:83
Test #1: N, N, N, N, N, E, E, S, S, E, E, N, N, E
  Result: Finish, expected Finish, which is a pass! woop)

a.ts:83
Test #2: N, N, N, N, N, E, E, E, E, E, W, W
  Result: Finish, expected Finish, which is a pass! woop)

a.ts:83
Test #3: N, N, N, W, W
  Result: Dead, expected Dead, which is a pass! woop)

a.ts:83
Test #4: N, N, N, N, N, E, E, S, S, S, S, S, S
  Result: Dead, expected Dead, which is a pass! woop)

woop πŸ•ΊπŸ’ƒ