Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

1028 linhas
34 KiB

  1. function spawnPathfinder(root) {
  2. class Cell
  3. {
  4. is_state(state){return this.State == state}
  5. reset(){this.make_state("null")}
  6. make_state(state){this.State = state;}
  7. draw(grid){
  8. grid.children[this.Y].children[this.X].classList.remove("animate")
  9. grid.children[this.Y].children[this.X].classList = "cell " + this.State + ` x${this.X}-y${this.Y}`;
  10. grid.children[this.Y].children[this.X].style.backgroundPosition = `${this.X * horizontal_cells * 0}px ${this.Y * vertical_cells / 4}px`;
  11. if(this.State != "null") grid.children[this.Y].children[this.X].classList.add("animate");
  12. }
  13. update_neighbours(grid, diagonal=true)
  14. {
  15. this.neighbours = []
  16. let space_top = this.Y > 0 && grid[this.Y-1][this.X];
  17. let space_down = this.Y < vertical_cells - 1 && grid[this.Y+1][this.X];
  18. let space_left = this.X > 0 && grid[this.Y][this.X-1];
  19. let space_right = this.X < horizontal_cells - 1 && grid[this.Y][this.X+1];
  20. let shiftXR = this.Y % 2 === 0 ? 0 : 1;
  21. let shiftXL = this.Y % 2 === 0 ? 1 : 0;
  22. let left = space_left && !grid[this.Y][this.X - 1].is_state("wall");
  23. let right = space_right && !grid[this.Y][this.X + 1].is_state("wall");
  24. let top_right = space_top && grid[this.Y-1][this.X + 1 - shiftXR] && !grid[this.Y-1][this.X + 1 - shiftXR].is_state("wall");
  25. let top_left = space_top && grid[this.Y-1][this.X - 1 + shiftXL] && !grid[this.Y-1][this.X - 1 + shiftXL].is_state("wall");
  26. let down_right = space_down && grid[this.Y+1][this.X + 1 - shiftXR] && !grid[this.Y+1][this.X + 1 - shiftXR].is_state("wall");
  27. let down_left = space_down && grid[this.Y+1][this.X - 1 + shiftXL] && !grid[this.Y+1][this.X - 1 + shiftXL].is_state("wall");
  28. if(top_right) this.neighbours.push(grid[this.Y-1][this.X + 1 - shiftXR]);
  29. if(top_left) this.neighbours.push(grid[this.Y-1][this.X - 1 + shiftXL]);
  30. if(down_right) this.neighbours.push(grid[this.Y+1][this.X + 1 - shiftXR]);
  31. if(down_left) this.neighbours.push(grid[this.Y+1][this.X - 1 + shiftXL]);
  32. if(right) this.neighbours.push(grid[this.Y][this.X+1]);
  33. if(left) this.neighbours.push(grid[this.Y][this.X-1]);
  34. }
  35. update_wall_neighbours(grid,space=1)
  36. {
  37. this.wall_neighbours = []
  38. let space_top = this.Y > space;
  39. let space_down = this.Y < vertical_cells - 1 - space;
  40. let space_left = this.X > space;
  41. let space_right = this.X < horizontal_cells - 1 - space;
  42. if(space_top) this.wall_neighbours.push(grid[this.Y-1-space][this.X]);// UP
  43. if(space_down) this.wall_neighbours.push(grid[this.Y+1+space][this.X]);// DOWN
  44. if(space_right) this.wall_neighbours.push(grid[this.Y][this.X+1+space]);// RIGHT
  45. if(space_left) this.wall_neighbours.push(grid[this.Y][this.X-1-space]);// LEFT
  46. }
  47. constructor(X,Y)
  48. {
  49. this.X = X;
  50. this.Y = Y;
  51. this.State = "null"
  52. this.neighbours = []
  53. this.wall_neighbours = []
  54. }
  55. }
  56. // Main grid
  57. let grid = [];
  58. // Grid element
  59. let body = root;
  60. let grid_HTML = root.getElementsByClassName("grid")[0];
  61. let navbar_HTML = root.getElementsByClassName("navbar")[0];
  62. let speed_range = root.getElementsByClassName("range-speed")[0];
  63. let algo_select = root.getElementsByClassName("algo-select")[0];
  64. let maze_algo_select = root.getElementsByClassName("maze-algo-select")[0];
  65. const window_y = (body.scrollHeight - navbar_HTML.scrollHeight);
  66. const window_x = body.scrollWidth;
  67. let horizontal_cells;
  68. let vertical_cells;
  69. let tile_size ;
  70. let placing_tiles = false;
  71. let erasing_tiles = false;
  72. let dragging_tile = false;
  73. let dragged_tile = "";
  74. let is_running = false;
  75. tile_size = "big"
  76. horizontal_cells = Math.floor(window_x / 35);
  77. vertical_cells = Math.floor(window_y / 35);
  78. horizontal_cells = Math.floor( (window_x - horizontal_cells) /35);
  79. vertical_cells = Math.floor( (window_y - vertical_cells) / 35 * 0.9);
  80. grid_HTML.style.width = `${horizontal_cells * 35}px`;
  81. grid_HTML.style.height = `${vertical_cells * 30}px`;
  82. // Start and End nodes
  83. let start_node = [Math.floor(horizontal_cells/3) , Math.floor(vertical_cells/2)];
  84. let end_node = [Math.floor(horizontal_cells/3*2) , Math.floor(vertical_cells/2)];
  85. let start_node_initial = [Math.floor(horizontal_cells/3) , Math.floor(vertical_cells/2)]
  86. let end_node_initial = [Math.floor(horizontal_cells/3*2) , Math.floor(vertical_cells/2)]
  87. // Populating grid
  88. for(var i = 0; i < vertical_cells; i++)
  89. {
  90. let row = [];
  91. let odd = i % 2 === 0;
  92. var row_HTML = document.createElement("div");
  93. row_HTML.classList = "row " + tile_size + (odd ? " odd" : "");
  94. for(var j = 0; j < horizontal_cells; j++)
  95. {
  96. let cell = new Cell(j,i);
  97. row.push(cell);
  98. var cell_HTML = document.createElement("div");
  99. cell_HTML.classList.add("cell");
  100. row_HTML.appendChild(cell_HTML);
  101. }
  102. grid.push(row);
  103. grid_HTML.appendChild(row_HTML);
  104. }
  105. // Setting tile placing
  106. for(var i = 0; i < vertical_cells; i++)
  107. {
  108. for(var j = 0; j < horizontal_cells; j++)
  109. {
  110. grid[i][j].draw(grid_HTML);
  111. grid_HTML.children[i].children[j].X=j;
  112. grid_HTML.children[i].children[j].Y=i;
  113. grid_HTML.children[i].children[j].onmouseover = function()
  114. {
  115. if(placing_tiles) PlaceTile(this.X,this.Y);
  116. else if(erasing_tiles) ResetTile(this.X,this.Y);
  117. if(dragging_tile) this.classList = "cell "+dragged_tile
  118. } ;
  119. grid_HTML.children[i].children[j].onmouseleave = function()
  120. {
  121. if(dragged_tile) grid[this.Y][this.X].draw(grid_HTML);
  122. }
  123. grid_HTML.children[i].children[j].onmousedown = function() {
  124. if(this.X == start_node[0] && this.Y == start_node[1] || this.X == end_node[0] && this.Y == end_node[1]){
  125. dragging_tile = true;
  126. dragged_tile = grid[this.Y][this.X].State;
  127. }
  128. else{
  129. if(grid[this.Y][this.X].is_state("wall")) erasing_tiles = true;
  130. else placing_tiles = true;
  131. if(placing_tiles) PlaceTile(this.X,this.Y);
  132. if(erasing_tiles) ResetTile(this.X,this.Y)
  133. }
  134. }
  135. grid_HTML.children[i].children[j].onmouseup = function() {
  136. if(dragging_tile)
  137. {
  138. dragging_tile = false;
  139. PlaceTile(this.X,this.Y,dragged_tile)
  140. }
  141. }
  142. grid_HTML.children[i].children[j].ondragstart = function(){return false};
  143. grid_HTML.children[i].children[j].ondrop = function(){return false};
  144. }
  145. }
  146. grid_HTML.onmouseup = function() {
  147. placing_tiles = false
  148. erasing_tiles = false
  149. }
  150. PlaceTile(start_node_initial[0],start_node_initial[1],"start")
  151. PlaceTile(end_node_initial[0],end_node_initial[1],"end")
  152. async function SelectChange(select)
  153. {
  154. if(select == "maze-algo-select")
  155. {
  156. await RunMaze();
  157. }
  158. }
  159. function PlaceTile(x,y,tile = "wall")
  160. {
  161. if(is_running) return;
  162. let is_start = start_node.length != 0 ? x==start_node[0] && y==start_node[1] : false;
  163. let is_end = end_node.length != 0 ? x==end_node[0] && y==end_node[1] : false;
  164. if(start_node.length == 0 || tile == "start"){
  165. if(!is_end){
  166. if(start_node.length != 0) ResetTile(start_node[0],start_node[1], true);
  167. grid[y][x].make_state("start");
  168. start_node = [x,y];
  169. }
  170. }
  171. else if(end_node.length == 0 || tile == "end"){
  172. if(!is_start){
  173. if(end_node.length != 0) ResetTile(end_node[0],end_node[1], true);
  174. grid[y][x].make_state("end");
  175. end_node = [x,y]
  176. }
  177. }
  178. else{
  179. if(!is_start && !is_end){
  180. grid[y][x].make_state("wall");
  181. }
  182. }
  183. grid[y][x].draw(grid_HTML);
  184. }
  185. function ResetTile(x,y,full=false)
  186. {
  187. if(is_running) return
  188. if(full){
  189. grid[y][x].reset();
  190. grid[y][x].draw(grid_HTML);
  191. return;
  192. }
  193. if(grid[y][x].is_state("wall"))
  194. {
  195. grid[y][x].reset();
  196. }
  197. grid[y][x].draw(grid_HTML);
  198. }
  199. async function ReconstructPath(came_from, current)
  200. {
  201. while(came_from[""+current.X+"y"+current.Y] != undefined){
  202. current = came_from[""+current.X+"y"+current.Y]
  203. current.make_state("path")
  204. current.draw(grid_HTML);
  205. await sleep(25)
  206. }
  207. }
  208. function sleep (time) {
  209. return new Promise((resolve) => setTimeout(resolve, time));
  210. }
  211. function ResetPath()
  212. {
  213. if(is_running) return
  214. for(var i = 0; i < vertical_cells; i++){
  215. for(var j = 0; j < horizontal_cells; j++){
  216. let cell = grid[i][j];
  217. if(!cell.is_state("wall") && !cell.is_state("start") && !cell.is_state("end")){
  218. grid[i][j].reset();
  219. grid[i][j].draw(grid_HTML);
  220. }
  221. }
  222. }
  223. }
  224. function ClearWalls()
  225. {
  226. if(is_running) return
  227. for(var i = 0; i < vertical_cells; i++){
  228. for(var j = 0; j < horizontal_cells; j++){
  229. let cell = grid[i][j];
  230. if(cell.is_state("wall")){
  231. grid[i][j].reset();
  232. grid[i][j].draw(grid_HTML);
  233. }
  234. }
  235. }
  236. }
  237. function ClearGrid()
  238. {
  239. if(is_running) return
  240. start_node = [];
  241. end_node = [];
  242. for(var i = 0; i < vertical_cells; i++){
  243. for(var j = 0; j < horizontal_cells; j++){
  244. grid[i][j].reset();
  245. grid[i][j].draw(grid_HTML);
  246. }
  247. }
  248. PlaceTile(start_node_initial[0],start_node_initial[1])
  249. PlaceTile(end_node_initial[0],end_node_initial[1])
  250. }
  251. async function Run()
  252. {
  253. let algo = algo_select.value;
  254. switch(algo){
  255. case "AStar":
  256. await RunAStar();
  257. break;
  258. case "Dijkstra":
  259. await RunDijkstra();
  260. break;
  261. case "BFS":
  262. await RunBFS();
  263. break;
  264. case "DFS":
  265. await RunDFS();
  266. break;
  267. case "Greedy":
  268. await RunGreedy();
  269. break;
  270. }
  271. }
  272. async function RunAStar()
  273. {
  274. if(is_running) return;
  275. ResetPath();
  276. is_running = true;
  277. let start = grid[start_node[1]][start_node[0]];
  278. let end = grid[end_node[1]][end_node[0]];
  279. for (var row of grid)
  280. {
  281. for (var cell of row)
  282. {
  283. cell.update_neighbours(grid)
  284. }
  285. }
  286. let count = 0;
  287. let open_set = [];
  288. open_set.push([0,count,start]);
  289. let came_from = {}
  290. let g_score = {}
  291. for(let row of grid){
  292. for(let cell of row){
  293. g_score[""+cell.X+"y"+cell.Y] = Number.MAX_VALUE
  294. }
  295. }
  296. g_score[""+start.X+"y"+start.Y] = 0;
  297. let f_score = {}
  298. for(let row of grid){
  299. for(let cell of row){
  300. f_score[""+cell.X+"y"+cell.Y] = Number.MAX_VALUE
  301. }
  302. }
  303. f_score[""+start.X+"y"+start.Y] = H(start_node[0],start_node[1],end_node[0],end_node[1]);
  304. let open_set_hash = new Set();
  305. open_set_hash.add(start);
  306. while(!open_set.length == 0)
  307. {
  308. let current = open_set[0][2]
  309. let current_smallest = Number.MAX_VALUE
  310. let temp_index = 0;
  311. for(let cell = 0; cell < open_set.length; cell ++)
  312. {
  313. if(open_set[cell][0] < current_smallest)
  314. {
  315. temp_index = cell;
  316. current = open_set[cell][2]
  317. current_smallest = open_set[cell][0]
  318. }
  319. }
  320. open_set.splice(temp_index, 1);
  321. open_set_hash.delete(current)
  322. if(current == end)
  323. {
  324. // make path
  325. end.make_state("end")
  326. start.make_state("start")
  327. end.draw(grid_HTML);
  328. start.draw(grid_HTML)
  329. await ReconstructPath(came_from,end)
  330. end.make_state("end")
  331. start.make_state("start")
  332. end.draw(grid_HTML);
  333. start.draw(grid_HTML)
  334. is_running = false;
  335. return
  336. }
  337. for(var neighbour of current.neighbours){
  338. let temp_g_score = g_score[""+current.X+"y"+current.Y]+1
  339. if(temp_g_score < g_score[""+neighbour.X+"y"+neighbour.Y] || g_score[""+neighbour.X+"y"+neighbour.Y] == undefined){
  340. came_from[""+neighbour.X+"y"+neighbour.Y] = current
  341. g_score[""+neighbour.X+"y"+neighbour.Y] = temp_g_score
  342. f_score[""+neighbour.X+"y"+neighbour.Y] = temp_g_score + H(neighbour.X,neighbour.Y, end.X,end.Y)
  343. if(!open_set_hash.has(neighbour)){
  344. count++;
  345. open_set.push([f_score[""+neighbour.X+"y"+neighbour.Y],count,neighbour])
  346. open_set_hash.add(neighbour)
  347. neighbour.make_state("open")
  348. }
  349. neighbour.draw(grid_HTML)
  350. }
  351. }
  352. if(current != start)
  353. {
  354. current.make_state("closed");
  355. current.draw(grid_HTML)
  356. }
  357. await sleep(200-speed_range.value)
  358. }
  359. is_running = false;
  360. }
  361. function H(x1,y1,x2,y2){
  362. return Math.abs(x1-x2)+Math.abs(y1-y2);
  363. }
  364. async function RunDijkstra()
  365. {
  366. if(is_running) return;
  367. ResetPath();
  368. is_running = true;
  369. let start = grid[start_node[1]][start_node[0]];
  370. let end = grid[end_node[1]][end_node[0]];
  371. let dist = {};
  372. let prev = {};
  373. let Q = []
  374. for (var row of grid)
  375. {
  376. for (var cell of row)
  377. {
  378. cell.update_neighbours(grid)
  379. }
  380. }
  381. for(var row of grid){
  382. for(var cell of row){
  383. dist[""+cell.X+"y"+cell.Y] = Number.MAX_VALUE;
  384. prev[""+cell.X+"y"+cell.Y] = null;
  385. Q.push(cell)
  386. }
  387. }
  388. dist[""+start.X+"y"+start.Y] = 0;
  389. while (Q.length > 0)
  390. {
  391. let u = Q[0];
  392. let current_smallest = Number.MAX_VALUE;
  393. let temp_index = 0;
  394. for(let cell = 0; cell < Q.length; cell ++)
  395. {
  396. if(parseFloat(dist[""+Q[cell].X+"y"+Q[cell].Y]) < current_smallest)
  397. {
  398. temp_index = cell;
  399. current_smallest = parseFloat(dist[""+ Q[cell].X+"y"+ Q[cell].Y]);
  400. u = Q[cell];
  401. }
  402. }
  403. Q.splice(temp_index, 1);
  404. if(current_smallest == Number.MAX_VALUE)
  405. {
  406. is_running = false;
  407. return;
  408. }
  409. for(let v of u.neighbours)
  410. {
  411. if(Q.indexOf(v) != -1)
  412. {
  413. let alt = parseFloat(dist[""+u.X+"y"+u.Y]) + H(u.X,u.Y,v.X,v.Y);
  414. if(alt < parseFloat(dist[""+v.X+"y"+v.Y])){
  415. dist[""+v.X+"y"+v.Y] = alt;
  416. prev[""+v.X+"y"+v.Y] = u;
  417. }
  418. v.make_state("open");
  419. v.draw(grid_HTML);
  420. }
  421. if(v == end)
  422. {
  423. end.make_state("end")
  424. start.make_state("start")
  425. end.draw(grid_HTML);
  426. start.draw(grid_HTML)
  427. await ReconstructPath(prev,end)
  428. end.make_state("end")
  429. start.make_state("start")
  430. end.draw(grid_HTML);
  431. start.draw(grid_HTML)
  432. is_running = false;
  433. return
  434. }
  435. }
  436. if(u != start && u != end)
  437. {
  438. u.make_state("closed");
  439. u.draw(grid_HTML);
  440. }
  441. await sleep(200-speed_range.value)
  442. }
  443. is_running = false;
  444. }
  445. async function RunBFS()
  446. {
  447. if(is_running) return;
  448. ResetPath();
  449. is_running = true;
  450. let start = grid[start_node[1]][start_node[0]];
  451. let end = grid[end_node[1]][end_node[0]];
  452. let disc = [];
  453. let prev = {};
  454. let Q = []
  455. disc.push(start)
  456. Q.push(start)
  457. for (var row of grid)
  458. {
  459. for (var cell of row)
  460. {
  461. cell.update_neighbours(grid)
  462. }
  463. }
  464. while(Q.length > 0)
  465. {
  466. let v = Q[0];
  467. Q.splice(0,1);
  468. for(var n of v.neighbours)
  469. {
  470. if(disc.indexOf(n) == -1)
  471. {
  472. disc.push(n);
  473. Q.push(n);
  474. n.make_state("open");
  475. n.draw(grid_HTML);
  476. prev[""+n.X+"y"+n.Y] = v;
  477. if(n == end)
  478. {
  479. end.make_state("end")
  480. start.make_state("start")
  481. end.draw(grid_HTML);
  482. start.draw(grid_HTML)
  483. await ReconstructPath(prev,end)
  484. end.make_state("end")
  485. start.make_state("start")
  486. end.draw(grid_HTML);
  487. start.draw(grid_HTML)
  488. is_running = false;
  489. return
  490. }
  491. }
  492. }
  493. if(v != start && v != end)
  494. {
  495. v.make_state("closed");
  496. v.draw(grid_HTML);
  497. }
  498. await sleep(200-speed_range.value)
  499. }
  500. is_running = false;
  501. }
  502. async function RunDFS()
  503. {
  504. if(is_running) return;
  505. ResetPath();
  506. is_running = true;
  507. let start = grid[start_node[1]][start_node[0]];
  508. let end = grid[end_node[1]][end_node[0]];
  509. let disc = [];
  510. let prev = {};
  511. let S = []
  512. S.push(start)
  513. for (var row of grid)
  514. {
  515. for (var cell of row)
  516. {
  517. cell.update_neighbours(grid,false)
  518. }
  519. }
  520. while(S.length > 0)
  521. {
  522. let v = S.pop();
  523. disc.push(v);
  524. for(var i = v.neighbours.length-1;i>=0;i--)
  525. {
  526. let n = v.neighbours[i];
  527. if(disc.indexOf(n) == -1)
  528. {
  529. n.make_state("open");
  530. n.draw(grid_HTML);
  531. prev[""+n.X+"y"+n.Y] = v;
  532. if(n == end)
  533. {
  534. end.make_state("end")
  535. start.make_state("start")
  536. end.draw(grid_HTML);
  537. start.draw(grid_HTML)
  538. await ReconstructPath(prev,end)
  539. end.make_state("end")
  540. start.make_state("start")
  541. end.draw(grid_HTML);
  542. start.draw(grid_HTML)
  543. is_running = false;
  544. return
  545. }
  546. else{
  547. S.push(n)
  548. }
  549. }
  550. }
  551. if(v != start && v != end)
  552. {
  553. v.make_state("closed");
  554. v.draw(grid_HTML);
  555. }
  556. await sleep(200-speed_range.value)
  557. }
  558. is_running = false;
  559. }
  560. async function RunGreedy()
  561. {
  562. if(is_running) return;
  563. ResetPath();
  564. is_running = true;
  565. let start = grid[start_node[1]][start_node[0]];
  566. let end = grid[end_node[1]][end_node[0]];
  567. let dist = {}
  568. let disc = []
  569. let prev = {};
  570. let Q = []
  571. for (var row of grid)
  572. {
  573. for (var cell of row)
  574. {
  575. cell.update_neighbours(grid)
  576. }
  577. }
  578. for(let row of grid){
  579. for(let cell of row){
  580. dist[""+cell.X+"y"+cell.Y] = Number.MAX_VALUE
  581. }
  582. }
  583. dist[""+start.X+"y"+start.Y] = H(start.X,start.Y,end.X,end.Y);
  584. Q.push(start);
  585. while(Q.length > 0){
  586. let u = Q[0];
  587. let current_smallest = Number.MAX_VALUE;
  588. let temp_index = 0;
  589. for(let cell = 0; cell < Q.length; cell ++)
  590. {
  591. if(parseFloat(dist[""+Q[cell].X+"y"+Q[cell].Y]) < current_smallest)
  592. {
  593. temp_index = cell;
  594. current_smallest = parseFloat(dist[""+ Q[cell].X+"y"+ Q[cell].Y]);
  595. u = Q[cell];
  596. }
  597. }
  598. Q.splice(temp_index, 1);
  599. disc.push(u);
  600. if(u == end)
  601. {
  602. end.make_state("end")
  603. start.make_state("start")
  604. end.draw(grid_HTML);
  605. start.draw(grid_HTML)
  606. await ReconstructPath(prev,end)
  607. end.make_state("end")
  608. start.make_state("start")
  609. end.draw(grid_HTML);
  610. start.draw(grid_HTML)
  611. is_running = false;
  612. return
  613. }
  614. for(var n of u.neighbours)
  615. {
  616. if(disc.indexOf(n) == -1)
  617. {
  618. dist[""+n.X+"y"+n.Y] = H(n.X,n.Y,end.X,end.Y);
  619. disc.push(n);
  620. Q.push(n);
  621. n.make_state("open");
  622. n.draw(grid_HTML);
  623. prev[""+n.X+"y"+n.Y] = u;
  624. }
  625. }
  626. if(u != start && u != end)
  627. {
  628. u.make_state("closed");
  629. u.draw(grid_HTML);
  630. }
  631. await sleep(200-speed_range.value)
  632. }
  633. is_running = false;
  634. }
  635. // MAZES
  636. async function RunMaze()
  637. {
  638. ClearGrid();
  639. is_running = true;
  640. for (var row of grid)
  641. {
  642. for (var cell of row)
  643. {
  644. cell.update_wall_neighbours(grid);
  645. cell.update_neighbours(grid,false);
  646. cell.visited_fill = null;
  647. cell.visited = null;
  648. cell.connect_visited = null;
  649. }
  650. }
  651. let ctX = Math.floor(horizontal_cells/2);
  652. let ctY = Math.floor(vertical_cells/2);
  653. if(grid[ctY][ctX].is_state("start") || grid[ctY][ctX].is_state("end") && !grid[ctY+1][ctX].is_state("start") && !grid[ctY+1][ctX].is_state("end"))
  654. {
  655. ctY++;
  656. }
  657. else if(grid[ctY+1][ctX].is_state("start") || grid[ctY+1][ctX].is_state("end") && !grid[ctY][ctX+1].is_state("start") && !grid[ctY][ctX+1].is_state("end")){
  658. ctX++;
  659. }
  660. let algo = maze_algo_select.value;
  661. switch(algo){
  662. case "DFS":
  663. FillWithWalls();
  664. await RecursiveMazeDFS(ctY,ctX);
  665. break;
  666. case "Prim":
  667. FillWithWalls();
  668. await MazePrim(grid[ctY][ctX]);
  669. break;
  670. case "Random":
  671. FillWithWalls();
  672. await RecursiveMazeRandom(grid[ctY][ctX]);
  673. break;
  674. }
  675. is_running = false;
  676. }
  677. function FillWithWalls()
  678. {
  679. if(!grid[0][0].is_state("start") && !grid[0][0].is_state("end"))
  680. {
  681. RecursiveFillWithWalls(grid[0][0]);
  682. }
  683. else if(!grid[0][1].is_state("start") && !grid[0][1].is_state("end"))
  684. {
  685. RecursiveFillWithWalls(grid[0][1]);
  686. }
  687. else{
  688. RecursiveFillWithWalls(grid[1][0]);
  689. }
  690. }
  691. function RecursiveFillWithWalls(current)
  692. {
  693. if(current.is_state("start") || current.is_state("end")) return;
  694. current.make_state("wall");
  695. current.draw(grid_HTML);
  696. current.visited_fill = true;
  697. for(let n of current.neighbours)
  698. {
  699. if(n.visited_fill != true)RecursiveFillWithWalls(n);
  700. }
  701. }
  702. async function RecursiveMazeRandom(current)
  703. {
  704. current.visited = true;
  705. let neighbours = current.wall_neighbours;
  706. while(neighbours.length > 0)
  707. {
  708. let idx = Math.floor(Math.random() * neighbours.length);
  709. let n = neighbours[idx];
  710. neighbours.splice(idx,1);
  711. if(n.visited != true)
  712. {
  713. n.visited = true;
  714. let wall = [];
  715. if(n.X == current.X) wall = [n.X, n.Y>current.Y ? current.Y+1 : n.Y+1 ];
  716. else wall = [n.X>current.X ? current.X+1 : n.X+1, n.Y ];
  717. let wall_cell = grid[wall[1]][wall[0]]
  718. if(!wall_cell.is_state("start") && !wall_cell.is_state("end"))
  719. {
  720. wall_cell.make_state("null");
  721. wall_cell.draw(grid_HTML);
  722. }
  723. //await sleep(1);
  724. await RecursiveMazeRandom(wall_cell);
  725. }
  726. }
  727. }
  728. async function RecursiveMazeDFS(r,c)
  729. {
  730. let randDirs = [1,2,3,4];
  731. shuffle(randDirs);
  732. for (var i = 0; i < randDirs.length; i++) {
  733. switch(randDirs[i]){
  734. case 1:
  735. if (r - 2 <= 0 )
  736. continue;
  737. if (grid[r - 2][c].State != "null") {
  738. if(!grid[r-2][c].is_state("start") && !grid[r-2][c].is_state("end")) grid[r-2][c].make_state("null");
  739. if(!grid[r-1][c].is_state("start") && !grid[r-1][c].is_state("end")) grid[r-1][c].make_state("null");
  740. grid[r-2][c].draw(grid_HTML);
  741. grid[r-1][c].draw(grid_HTML);
  742. await sleep(1);
  743. RecursiveMazeDFS(r - 2, c);
  744. }
  745. break;
  746. case 2:
  747. if (c + 2 >= horizontal_cells - 1)
  748. continue;
  749. if (grid[r][c + 2].State != "null") {
  750. if(!grid[r][c + 2].is_state("start") && !grid[r][c + 2].is_state("end")) grid[r][c + 2].make_state("null");
  751. if(!grid[r][c + 1].is_state("start") && !grid[r][c + 1].is_state("end")) grid[r][c + 1].make_state("null");
  752. grid[r][c + 2].draw(grid_HTML);
  753. grid[r][c + 1].draw(grid_HTML);
  754. await sleep(1);
  755. RecursiveMazeDFS(r, c + 2);
  756. }
  757. break;
  758. case 3:
  759. if (r + 2 >= vertical_cells - 1)
  760. continue;
  761. if (grid[r + 2][c].State != "null") {
  762. if(!grid[r+2][c].is_state("start") && !grid[r+2][c].is_state("end")) grid[r+2][c].make_state("null");
  763. if(!grid[r+1][c].is_state("start") && !grid[r+1][c].is_state("end")) grid[r+1][c].make_state("null");
  764. grid[r+2][c].draw(grid_HTML);
  765. grid[r+1][c].draw(grid_HTML);
  766. await sleep(1);
  767. RecursiveMazeDFS(r + 2, c);
  768. }
  769. break;
  770. case 4:
  771. if (c - 2 <= 0)
  772. continue;
  773. if (grid[r][c - 2].State != "null") {
  774. if(!grid[r][c - 2].is_state("start") && !grid[r][c - 2].is_state("end")) grid[r][c - 2].make_state("null");
  775. if(!grid[r][c - 1].is_state("start") && !grid[r][c - 1].is_state("end")) grid[r][c - 1].make_state("null");
  776. grid[r][c - 2].draw(grid_HTML);
  777. grid[r][c - 1].draw(grid_HTML);
  778. await sleep(1);
  779. RecursiveMazeDFS(r, c - 2);
  780. }
  781. break;
  782. }
  783. }
  784. }
  785. async function MazePrim(start)
  786. {
  787. for(var row of grid){
  788. for(var cell of row){
  789. cell.update_wall_neighbours(grid,0);
  790. }
  791. }
  792. start.make_state("null");
  793. start.draw(grid_HTML);
  794. start.visited = true;
  795. let walls = [];
  796. for(let n of start.wall_neighbours){
  797. if(n.is_state("wall")) walls.push(n);
  798. }
  799. while(walls.length > 0)
  800. {
  801. let idx = Math.floor(Math.random() * walls.length);
  802. let r = walls[idx];
  803. walls.splice(idx,1);
  804. if( !(r.X <= 0 || r.X >= horizontal_cells-1) ){
  805. let prev = grid[r.Y][r.X-1];
  806. let next = grid[r.Y][r.X+1];
  807. if(prev.visited != true && next.visited == true){
  808. if(!r.is_state("start") && !r.is_state("end")){
  809. r.make_state("null");
  810. r.draw(grid_HTML);
  811. }
  812. prev.visited = true;
  813. if(!prev.is_state("start") && !prev.is_state("end")){
  814. prev.make_state("null");
  815. prev.draw(grid_HTML);
  816. }
  817. for(var n of prev.wall_neighbours){
  818. if(n.is_state("wall")) walls.push(n);
  819. }
  820. }
  821. else if(prev.visited == true && next.visited != true){
  822. if(!r.is_state("start") && !r.is_state("end")){
  823. r.make_state("null");
  824. r.draw(grid_HTML);
  825. }
  826. next.visited = true;
  827. if(!next.is_state("start") && !next.is_state("end")){
  828. next.make_state("null");
  829. next.draw(grid_HTML);
  830. }
  831. for(var n of next.wall_neighbours){
  832. if(n.is_state("wall")) walls.push(n);
  833. }
  834. }
  835. }
  836. if( !(r.Y <= 0 || r.Y >= vertical_cells-1) ){
  837. let prev = grid[r.Y-1][r.X];
  838. let next = grid[r.Y+1][r.X];
  839. if(prev.visited != true && next.visited == true){
  840. if(!r.is_state("start") && !r.is_state("end")){
  841. r.make_state("null");
  842. r.draw(grid_HTML);
  843. }
  844. prev.visited = true;
  845. if(!prev.is_state("start") && !prev.is_state("end")){
  846. prev.make_state("null");
  847. prev.draw(grid_HTML);
  848. }
  849. for(var n of prev.wall_neighbours){
  850. if(n.is_state("wall")) walls.push(n);
  851. }
  852. }
  853. else if(prev.visited == true && next.visited != true){
  854. if(!r.is_state("start") && !r.is_state("end")){
  855. r.make_state("null");
  856. r.draw(grid_HTML);
  857. }
  858. next.visited = true;
  859. if(!next.is_state("start") && !next.is_state("end")){
  860. next.make_state("null");
  861. next.draw(grid_HTML);
  862. }
  863. for(var n of next.wall_neighbours){
  864. if(n.is_state("wall")) walls.push(n);
  865. }
  866. }
  867. }
  868. await sleep(0);
  869. }
  870. }
  871. function RecursiveAreConnected(start,end)
  872. {
  873. if(start == end) return true;
  874. start.connect_visited = true;
  875. let connected = false;
  876. start.update_neighbours(grid,false);
  877. for(var n of start.neighbours)
  878. {
  879. if(n == end) return true;
  880. if(n.connect_visited != true) connected = connected || RecursiveAreConnected(n,end);
  881. }
  882. return connected;
  883. }
  884. function shuffle(array) {
  885. array.sort(() => Math.random() - 0.5);
  886. }
  887. return {Run, RunMaze};
  888. }