0

I was implementing prim's algorithm to generate mazes using the buckblog article in JavaScript and encountered an error, the error is that one particular variable (frontier list) is not saving what i want it to save. JavaScript code is given below, here is the complete code with html maze generator and here is the deployment web

P.S: any help is appreciated, i'm kinda new at JavaScript :)

everything works as expected but "frontier" is not saving the "random_point" neighbors in generate method. i.e "listValues" a.k.a "frontier" is not saving the return value by "neighbors()" method but works fine and saves the return values by "neighbors()" method at "frontier_neighbors"

function createMatrix() {
  // Get the dimensions from the input fields
  var rows = parseInt(document.getElementById('rows').value);
  var cols = parseInt(document.getElementById('cols').value);
  let maze = new Maze(rows, cols);
  maze.generate();
  maze.display();
}

class pair {
  constructor() {
    this.col = 0;
    this.row = 0;
  }
}

class maze_element {
  constructor() {
    this.top = 1;
    this.bottom = 1;
    this.left = 1;
    this.right = 1;
    this.v = 0;
  }
}

class Maze {
  constructor(rows, cols) {
    this.mat = [];
    this.rows = rows;
    this.cols = cols;
    for (let i = 0; i < rows; i++) {
      this.mat[i] = [];
    }
    let count = 0;
    for (let i = 0; i < rows; i++) {
      for (let j = 0; j < cols; j++) {
        this.mat[i][j] = new maze_element();
      }
    }
  }
  neighbors(random_point) {
    let neighbor = [];
    let col = random_point.col;
    let row = random_point.row;

    if (row > 0) {
      let temp = new pair();
      temp.col = col;
      temp.row = row - 1;
      neighbor.push(temp);
    }

    // Corrected condition here
    if (row < this.rows - 1) {
      let temp = new pair();
      temp.col = col;
      temp.row = row + 1;
      neighbor.push(temp);
    }

    if (col < this.cols - 1) {
      let temp = new pair();
      temp.col = col + 1;
      temp.row = row;
      neighbor.push(temp);
    }

    if (col > 0) {
      let temp = new pair();
      temp.col = col - 1;
      temp.row = row;
      neighbor.push(temp);
    }

    return neighbor;
  }
  getAdjacentIn(neighbors) {
    let newPair = new pair();
    for (let neighbor of neighbors) {
      if (this.mat[neighbor.row][neighbor.col].v === 1) {
        newPair.col = neighbor.col;
        newPair.row = neighbor.row;
        return newPair;
      }
    }
  }
  getWall(cell1, cell2) {
    if (cell1.row < cell2.row) {
      return 'bottom';
    } else if (cell1.row > cell2.row) {
      return 'top';
    } else if (cell1.col < cell2.col) {
      return 'right';
    } else if (cell1.col > cell2.col) {
      return 'left';
    }
  }
  getOppositeWall(wall) {
    if (wall === 'top') {
      return 'bottom';
    } else if (wall === 'right') {
      return 'left';
    } else if (wall === 'bottom') {
      return 'top';
    } else if (wall === 'left') {
      return 'right';
    }
  }
  breakWall(inside_maze, frontier_outside_maze) {

    let wall = this.getWall(inside_maze, frontier_outside_maze);
    let oppWall = this.getOppositeWall(wall);
    if (wall === 'top' && oppWall === 'bottom') {
      this.mat[inside_maze.row][inside_maze.col].top = 0;
      this.mat[frontier_outside_maze.row][frontier_outside_maze.col].bottom = 0;
    }
    if (wall === 'bottom' && oppWall === 'top') {
      this.mat[inside_maze.row][inside_maze.col].bottom = 0;
      this.mat[frontier_outside_maze.row][frontier_outside_maze.col].top = 0;
    }
    if (wall === 'left' && oppWall === 'right') {
      this.mat[inside_maze.row][inside_maze.col].left = 0;
      this.mat[frontier_outside_maze.row][frontier_outside_maze.col].right = 0;
    }
    if (wall === 'right' && oppWall === 'left') {
      this.mat[inside_maze.row][inside_maze.col].right = 0;
      this.mat[frontier_outside_maze.row][frontier_outside_maze.col].left = 0;
    }
    return null;
  }
  addFrontier(frontier_neighbors, frontier) {
    for (let neighbor of frontier_neighbors) {
      if (this.mat[neighbor.row][neighbor.col].v === 0) {
        frontier.push(neighbor);
      }
    }
  }
  shuffle(array) {
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }
  generate() {
    let random_point = new pair(); //creates index of a random cell each time it is executed
    random_point.col = Math.floor(Math.random() * this.cols);
    random_point.row = Math.floor(Math.random() * this.rows);
    this.mat[random_point.row][random_point.col].v = 1; //first cell in the maze
    let listValues = this.neighbors(random_point);

    console.log('List Values:', listValues);
    console.log('Length:', listValues.length);
    let frontier = listValues; //all the neighbors of current cell
    while (frontier.length > 0) {
      this.shuffle(frontier);
      let random_frontier_index = new pair();
      let index = Math.floor(Math.random() * frontier.length);
      random_frontier_index = frontier[index];
      let frontier_neighbors = this.neighbors(random_frontier_index);

      //continue here 26 may 2023

      console.log("random cell", random_point);
      console.log("frontier list", frontier);
      console.log("frontiner cell", random_frontier_index);
      console.log("frontier neighbors", frontier_neighbors);
      let adjacent_cell = this.getAdjacentIn(frontier_neighbors);
      console.log("adjacent cell", adjacent_cell);
      this.breakWall(random_point, random_frontier_index);

      //mark the frontier cell as visited using .v;
      this.mat[random_frontier_index.row][random_frontier_index.col].v = 1;

      //add the neighbors of random frontier cell to frontier list.
      this.addFrontier(frontier_neighbors, frontier);
      // }

      //remove the random frontier cell from the frontier list.
      frontier.splice(frontier.indexOf(random_frontier_index), 1);
      random_point = random_frontier_index;
    }

  }
  display() {
    const existingCanvas = document.querySelector('canvas');
    if (existingCanvas) {
      existingCanvas.parentNode.removeChild(existingCanvas);
    }
    let canvas = document.createElement("canvas");
    canvas.style.marginLeft = "25em";
    canvas.style.marginTop = "20px";
    canvas.width = this.cols * 20;
    canvas.height = this.rows * 20;
    let context = canvas.getContext("2d");
    context.beginPath();

    for (let row = 0; row < this.rows; row++) {
      for (let col = 0; col < this.cols; col++) {
        let cell = this.mat[row][col];

        if (cell.top) {
          context.moveTo(col * 20, row * 20);
          context.lineTo((col + 1) * 20, row * 20);
        }
        if (cell.right) {
          context.moveTo((col + 1) * 20, row * 20);
          context.lineTo((col + 1) * 20, (row + 1) * 20);
        }
        if (cell.bottom) {
          context.moveTo((col + 1) * 20, (row + 1) * 20);
          context.lineTo(col * 20, (row + 1) * 20);
        }
        if (cell.left) {
          context.moveTo(col * 20, (row + 1) * 20);
          context.lineTo(col * 20, row * 20);
        }
      }
    }

    context.stroke();
    document.body.appendChild(canvas);
  }
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • What is the point of creating `listValues` and then aliasing it as `frontier` when you don't seem to use it again? Or are you under the impression that copies the array? – Jared Smith May 26 '23 at 13:39
  • @JaredSmith it was initially created to copy the array using [...this.neighbors(random_point)] but it resulted in no change so i removed the whole idea – Gaurav malik May 26 '23 at 13:43
  • the console.log()s are just for debugging purposes, please ignore them – Gaurav malik May 26 '23 at 13:46
  • 1
    Please visit [help], take [tour] to see what and [ask]. Do some research, search for related topics on SO; if you get stuck, post a [mcve] of your attempt, noting input and expected output, preferably in a [Stacksnippet](https://blog.stackoverflow.com/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/) – mplungjan May 26 '23 at 13:47
  • It's really hard to understand your question because you don't have a reproduction case where for input X you expect Y but get Z, but if I had to take a shot in the dark based on some things that look off about your code I'd say it's that you're mutating the array in place in the shuffle method but somehow expecting the array you pass to it to remain unchanged. – Jared Smith May 26 '23 at 13:48
  • @JaredSmith but I am logging the listValues way before the shuffle method this shouldn't change anything, for matrix of dimensions 3x3 random_point = [2,1] expected listValues = [[1,1],[2,2],[2,0]] with length = 3 got listValues = [pair, pair, pair] with length = 0, but if I log the listValues.length it gives length = 3; – Gaurav malik May 26 '23 at 14:00
  • @Gauravmalik Do you mean console output is inconsistent with expected state of objects? – blakkwater May 26 '23 at 14:21
  • The console keeps a live reference to the array. So when you shuffle the array, the console changes. See https://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays – Barmar May 26 '23 at 14:36
  • @blakkwater i want "listValues" aka "frontier" to hold the list of neighbors that "random_point" variable has and looking at console output i dont think its storing the neighbors – Gaurav malik May 26 '23 at 14:39
  • @Gauravmalik When you pass references to the console, it doesn't copy the entirety of the corresponding objects, only saves references and previews. So when you're looking to the output and try to expand the array, *only then* console fully loads its contents and shows the details; but at that moment your program already emptied that array, so you also see it empty. – blakkwater May 26 '23 at 15:00
  • @Gauravmalik Workaround is simple, just log the deep copy: `console.log('List Values:', structuredClone(listValues))`, and you'll see what the array was at the moment when you logged it. – blakkwater May 26 '23 at 15:07
  • @blakkwater aah I got it, it stores the values but doesn't show them in the console, yea I just iterated over listValues and the values are stored there, thank you, sir. – Gaurav malik May 26 '23 at 15:19

0 Answers0