【JavaScript】迷路の最短経路を出力する

スタートからゴールまでの距離を2次元配列で表現して、
最短経路の通路を「 」(半角スペース)から「*」に置き換えて出力する。

class Maze {
  constructor(width, height) {
    this.PATH = 0;
    this.WALL = 1;
    this.width = width;
    this.height = height;
    if (this.width < 5 || this.height < 5) {
      return;
    }
    if (this.width%2 == 0) {
      this.width++;
    }
    if (this.height%2 == 0) {
      this.height++;
    }
    this.maze = Array.from(new Array(this.width),() => new Array(this.height).fill(this.PATH));
    this.dist = [[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, 10,  9,  8,  7,  6,  5,  4, -1, -1, -1, -1, -1, -1, -1],
                 [-1, 11, -1, -1, -1, -1, -1,  3, -1, -1, -1, -1, -1, -1, -1],
                 [-1, 12, -1, -1, -1,  0,  1,  2, -1, -1, -1, -1, -1, -1, -1],
                 [-1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, 20, 21, 22, 23, 24, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, 25, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
                 [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]];
    this.start = [1, 1];
    this.goal = [this.width-2, this.height-2];
  }

  set_outer_wall() {
    for (let y = 0; y < this.height; ++y) {
      for (let x = 0; x < this.width; ++x) {
        if (x == 0 || y == 0 || x == this.width-1 || y == this.height-1) {
          this.maze[y][x] = this.WALL;
        }
      }
    }
    return this.maze;
  }
  
  set_inner_wall() {
    for (let y = 2; y < this.height-1; y+=2) {
      for (let x = 2; x < this.width-1; x+=2) {
        this.maze[y][x] = this.WALL;
      }
    }
    return this.maze;
  }
  
  set_maze_boutaoshi() {
    let wall_x;
    let wall_y;
    let direction;
    maze1.set_outer_wall();
  maze1.set_inner_wall();
  for (let y = 2; y < this.height-1; y+=2) {
      for (let x = 2; x < this.width-1; x+=2) {
        while (true) {
          wall_x = x;
          wall_y = y;
          if (y == 2) {
            direction = Math.floor(Math.random()*4);
          } else {
            direction = Math.floor(Math.random()*3);
          }
          if (direction == 0) {
            wall_x += 1;
          } else if (direction == 1) {
            wall_y += 1;
          } else if (direction == 2) {
            wall_x -= 1;
          } else if (direction == 3) {
            wall_y -= 1;
          }
          if (this.maze[wall_y][wall_x] != this.WALL) {
            this.maze[wall_y][wall_x] = this.WALL;
            break;
          }
        }
      }
    }
    return this.maze;
  }
  
  set_start_goal(start, goal) {
    if (this.maze[start[1]][start[0]] == this.PATH) {
      this.start = start;
    }
    if (this.maze[goal[1]][goal[0]] == this.PATH) {
      this.goal = goal;
    }
    return this.maze;
  }
  
  set_shortest_path() {
    let point = this.goal;
    let x = [[0,-1],[1,0],[0,1],[-1,0]];
    this.maze[point[1]][point[0]] = '*';
    while (this.dist[point[1]][point[0]] > 0) {
      for (let i = 0; i < x.length; ++i) {
        if (this.dist[point[1]][point[0]]-this.dist[point[1]+x[i][1]][point[0]+x[i][0]] == 1) {
          if (this.dist[point[1]][point[0]] > 0) {
            this.maze[point[1]+x[i][1]][point[0]+x[i][0]] = '*';
            point = [point[0]+x[i][0],point[1]+x[i][1]];
          }
        }
      }
    }
    return this.maze;
  }

  print_maze() {
    this.maze[this.start[1]][this.start[0]] = 'S';
    this.maze[this.goal[1]][this.goal[0]] = 'G';
    for (let col of this.maze) {
      let arr = ''
      for(let cell of col) {
        if (cell == this.WALL) {
          arr += '#';
        } else if (cell == this.PATH) {
          arr += ' ';
        } else if (cell == 'S') {
          arr += 'S';
        } else if (cell == 'G') {
          arr += 'G';
        } else if (cell == '*') {
          arr += '*';
        }
      }
      console.log(arr);
    }
  }
}

let maze1 = new Maze(15, 15);
maze1.set_maze_boutaoshi();
maze1.set_start_goal([5,5], [9,11]);
maze1.set_shortest_path();
maze1.print_maze();

コメント

タイトルとURLをコピーしました