// --------------------------------------------- // DOM // --------------------------------------------- const fileInput = document.getElementById("fileInput"); const canvas = document.getElementById("mapCanvas"); const ctx = canvas.getContext("2d"); const submitBtn = document.getElementById("submitBtn"); const runBtn = document.getElementById("runBtn"); // Grid // --------------------------------------------- const gridWidth = 20; const gridHeight = 20; // 0 = walkable | 1 = wall | 2 = exit | 3 = start let grid = []; let uploadedImage = null; // Modes: "walls" → "exits" → "start" let mode = "walls"; // --------------------------------------------- // Init grid // --------------------------------------------- for (let r = 0; r < gridHeight; r++) { grid[r] = []; for (let c = 0; c < gridWidth; c++) { grid[r][c] = 0; } } // --------------------------------------------- // Image upload // --------------------------------------------- fileInput.addEventListener("change", (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = ev => { const img = new Image(); img.onload = () => { uploadedImage = img; generateGridFromImage(img); drawGrid(); }; img.src = ev.target.result; }; reader.readAsDataURL(file); }); // --------------------------------------------- // Generate grid from image // --------------------------------------------- function generateGridFromImage(img) { const temp = document.createElement("canvas"); temp.width = canvas.width; temp.height = canvas.height; const tctx = temp.getContext("2d"); tctx.drawImage(img, 0, 0, canvas.width, canvas.height); const data = tctx.getImageData(0,0,canvas.width,canvas.height).data; const tileW = canvas.width / gridWidth; const tileH = canvas.height / gridHeight; for (let r = 0; r < gridHeight; r++) { for (let c = 0; c < gridWidth; c++) { let dark = 0; for (let y = r * tileH; y < (r+1)*tileH; y++) { for (let x = c * tileW; x < (c+1)*tileW; x++) { const i = (Math.floor(y) * canvas.width + Math.floor(x)) * 4; const b = (data[i] + data[i+1] + data[i+2]) / 3; if (b < 120) dark++; } } grid[r][c] = dark > tileW * tileH * 0.05 ? 1 : 0; } } } // --------------------------------------------- // Draw grid // --------------------------------------------- function drawGrid() { const tileW = canvas.width / gridWidth; const tileH = canvas.height / gridHeight; ctx.clearRect(0,0,canvas.width,canvas.height); if (uploadedImage) ctx.drawImage(uploadedImage,0,0,canvas.width,canvas.height); for (let r=0;r { const rect = canvas.getBoundingClientRect(); const col = Math.floor((e.clientX - rect.left) / (canvas.width / gridWidth)); const row = Math.floor((e.clientY - rect.top) / (canvas.height / gridHeight)); if (!grid[row] || grid[row][col] === undefined) return; if (mode === "walls") { grid[row][col] = grid[row][col] === 1 ? 0 : 1; } else if (mode === "exits") { grid[row][col] = grid[row][col] === 2 ? 0 : 2; } else if (mode === "start") { for (let r=0;r { if (mode === "walls") { mode = "exits"; submitBtn.textContent = "Submit Exits"; alert("Now mark exits."); } else if (mode === "exits") { mode = "start"; submitBtn.textContent = "Place Start"; alert("Now place the start tile."); } }; // --------------------------------------------- // Run A* // --------------------------------------------- runBtn.onclick = () => { drawGrid(); runAStar(); }; // --------------------------------------------- // A* pathfinding // --------------------------------------------- function heuristic(a,b) { return Math.abs(a.r-b.r) + Math.abs(a.c-b.c); } function neighbors(n) { return [[1,0],[-1,0],[0,1],[0,-1]] .map(d => ({ r:n.r+d[0], c:n.c+d[1] })) .filter(p => p.r>=0 && p.r=0 && p.c`${n.r},${n.c}`; g[key(start)]=0; f[key(start)]=0; while (open.length) { open.sort((a,b)=>f[key(a)]-f[key(b)]); const cur=open.shift(); if (grid[cur.r][cur.c]===2) { drawPath(reconstruct(came,cur)); return; } for (const nb of neighbors(cur)) { const tg=g[key(cur)]+1; if (g[key(nb)]===undefined||tgheuristic(nb,e))); if (!open.find(o=>key(o)===key(nb))) open.push(nb); } } } alert("No path found."); } function reconstruct(came,cur){ const p=[cur]; while(came[`${cur.r},${cur.c}`]){ cur=came[`${cur.r},${cur.c}`]; p.push(cur); } return p.reverse(); } function drawPath(path){ const w=canvas.width/gridWidth; const h=canvas.height/gridHeight; ctx.fillStyle="rgba(0,0,0,0.7)"; path.forEach(p=>ctx.fillRect(p.c*w,p.r*h,w,h)); }