Backtracking

Maze generation using backtracking.

Log in to post a comment.

const OFFSETS = [[-1, 0], [0, -1], [1, 0], [0, 1]]

const getRandomInt = max => Math.floor(Math.random() * max)
const getRandomElement = array => array[getRandomInt(array.length)]

class Nodes {
  static offset([x, y]) {
    return [x - 100, y - 100]
  }

  constructor() {
    this.nodes = Array.from(Array(201)).map(() => Array.from(Array(201)))
    this.queue = []
  }

  hasNext() {
    return this.queue.length > 0
  }

  next() {
    const index = getRandomInt(this.queue.length)
    return this.queue.splice(index, 1)[0]
  }

  visit([x, y]) {
    this.nodes[x][y] = true
    this.queue.push([x, y])

    return this
  }

  visible([x, y]) {
    return 0 <= x && x <= 200 && 0 <= y && y <= 200
  }

  getAdjacent([x, y]) {
    return OFFSETS.map(([xOffset, yOffset]) => ([x + xOffset, y + yOffset]))
      .filter(([_x, _y]) => this.visible([_x, _y]))
  }

  getUnvisitedNodes(node) {
    return this.getAdjacent(node).filter(([x, y]) => !this.nodes[x][y])
  }
}

Canvas.setpenopacity(-1)
const turtle = new Turtle()
const nodes = new Nodes()

nodes.visit([getRandomInt(201), getRandomInt(201)])

const walk = i => {
  if (!nodes.hasNext()) {
    console.log('done')
    return
  }

  const current = nodes.next()

  const neighbors = nodes.getUnvisitedNodes(current)

  if (neighbors.length) {
    const neighbor = getRandomElement(neighbors)

    turtle.penup()
    turtle.goto(...Nodes.offset(current))
    turtle.pendown()
    turtle.goto(...Nodes.offset(neighbor))

    nodes.queue.push(current)
    nodes.visit(neighbor)
  }

  return i < 1000000
}