xxxxxxxxxx
795
/*
changelog
- 16-12-2024 aoc map, hsb, add changelog lol, very lag.
TODO
let mapsize differ, randomize random maps, put 1 in queue, build it in a seperate steppable function
*/
// latest edit: changed map to one from AoC2024day16
// visualiser for A* for https://www.codingame.com/ide/puzzle/vindinium
const MAP = [
"#############################################################################################################################################",
"#.......#...#.....#.................#.......#.........#.......#.....#.......#.....#.#.....................#.........#.......#.#............E#",
"#.###.#.#.#.###.#.#.#####.#########.#####.###.#.#######.#####.#.###.#.#.#.#.#.#.#.#.#.#.###.#####.#.###.#.#.###.###.#.###.#.#.#.#.###.###.###",
"#.#...#...#.....#.........#...#.....#...#.....#.....#...#...#...#...#.#.............#.....................#.#.#...#.#.#.#.#...#.#...#.......#",
"#.#.###.#######.###.#######.###.#####.#.#####.#####.#.#####.#.###.###.###.###.#.###.#.#######.#.###.#.###.#.#.###.###.#.#.#####.#.#.#####.#.#",
"#.#.#...#.............................#.....#.#.....#.........#.#...#...#.....#.........#...#.#.#...#.#...#.....#.....#.#.......#.#...#...#.#",
"###.#####.###.#.###.#.#.#####.#.###.#######.###.###.#########.#.###.###.#.###############.#.###.#.###.###.#####.#######.#########.#####.#.#.#",
"#...#.......#...#.#.#.#.......#.....#.............................................#.......#...#.........#.....#.#.......#...#...#.#.....#...#",
"#.###.#####.###.#.#.#.#######.#########.#.###.#.#.#####.#.###.#.#.#.#.#.#.#######.#.#########.#######.#.#####.#.#.#####.#.#.#.#.#.#.#######.#",
"#.....#...#...#...#.#...#...#.#.......#.#.#...#.#...#...#.#...#.#.#...#.#.......#.#.....#...#...#...#.#.....#.#...#...#...#...#.#.#.......#.#",
"#.#####.#.###.#.###.#.#.#.###.###.###.###.#.###.#.###.###.#.#.#.#.###.#.#.#####.#.#####.#.#####.#.#.###.###.#######.#.#########.#.#######.#.#",
"#.#...#.#...#...#...#.#.#...#.....#.#...................#...#...#.#...#.#.#...#.#...#...#.#...#.#.#.................#.....#...#.#.....#...#.#",
"#.###.#.###.###.#.#####.#.#.#######.###.#.#.#.###.#####.#######.#.#####.#.#.###.###.#.###.#.#.#.#.###.#.#.#.#.#.#.#.#.#####.#.#.#.#####.###.#",
"#.....#...............................#.#.#...#.#.#.....#.#.....#.#...#.#.#...#.....#.#...#.#...#...#.#...#...#.#.#.#.#.....#...#...#...#...#",
"#######.#.#####.###.#.#.#############.#.#.#####.#.#.###.#.#.#####.#.#.#.#.#.#.###.###.#.###.#######.#.#####.###.#.#.#.#.#######.###.#.###.###",
"#.......#.#...#.....#.#.....#.......#...............#.#.#.#.#...#...#.#.#.#.#.#...#.....#...#.......#.....#...#.#.#.#...#.#.........#.#.....#",
"#.#.#####.#.#.#.#####.#.###.#.#####.#################.#.#.#.#.#.#####.#.#.###.#.###.###.#.###.###########.#####.###.#.###.#.#.#######.#######",
"#.#.#...#.#.#...#.....#...#.....#.#...................#...#.#.#.....#.#...#...#.#...#...#.#...#.........#.....#.#.........#.#.#.......#.....#",
"#.#.#.#.###.#####.#############.#.###################.###.#.#######.#.#####.###.#.###.###.#.#######.###.#####.#.#.#####.#.#.#.#.#.#.###.###.#",
"#.#.#.#.....#...#.......#...#...#...........#...#...#...#.#.....#...#...........#...#.......#.....#...#.#.....#.#.....#.#.#.#...#.#.....#.#.#",
"#.#.#.#######.#.#######.#.#.#.#.#####.#####.#.#.#.#.###.#.#####.#.#.#########.#.###.#.#######.###.###.#.#.#####.#####.#.#.#.#######.#####.#.#",
"#.#.#...#.....#.#.....#.#.#.#...#.........#...#...#.#...#...#.#.#.#.....#...#...#...#.#.....#...#...#.#...........#...#.#.#.....#.........#.#",
"#.#.###.#######.#.#.#.#.#.#.#.###.#######.#####.###.#.#.#.#.#.#.#.#####.#.#.#####.#####.###.###.###.###.###########.#####.#####.#.#.#######.#",
"#.#...#...........#.#.#...#.#.....#.....#.#...#...#.#.#...#...#.#...#.....#.#...#.....#.#.#.....#.#...#.#...................#...#...#.......#",
"#.###########.#####.#####.#.###.###.###.#.#.#.#####.#.#######.#.###.#####.###.#.#####.#.#.#######.###.###.#.#########.#####.#.###.#.#.#####.#",
"#.........#...#.....#...#.#.#...#...#...#...#.......#.#.....#.#...#...#.#.#...#.....#.#.#.......#...#.....#...#...........#.#.....#...#.#...#",
"#.#######.#.###.#####.#.#.#.###.#.###.#######.#.#####.#.#.###.###.#.#.#.#.#.#.#####.#.#.#.###.###.#.#######.#.###.#######.#.#######.###.#.###",
"#.........#.....#.....#.#.#...#.#...#.........#.#...#...........#...#.#...#.#.........#.#.#...#.........#...#.....#.......#...#...#...#.#...#",
"#.#####.#######.#.#####.###.#.#####.#########.###.#.#.#########.#.###.#.###.###########.#.#.#.#.#####.#.#.#####.#######.#####.#.#.#.#.#.#.#.#",
"#.#...#.#.......#.#...#...#.#...#...#...#...#...#.#.#.#.......#.#.....#...#.....#.......#.#.#.#.#...#.#...#.....#.......#.....#.#...#.#.....#",
"#.###.#.#.#######.#.#.###.#####.#.###.#.###.###.#.#.###.#####.#.#####.###.#####.#.#######.#.###.#.#.#.#####.###.#.#.###.#.#####.###.#.###.#.#",
"#...#...#...#.#...#.#...#...#...#.#...#...#...#...#.....#...#.#.#.....#...#.....#...#...#.#.....#.#.#.#.....#.#...#.#...#...#.......#.#...#.#",
"#.#.#.#####.#.#.#####.#####.#.#.#.#.#.###.#.#.#########.###.#.###.#.###.###.###.###.###.#.#.#######.#.#####.#.#####.#.###.#.#######.#.#.#.#.#",
"#.#.#.#...#...#.....#.........#.#.#.#...#.#.#...#.....#.....#.....#...#.#.#.#.....#...#.............#.....#.......#.#.#...#.........#...#...#",
"#.#.#.#.#####.#####.#############.#.###.#.#.###.#.###.#############.#.#.#.#.#.#######.#.#########.#######.#######.#.#.###.#########.#####.#.#",
"#...#...#.....#.#...#...#...#.....#...#.#.#.#.......#.............#.#...#.#.#.#.....#.#.#...........#.....#.........#.#.......#.......#...#.#",
"#.#####.#.#####.#.###.#.#.#.#.#########.#.#.#####.#.#############.#.#####.#.###.###.#.#.#.#.#######.#.#####.#.#######.#.#.#####.###.#.#.#.#.#",
"#.#.............#.#...#...#.#.#.........#...#.......#...#.....#...#.#...#.#.....#...#.#.#.#.#.....#.#.#.....#.#...#.....#.#.....#...#.#.#...#",
"#.#.#.###.#.###.#.#.#######.#.###.#.#########.#######.#.#.###.#.#.#.#.#.#.#######.#.#.###.###.###.#.#.#.#.#####.#.#########.#####.#.###.#.#.#",
"#...#.......#.#.#.#...#...#.#...#.#.#.......#.#.......#...#...#.#...#.#...#.#.....#.#.#...#...#...#...#.#.......#.#.......#.....#.#...#...#.#",
"#.#.#########.#.#.###.#.#.#.#.#.#.###.#####.#.#.###########.###.###.#.#.#.#.#.#####.#.#.#.#.###.#######.#######.#.#.#####.#####.#.###.###.#.#",
"#.....#...#.....#.....#.#.......#.#...#.#...#.#.#...#.....#...#...#...#.#...#.#...#.#...#.#.#.....#...#.#.....#...#.#.#...#.....#...#.....#.#",
"#.#.###.#.###.#########.###.#.###.#.###.#.###.#.#.#.#.###.###.###.#####.#.###.#.###.#####.#.#.###.#.#.#.#.###.#.#.#.#.#.###.###.###.#####.#.#",
"#...#...#...#.#.......#.#.#.#.#...#.#.....#.......#.#.#.....#...#.#.....#.#...#.#.....#...#.#.#.....#...#.#...#.#.#.#.#.......#.....#.....#.#",
"#.#.#.#####.#.#.#####.#.#.#.#.###.#.#.#.#.#.#######.#.#.###.###.#.#.###.#.#.###.#.#####.###.#.#####.#.###.#.#.#.###.#.#########.###.#.###.###",
"#.....#.#...#...#.....#.#...#.....#.#.#.#.#.....#...........#...#.#...#.#.#.#.....#.....#...#.#.....#...#.#.#.#.....#.......#...#...#.#.#...#",
"#.#.###.#.#############.#.#####.#.#.#.#.#.#####.#####.#######.#.#.###.#.#.#.#######.#####.###.#.###.###.#.#.#.#######.#.#####.#.#####.#.#.#.#",
"#.#.......#.........#...#.#.....#.#.#.#.#.....#.....#.#...#...#.#.#.#.#...#.........#...#.#.....#.....#...#.........#.#.....#...#.....#...#.#",
"#.#.#.#####.#######.#.###.#.#####.#.#.#.#.#########.###.#.#.#####.#.#.#######.#########.#.#.###.#####.###.#####.###.#.#####.###.#.#####.###.#",
"#...#.#.....#.......#...#.#.....#...#.#.#.#...........#.#.#.#.....#.#.#.....#...........#...#...#...#...#.#...#...#.#.#.#...#.#.#...#...#...#",
"###.#.###.#.#######.###.#.#####.#.###.###.#.#####.###.#.#.#.#.#####.#.#.###.#########.#####.#####.#.###.###.#.#.#.#.#.#.#.#.#.#.###.###.#.###",
"#...#.....#.#...........#.#.....#.....#...#.#...#.#...#.#.#.#.#.....#.#.#...........#.#...#.......#.#.#.....#.#.#.......#.#...#...#.#...#...#",
"#.###.#######.###.#########.###########.#.#.#.###.#.###.#.#.#.#.#####.#.#.#########.###.#.#######.#.#.#######.#.#.#######.#####.#.#.#.#.###.#",
"#.#.........#.#.#.......#...#.....#.....#.#.#...#.#.#...#.#.#.#.......#.#.#.......#...#.#.#.........#...#.....#.#...#...#...#.....#...#.#...#",
"#.#.#######.#.#.#######.#.#####.#.#.#####.#.###.#.#.#.###.#.#.#########.#.#.###.#.#.#.#.#.#.###########.#.#####.###.#.#.###.#.#.#######.#.###",
"#.#.#...#...#...#.....#...#.....#...#.....#.....#.#...#.#...#.......#...#.#.#...#...#...#.#.#.#...........#.......#.#.#.....#...#.......#...#",
"#.#.#.#.#.#####.#.###.#######.#######.#######.###.#####.###.#######.#.#####.#.###.#.#####.#.#.#.#.#####.#.#.#######.#.#####.###.#.#########.#",
"#.#.#.#.#...#...#.......#.....#.....#...#.....#.......#.....#.......#...#...#...#.#.#...#.#.#...#...#...#.#...#.......#...#.#...#.#.....#...#",
"#.#.#.#.###.#.#####.###.#.#####.###.###.#.#####.#.#####.#####.#######.#.#.#####.#.###.#.#.#.###.###.#.###.#.#.#.#.#####.###.#.#.#.#.#.###.#.#",
"#...#.#...#...#.....#...#.#...#...#...#.#...#.#.#.#...#.#.............#.#.#...#.#...#.#...#...#...#.#.#...#.#...#...........#.#.#.#.#.#...#.#",
"#.#####.#.#####.#.###.###.#.#.#######.#.###.#.#.###.#.#.#.#####.#######.#.#.#.#.###.#.###.###.#####.###.###########.#########.#.#.#.###.###.#",
"#...#...#...#.......#.#.....#...#.......#.#.#.#.........#...#.#.#.....#.....#.#...#.#.#.....#.....#...#.#.........#.#.......#.#.#...#...#.#.#",
"###.#.#####.#######.#.###.#####.#.#####.#.#.#.#############.#.#.#.###.#.###.#####.#.#.#.###.#.###.#.#.#.###.#####.###.#####.#.#####.#.###.#.#",
"#.#...#.#...#.......#...#.#.#...#.........#...#.....#.......#...#...#.#...#.#.....#.#.#...#.#...#.#.#.#...#...#.#.....#.#...#...#...........#",
"#.#####.#.###.#########.#.#.#.###.###########.#####.#.#######.###.###.#.#.###.#####.#.###.#.#####.#.#.###.###.#.#######.#.#####.#.#.#.#.#.#.#",
"#...#...#.....#.......#.#...#.#.#...#.........#.....#.#...#.....#.#...#.#.......#...#...#...#.....#.#.....#.............#.....#...#...#.#.#.#",
"#.###.#.###########.#.#.###.#.#.###.#.#########.#####.#.#.#######.#.###.#.###.#.#.#.###.#.#.#.#####.###.###.###.#.#####.#####.#####.###.#.#.#",
"#.....#.........#...#.#.#...#.#...#.#...#.#.....#...#...#.........#.#...#.#...#...#.....#.#.......#.....#...#...#.#...#.....#.......#.#.#.#.#",
"#.#####.#######.#.#.###.#.###.#.###.#.#.#.#.#.###.#.###############.#.#####.#.#.#########.#.#####.#####.#.#.###.###.#.#.###########.#.#.#.#.#",
"#.#...#.#...#...#.#.#...#...#.#.#.....#.#...#.#...#.......#.....#...#.......#.#...#.......#.#.....#...#.#.#...#.......#.#...#.......#...#.#.#",
"#.#.###.###.#.###.###.#######.#.#.#####.#####.#.#####.#.#.#.###.#.###########.###.#.#.#####.#.#.###.###.#####.#.#####.###.#.#.#.###.#.###.#.#",
"#...#...#...#.#.#...........#.#...#...#.#.....#.#...#.#.#.#...#.#.......#.....#.#.#.#...#.#...#.#.....#.#.....#...#.#.....#.#.#.#...#.#.#...#",
"#.###.###.#.#.#.#.#.#######.#.#####.#.#.#.#####.#.#.###.#.#####.#########.#####.#.#####.#.#####.#.###.#.#.#######.#.#######.#.#.###.#.#.#####",
"#.....#...#.#.#.#.#.......#.#...#...#.....#.....#.#.#...#.....#...........#...#...#...#.#.........#.......#.#.....#...#...#...#.....#.#.....#",
"#.#####.#####.#.#.#.#.###.#.###.#.#######.#.#####.#.#.#######.#.###.#####.###.#.###.#.#.###########.#######.#.#####.#.###.#########.#.#.#####",
"#.#.#.........#...#...#.....#...#.#.........#.....#.#.#.....#.#.#.#...........#.#...#.#...........#.........#...#...#...#.........#...#.....#",
"#.#.#.#######.#######.#.###.#.#.#.###.#######.#####.#.###.#.#.#.#.#.#.#######.#.###.#.#.#########.###.#.###.###.###.###.###.#####.#####.###.#",
"#.#...............#...#...#...#.#.............#.#...#...#.#.#...#.#.#.#...#.#.#.#...#.#.........#...#.#.......#.....#.#...#...#...#...#.#.#.#",
"#.###############.#.#.#########.###############.#.###.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.###.#########.#.#.#####.#######.#.#.#.#.#####.#.#.#.#.#",
"#...#...#.......#.#...#.......#...#...#.......#...#.....#.#.....#...#.#.#.#...#...#...#...#.......#.#.#.....#...#...#.......#.......#.....#.#",
"#.#.#.#.#.###.###.#.###.#####.###.#.#.#.#.###.#.###.#####.###.###.###.#.#.#########.###.###.#####.#.#.#.###.#.###.#.#.#.###.###############.#",
"#.#...#.....#...#.#.....#.......#...#.#.#.#...#...#.#.....#...#.....#...#...#.......#...#.#.#.#...#.#.....#.#.#...#...#.#...#...........#...#",
"#.#######.#.#.#.#.#.#####.#####.#####.###.#######.#.#####.#.###.#####.#####.#.#######.###.#.#.#.###.#####.#.###.#######.#.###.#######.###.#.#",
"#.......#...#.#...#.#.....#...#.....#...........#.#.......#.....#...#...#...#.....#...#...#.#.....#.#.....#.....#.....#.....#.#.....#.#...#.#",
"#########.###.#######.#####.#.#########.#####.###.#.###.#.#####.#.#.###.#.#####.#.#.###.###.#####.#.#.###########.#.#.#####.#.#.###.#.#.###.#",
"#.....#...#...#.....#.......#...#.....#...#...#...#.....#.#...#.#.#...#.#.....#.#.........#.....#...#.....#.........#...#...#.#...#.#.#...#.#",
"#.###.#.#.#.###.###.#.#########.#.###.###.#.###.#######.#.#.#.###.###.###.###.#.###.#####.#####.#####.#.#.#.#######.###.#.###.#####.#.###.###",
"#...#...#.......#...............#...#.....#...#.#.....#.#...#...#.#.....#...#.#...#.....#.....#.....#...#.#.........#...#.....#...#.....#...#",
"#.#.#####.#####.#########.#####.###.#######.#.#.#####.#.#######.#.#####.#####.###.#####.#.###.#####.#####.###.#.#####.#########.#.#.#######.#",
"#.#...#...#...#.#...#.............#.....#...#.#.....#.......#...#...#.#.....#...#.#.......#.#.#...#.....#...#.#.#...#...#...#...#.#.#.....#.#",
"#.###.#####.#.###.#.#############.#####.#.###.#####.#######.#.#####.#.#####.###.#.#########.#.###.#####.#.#.###.#.#.###.#.#.#.###.#.#.###.#.#",
"#.#.#.......#.....#...........#.....#...#.#...........#...#.#.#.......#...#.....#.....#.....#.....#...#.#.......#.#...#...#...#.#.#.#...#.#.#",
"#.#.#####################.###.#####.#.###.#.###.#.###.#.#.###.#.#####.#.#.#####.#####.###.#.#####.#.#.#.#########.###.#########.#.#####.#.#.#",
"#.#.......#.......#.....#...#...#.....#...#...#...#.#...#.....#.#.....#.#...........#...#.#.....#.#.#.#.......#...#...#...#.....#.......#.#.#",
"#.#.#####.#.#.#####.###.#.#####.#####.#######.#.###.###########.###.###.###.#####.#.###.#.#.#####.#.#.#######.#####.###.#.#.#.#.#########.#.#",
"#.........#.#.....#...#.#.#...#.....#.........#.#.........#.............#.#...#.....#...#.#.....#.#.#.....#...#.....#...#...#.#.........#...#",
"#####.###.#######.###.#.###.#.#####.#.#########.###.#.###.#.#####.#####.#.#.#.#####.#.###.#####.#.#.###.###.###.#####.#######.#############.#",
"#.....#...........#...#.....#...........#.........#.#.#...#.#...#.#...#...#.#.....#.#.......#...#.#.#...#...#...#.....#...................#.#",
"#.#.#.#.#########.#.#####.#############.#####.###.###.#####.#.#.#.#.#.###.#.#####.#.###.###.#.###.#.#.###.###.###.#####.#####.#.#######.###.#",
"#.#.#.#...#...#...#.....#.#.......#...#.....#...#...#.#.....#.#.#...#...#.#.....#.....#.#.#.#...#.#.#...#.#.......#...#...#...#.#.....#.....#",
"#.#.#.#.###.#.#####.###.#.#.#####.#.#.#####.#.#####.#.#.#####.###.###.#.#.#####.###.###.#.#.###.#.###.#.#.#####.#####.###.#.###.#.###.#######",
"#.#.#.#.#...#.....#.#...#.#.#.....#.#.#.......#...#.#.#.......#.....#.#.#.#...#...#.....#.#...#.....#.#.#.#...#.#...#...#.#.#...#.#...#.....#",
"#.#.#.#.#.#######.#.#.#####.#.#.#####.#.#######.#.#.#.###.#####.###.#.#.#.###.###.#.#####.#.###.###.###.#.#.#.#.#.#.#.#.#.#.#.###.#.###.#.###",
"#.#.#...#.....#...#.#.......#.#.#...#...#...#...#...#.....#.....#...#.#.......#.#.#.......#.#...#.......#...#...#.#.......#.#.#...#...#.#...#",
"#.#.#.#####.#.#.#############.###.#.#.#.#.###.#######.#.#.#.#####.#####.#####.#.#.###.###.#.#.###.#.#########.#.#.#####.#.###.#.#####.#.###.#",
"#...............#...........#...#.#...#...#...#.....#.#...#.....#.....#...#.....#...#...#...#.......#.........#...#.....#.....#...#...#...#.#",
"#.#.#.###.#.#.#.###.#######.###.#.###.#####.###.#####.#########.#####.#.#.#########.###########.#####.#############.#.###########.#.#######.#",
"#.#...#.....#.#.....#.....#.....#...#.....#.#.#.......#.....#.#...#...#.#.........#...........#.#...#.#.....#...#...#.#...#.#.....#.#.......#",
"###.#.#.###.#.#######.#.#.#####.###.#####.#.#.#.#######.#.#.#.###.#.###.#######.#.###########.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.###.###.###.#",
"#...#...#.....#.....#.#.#.....#.#.#...#.#.#.#.#.#.......#.#.....#.#.#.......#...#.........#...#...#.#...#...#.#...#.#...#.#...#.#...#...#...#",
"#.###.###.#.###.###.#.#.#####.#.#.###.#.#.#.#.#.#####.#.#.#####.#.#.#########.#####.#####.#.###.###.#.#.#####.#####.#####.###.#.#.###.###.###",
"#.....#.........#.#.#.#.#.....#.#...#...#.#.#.#.#...#.#.#.#.....#.#.......#...#...#.#...#.#...#.#.#.#.........#...#.....#...#.#.#...#.#.....#",
"#.###.#.###.#.#.#.#.#.#.#####.#.#.#.###.#.#.#.#.#.#.#.#.#.#####.#.#######.#.#.#.#.###.#.#####.#.#.#.#.#####.#####.###.#.###.#.#.###.#.#######",
"#.......#...#.#.......#.#...#.#.#...#...#.#.#.....#.......#...#.#.......#...#.#.#.#...#...#...#.#.....#...#.......#.#.....#.#.#.#.#.#.......#",
"#####.#.#.#.#.###.#####.#.#.#.#.#.###.###.#.#####.###.#.###.#.###.#####.#####.#.#.#.#####.#.###.#######.#.#######.#.#####.#.###.#.#.###.###.#",
"#.#...#...#...#.......#...#.#.#...#...#...#.....#.#...#.#...#...#.#...#.....#...#.#.....#...#...#.....#.#...#...#.#...#...#.#...#.#.........#",
"#.#.#.###.#.#########.#.###.###.###.###.#######.###.#.###.#####.#.#.#.#####.#.###.#####.#####.###.###.#.###.#.#.#.#.#.#.###.#.###.#.###.###.#",
"#...#.#...#...#...#...#...#.#...#...#.#.....#.#.....#.....#...#.#.#.#.....#.#.#.....#.#.#.....#...#.#...#...#.#.#.#.#.#...#...#...#.......#.#",
"#.###.#.###.#.#.#.#.#.###.#.#.###.###.#.#.#.#.#######.#.#####.#.#.#.#######.#.#.###.#.#.###.#.#.###.#####.###.#.#.#.#.###.###.#.###.#.#.###.#",
"#...#...........#...#...#.#.......#.....#.#.........#.#.#.....#.#.#.#.....#...#.#.....#...#.#...#.......#.....#.#...#...#.....#...#.#.#.#...#",
"###.#.#####.###########.#.#######.#####.#.#########.#.#.#.#.###.#.#.#.###.#.#.#.#########.#.#####.#.#######.###.###########.###.#.#.#.#.#.###",
"#.#.#.............#.....#.#.......#...#.#.#.......#.#.#.#.#.....#.#.....#.#...#.......#...#...#...#.#.....#...#...........#.....#...#.#.#.#.#",
"#.#.#.#############.#####.#.#######.#.#.#.#.#####.###.#.#.#######.#.#####.###########.#.#####.#.#####.###.###.###########.#.#######.#.#.#.#.#",
"#...#.............#...#...#.........#.#.#...#...#.....#.#.#...#...#.#.......#.....#...#.....#.#.#.....#.#.#...#.......#...#.#.............#.#",
"#.###.###########.###.#####.#.#######.#.#####.#########.#.#.#.#.#####.#####.#####.#.#.#####.#.#.#.#####.#.#####.#####.#.###.###.###.#.#.###.#",
"#.#...........#.....#.......#.#.....#.#.................#.#.#.#.......#.....#...#.#.#.....#.#...#.......#...........#.#...#...#.#...#.#.#...#",
"#.###.#######.#.###.#########.###.###.#.#.#######.#######.#.#####.#####.#####.#.#.#.#.#####.#.#.###.#.#########.#.###.###.###.#.#.#.#.#.#.#.#",
"#...#.#.....#...#...#.......#...#.....#.#.#.....#...#.#...#...#.......#.....................#.....#.#.....#...#.....#.....#...#.#.#...#...#.#",
"###.#.#.#.#.#####.#####.###.###.#.#####.#.#.###.#.#.#.#.#####.#.#.###.#.#.#.#.#####.#.#######.###.#.###.#.#.#.#.###.#######.###.#.#.#.#####.#",
"#.#...#...#...#.#.....#...#.....................#.#.#.#.#...#.......#.....#...#.....#.#...#.....................................#.#.#.#...#.#",
"#.#######.#.#.#.#####.###.###.#.#########.###.#.###.#.#.#.#.#####.###########.#.###.#.#.#.#.#.#.#####.#.#####.#.#.#####.#####.#.#.#.#.#.###.#",
"#.....#...#.#.#.....#...#...#.#.....#.#...#...#.........#.#.........................#...#...#.#.#...#.#...#...#.................#.#...#.#...#",
"#.#####.#.#.#.#.#######.#.#.#.#####.#.#.###.###.#.#####.#.#######.#.###.#.#.#.###.#.#.#######.#.#.#.#.#.###.#.#.###.#.###.#.###.#.#.###.#.###",
"#...#...#.#.#...#.......#.#.#.......#.......#.....#...#.#.#.....#.#...#.#.#.....#.#.........#...#.#...#.#...#.#.#.#.#.#...#...#.#.#.....#.#.#",
"#.#.#.###.#.###.#.#########.#####.#.###############.#.#.#.#.#.#.#.###.#.#########.#########.#.###.#####.#.###.#.#.#.###.#####.#.#.#####.#.#.#",
"#.#.#.....#.........................................#.#...#.#...#.....#.........#.#.....#...#.#...#.....#.#...#.#.#...#.#...#.........#.#.#.#",
"#.#.#####.###.#.#.#.#.#.#####.#.#.#.#########.#.#####.#######.#.###############.#.#.#.#.#.###.###.#######.#.###.#.###.#.#.###########.###.#.#",
"#.#.......#.#.#.#.#...#...#...#.#.#.#.......#...........................#.....#.#.#.#.#.#...#...#...#.....#.#...#.#...#...........#...#...#.#",
"#.#########.#.###.#######.#.#.###.###.#####.###########.#.#.#.#######.#.#.#.###.#.#.#.#####.#.#.###.#.#######.###.#.###.###.#####.#.###.###.#",
"#S........................#.#.........#.................#.............#...#.......#.#.........#.....#.............#.........#.....#.........#",
"#############################################################################################################################################",
];
const size = MAP.length;
let openSet = [];
let cameFrom = new Map();
let gScore = {};
let fScore = {};
let current = null;
let path = [];
let pathFound = false;
let cellSize = 40;
let start = { x: 1, y: 139 }; // Adjust as needed
let goal = { x: 139, y: 1 }; // Adjust as needed
let AStarStepSlider;
let oscillator;
let env;
let restarting; // used to continuously reset start/goal if no interaction is found
let osc_type = "sine";
const RETRY_RESTART_DELAY = 3000; // Example delay of 10 seconds
const NEW_SOUND_TIMEOUT_DELAY = 250;
let show_text_checkbox;
const DEBUG_ON = false;
const DEFAULT_FRAMERATE = 15; // per second
const DEFAULT_ASTAR_STEPS_PER_FRAME = 10;
let rainbow_mode_checkbox;
let show_debug_checkbox;
function windowResized() {
let mapWidth = MAP[0].length;
let mapHeight = MAP.length;
cellSize = Math.min(
Math.floor(windowWidth / mapWidth),
Math.floor(windowHeight / mapHeight)
);
resizeCanvas(mapWidth * cellSize, mapHeight * cellSize);
}
function setup() {
let mapWidth = MAP[0].length;
let mapHeight = MAP.length;
cellSize = Math.min(
Math.floor(windowWidth / mapWidth),
Math.floor(windowHeight / mapHeight)
);
let canvas = createCanvas(mapWidth * cellSize, mapHeight * cellSize);
canvas.parent("main"); // Attach the canvas to the main container
// Apply CSS dynamically
canvas.style("margin", "5px auto");
canvas.style("display", "block");
frameRate(15); // Visualization speed
show_text_checkbox = createCheckbox("show_text")
.checked(false)
.parent("sidebar_id");
show_debug_checkbox = createCheckbox("debug")
.checked(DEBUG_ON)
.parent("sidebar_id");
rainbow_mode_checkbox = createCheckbox("rainbow-mode")
.checked(true)
.parent("sidebar_id");
openSet.push(start);
gScore[nodeKey(start)] = 0;
fScore[nodeKey(start)] = heuristic(start, goal);
let framerateSlider = document.getElementById("framerateSlider");
framerateSlider.value = DEFAULT_FRAMERATE;
document.getElementById("framerateSpan").innerHTML = DEFAULT_FRAMERATE;
frameRate(DEFAULT_FRAMERATE);
framerateSlider.addEventListener("input", (event) => {
frameRate(parseInt(event.target.value, 10));
document.getElementById("framerateSpan").innerHTML = event.target.value;
});
// Set initial frame rate
document.getElementById("framerateSpan").innerHTML = framerateSlider.value;
frameRate(framerateSlider.value);
AStarStepSlider = document.getElementById("AStarStepSlider");
AStarStepSlider.value = DEFAULT_ASTAR_STEPS_PER_FRAME;
document.getElementById(
"AStarStepSpan"
).innerHTML = DEFAULT_ASTAR_STEPS_PER_FRAME;
AStarStepSlider.addEventListener("input", (event) => {
document.getElementById("AStarStepSpan").innerHTML = event.target.value;
});
// Set initial frame rate
document.getElementById("AStarStepSpan").innerHTML = AStarStepSlider.value;
setupSoundSystem();
}
function draw() {
background(220); // Clear the canvas
if (!pathFound) {
for (var i = 0; i < AStarStepSlider.value; i++) {
if (!pathFound) {
let first_time_path_found = stepAstar();
if (first_time_path_found) {
restarting = true;
setTimeout(() => {
osc_type = random([
"sawtooth",
"sine",
"square",
"triangle",
"sine",
"sine",
"triangle",
"triangle",
]); // Corrected typo 'tiangle' to 'triangle'
oscillator.setType(osc_type);
if (restarting) {
pickNewStartAndGoal();
}
}, NEW_SOUND_TIMEOUT_DELAY);
attemptPickNewStartAndGoal();
}
}
}
playBeepBoop();
}
drawMap(); // Draw the map
// Inside draw function for start and goal visualization
fill("rgba(0,255,0,1)"); // Start
ellipse(
start.x * cellSize + cellSize / 2,
start.y * cellSize + cellSize / 2,
cellSize
);
fill("rgba(255,0,0,1)"); // Goal
ellipse(
goal.x * cellSize + cellSize / 2,
goal.y * cellSize + cellSize / 2,
cellSize
);
// Optionally, draw the current best path if current is defined
if (current) {
let partialPath = reconstructPartialPath(cameFrom, current);
drawPath2(partialPath, color("cyan"), color("red")); // Use a distinct color for the partial path
}
// Draw the final path if found
if (pathFound) {
drawPath2(path, color("rgba(0,255,0, 0.5)"), color("gold")); // Original path color
}
// Visualize the current node
if (current) {
fill("rgba(255,165,0, 0.5)"); // Orange for the current node
rect(current.x * cellSize, current.y * cellSize, cellSize, cellSize);
}
// Visualize the open set
fill("rgba(0,0,255, 0.25)"); // Blue for open set nodes
for (let node of openSet) {
rect(node.x * cellSize, node.y * cellSize, cellSize, cellSize);
}
if (start.x == goal.x && start.y == goal.y) {
push();
textSize(40);
textAlign(CENTER);
textWrap(WORD);
fill("red");
text(
"⚠\nstart and goal are overlapping\n⚠",
width / 4,
height / 4,
width / 2,
height / 2
);
pop();
}
push();
fill("yellow");
textAlign(CENTER);
textSize(10);
if (show_text_checkbox.checked()) {
text(`you're listening to ${osc_type} beeps`, width / 2, height - 15);
fill(restarting ? "green" : "red");
text(
`demo ${restarting ? "on" : "off (press T or S somewhere to restart)"}`,
width / 2,
height - 50
);
}
pop();
}
function attemptPickNewStartAndGoal() {
if (restarting) {
// Initial check to see if we're still in the state that requires a restart
setTimeout(() => {
// Check again after the delay to confirm we still want to restart
if (restarting) {
pickNewStartAndGoal();
}
// If needed, else logic for not restarting can go here
}, RETRY_RESTART_DELAY);
}
}
function setupSoundSystem() {
{
oscillator = new p5.Oscillator();
oscillator.setType(osc_type); // You can change this to 'triangle', 'sawtooth', or 'square'
oscillator.freq(440); // Frequency in Hz, 440 is the A above middle C
oscillator.amp(0); // Start with amplitude at 0 to avoid sudden sounds
oscillator.start();
// Initialize the envelope
env = new p5.Envelope();
env.setADSR(0.01, 0.1, 0.1, 0.1); // Attack, Decay, Sustain, Release times
env.setRange(0.1, 0); // Max and min amplitudes
let gainNode = new p5.Gain();
gainNode.connect();
oscillator.disconnect(); // Disconnect from master output
oscillator.connect(gainNode); // Connect oscillator to gain node
gainNode.amp(0.2); // Set gain node amplitude
}
}
function playBeepBoop() {
let freq = random(100, 1200); // Random frequency for variety
oscillator.freq(freq);
// Trigger the envelope to play the sound
env.play(oscillator);
}
function nodeKey(node) {
return `${node.x},${node.y}`;
}
function heuristic(a, b) {
// Manhattan distance on a square grid
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
}
function aStar(start, goal) {
let openSet = [start];
let cameFrom = new Map(); // Using Map for better handling of complex keys
let gScore = {};
gScore[nodeKey(start)] = 0;
let fScore = {};
fScore[nodeKey(start)] = heuristic(start, goal);
while (openSet.length > 0) {
let current = openSet.reduce((prev, curr) =>
fScore[nodeKey(prev)] === undefined ||
fScore[nodeKey(curr)] < fScore[nodeKey(prev)]
? curr
: prev
);
if (current.x === goal.x && current.y === goal.y) {
return reconstructPath(cameFrom, current);
}
openSet = openSet.filter(
(item) => item.x !== current.x || item.y !== current.y
);
let neighbors = getNeighbors(current);
for (let neighbor of neighbors) {
let tentativeGScore = gScore[nodeKey(current)] + 1; // assuming cost of 1 to move between neighbors
if (tentativeGScore < (gScore[nodeKey(neighbor)] || Infinity)) {
cameFrom.set(nodeKey(neighbor), current); // Correctly map using nodeKey
gScore[nodeKey(neighbor)] = tentativeGScore;
fScore[nodeKey(neighbor)] =
gScore[nodeKey(neighbor)] + heuristic(neighbor, goal);
if (
!openSet.some(
(item) => item.x === neighbor.x && item.y === neighbor.y
)
) {
openSet.push(neighbor);
}
}
}
}
return false; // No path found
}
function getNeighbors(node) {
let neighbors = [];
const directions = [
[1, 0],
[0, 1],
[-1, 0],
[0, -1],
]; // Right, Down, Left, Up
for (let [dx, dy] of directions) {
let newX = node.x + dx;
let newY = node.y + dy;
if (
newX >= 0 &&
newX < MAP[0].length &&
newY >= 0 &&
newY < MAP.length &&
MAP[newY][newX] !== "#"
) {
neighbors.push({ x: newX, y: newY });
}
}
return neighbors;
}
function stepAstar() {
if (openSet.length > 0 && !pathFound) {
current = openSet.reduce((prev, curr) =>
fScore[nodeKey(prev)] === undefined ||
fScore[nodeKey(curr)] < fScore[nodeKey(prev)]
? curr
: prev
);
if (current.x === goal.x && current.y === goal.y) {
path = reconstructPath(cameFrom, current);
pathFound = true; // Path found
return true; // Exit the function early
}
openSet = openSet.filter(
(item) => item.x !== current.x || item.y !== current.y
);
let neighbors = getNeighbors(current);
for (let neighbor of neighbors) {
let tentativeGScore = gScore[nodeKey(current)] + 1;
if (tentativeGScore < (gScore[nodeKey(neighbor)] || Infinity)) {
cameFrom.set(nodeKey(neighbor), current);
gScore[nodeKey(neighbor)] = tentativeGScore;
fScore[nodeKey(neighbor)] = tentativeGScore + heuristic(neighbor, goal);
if (
!openSet.some(
(item) => item.x === neighbor.x && item.y === neighbor.y
)
) {
openSet.push(neighbor);
}
}
}
} else if (!pathFound) {
print("no path found!");
noLoop(); // Stop the draw loop if no path is found and openSet is empty
}
}
function findNearestNonWall(x, y) {
if (MAP[y][x] !== "#") {
return { x, y };
}
console.debug("Looking for nonwall");
// Search in expanding squares around the initial position
for (let radius = 1; radius < MAP.length; radius++) {
for (let i = -radius; i <= radius; i++) {
let checkPositions = [
{ x: x + i, y: y - radius },
{ x: x + i, y: y + radius },
{ x: x - radius, y: y + i },
{ x: x + radius, y: y + i },
];
for (let pos of checkPositions) {
if (
pos.x >= 0 &&
pos.x < MAP[0].length &&
pos.y >= 0 &&
pos.y < MAP.length &&
MAP[pos.y][pos.x] !== "#"
) {
return pos;
}
}
}
}
return { x, y }; // Fallback to the original position if no non-wall found
}
function resetAndRestart() {
openSet = [start];
cameFrom = new Map();
gScore = {};
fScore = {};
current = null;
path = [];
pathFound = false;
gScore[nodeKey(start)] = 0;
fScore[nodeKey(start)] = heuristic(start, goal);
loop(); // Ensure the draw loop is running
}
function mouseMoved() {
print("forcing the user to listen!");
userStartAudio();
mouseMoved = function () {
if (mouseX < 0 || mouseX > width || mouseY < 0 || mouseY > height) {
return;
}
if (restarting) {
restarting = false;
}
};
}
function keyPressed() {
if (mouseX < 0 || mouseX > width || mouseY < 0 || mouseY > height) {
return;
}
if (restarting) {
restarting = false;
}
if (key == "r") {
resetAndRestart();
}
if (key == "t" || key == "s") {
let mouseXIndex = Math.floor(mouseX / cellSize);
let mouseYIndex = Math.floor(mouseY / cellSize);
if (
mouseXIndex >= 0 &&
mouseXIndex < MAP[0].length &&
mouseYIndex >= 0 &&
mouseYIndex < MAP.length
) {
let newPos = findNearestNonWall(mouseXIndex, mouseYIndex);
if (key === "s") {
start = newPos;
} else if (key === "t") {
goal = newPos;
}
resetAndRestart(); // Reset everything and restart the animation
}
}
}
function reconstructPartialPath(cameFrom, current) {
let partialPath = [];
let tempCurrent = current;
let safetyCounter = 0; // Safety counter to prevent infinite loops
const MAX_ITERATIONS = 1000; // Adjust based on the expected maximum path length
while (cameFrom.has(nodeKey(tempCurrent)) && safetyCounter < MAX_ITERATIONS) {
partialPath.unshift(tempCurrent);
tempCurrent = cameFrom.get(nodeKey(tempCurrent));
safetyCounter++; // Increment safety counter
if (tempCurrent === start) break; // Break if start node is reached
}
if (safetyCounter >= MAX_ITERATIONS) {
console.error("Infinite loop detected in reconstructPartialPath");
return []; // Return an empty path as a fallback
}
partialPath.unshift(start); // Ensure start is included
return partialPath;
}
function pickNewStartAndGoal() {
let attempts = 0;
const maxAttempts = 100; // Prevent infinite loops
const minDistance = Math.floor(Math.max(MAP.length, MAP[0].length) / 2) - 1;
while (attempts < maxAttempts) {
// Randomly pick two points from the map
let startX = Math.floor(random(MAP[0].length));
let startY = Math.floor(random(MAP.length));
let goalX = Math.floor(random(MAP[0].length));
let goalY = Math.floor(random(MAP.length));
// (1, 139) (139, 1)
// Use findNearestNonWall to ensure these are walkable
let newStart = findNearestNonWall(startX, startY);
let newGoal = findNearestNonWall(goalX, goalY);
// Calculate distance to ensure it meets the minimum required distance
let distance =
Math.abs(newStart.x - newGoal.x) + Math.abs(newStart.y - newGoal.y);
if (distance >= minDistance) {
start = newStart; // Set the new start position
goal = newGoal; // Set the new goal position
resetAndRestart(); // Reset and restart pathfinding with the new points
break; // Break the loop once suitable points are found
}
attempts++;
}
}
function reconstructPath(cameFrom, current) {
let totalPath = [current];
let safetyCounter = 0; // Safety counter to prevent infinite loops
const MAX_ITERATIONS = 1000; // Adjust based on the expected maximum path length
while (cameFrom.has(nodeKey(current)) && safetyCounter < MAX_ITERATIONS) {
current = cameFrom.get(nodeKey(current));
totalPath.unshift(current);
safetyCounter++; // Increment safety counter
if (current === start) break; // Break if start node is reached
}
if (safetyCounter >= MAX_ITERATIONS) {
console.error("Infinite loop detected in reconstructPath");
return []; // Return an empty path as a fallback
}
return totalPath;
}
function drawRainBowMap() {
push();
colorMode(HSB, 100);
stroke(0);
for (let y = 0; y < MAP.length; y++) {
for (let x = 0; x < MAP[y].length; x++) {
if (MAP[y][x] === "#") {
const pulse = abs(sin(frameCount / 10)) * 50;
const wall_color = color(
(x / MAP[y].length) * 100,
20 + (y / MAP[y].length) * 120,
pulse
);
fill(wall_color);
} else {
fill(255); // White for walkable paths
}
rect(x * cellSize, y * cellSize, cellSize, cellSize);
}
}
pop();
}
function drawNormalMap() {
push();
colorMode(HSB, 100);
const wallcolor = color(100, 100, 0);
stroke(0);
for (let y = 0; y < MAP.length; y++) {
for (let x = 0; x < MAP[y].length; x++) {
if (MAP[y][x] === "#") {
fill(wallcolor);
} else {
fill(255);
}
rect(x * cellSize, y * cellSize, cellSize, cellSize);
}
}
pop();
}
function drawMap() {
if (rainbow_mode_checkbox.checked()) {
drawRainBowMap();
} else {
drawNormalMap();
}
}
function drawPath(path, col = "rgba(0,255,0, 0.5)") {
// Change the fill color based on the argument
for (let [i, node] of path.entries()) {
fill(lerpColor(color("red"), color(col), i / path.length));
ellipse(
node.x * cellSize + cellSize / 2,
node.y * cellSize + cellSize / 2,
cellSize * 0.8
);
}
}
function drawPath2(path, colFrom = color("green"), colTo = color("red")) {
/*
draw the path from colFrom to colTo
*/
for (let [i, node] of path.entries()) {
fill(lerpColor(colFrom, colTo, i / path.length));
ellipse(
node.x * cellSize + cellSize / 2,
node.y * cellSize + cellSize / 2,
cellSize * 0.8
);
}
}