126 lines
3.9 KiB
JavaScript
126 lines
3.9 KiB
JavaScript
// Canvas visualization for mazes
|
|
|
|
const canvas = document.getElementById('mazeCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
const COLORS = {
|
|
wall: '#000000',
|
|
background: '#FFFFFF',
|
|
start: '#FFE500', // Neon yellow
|
|
end: '#FF10F0', // Neon pink
|
|
solution: '#39FF14', // Neon green
|
|
visited: '#E0E0E0' // Light gray
|
|
};
|
|
|
|
function renderMaze(mazeData, visitedCells = null, solutionPath = null) {
|
|
const rows = mazeData.rows;
|
|
const cols = mazeData.cols;
|
|
const cellSize = Math.min(Math.floor(600 / Math.max(rows, cols)), 40);
|
|
|
|
const wallThickness = Math.max(2, Math.floor(cellSize / 10));
|
|
|
|
// Set canvas size
|
|
canvas.width = cols * cellSize + wallThickness;
|
|
canvas.height = rows * cellSize + wallThickness;
|
|
|
|
// Clear canvas
|
|
ctx.fillStyle = COLORS.background;
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// Create sets for quick lookup
|
|
const visitedSet = new Set();
|
|
if (visitedCells) {
|
|
visitedCells.forEach(([r, c]) => visitedSet.add(`${r},${c}`));
|
|
}
|
|
|
|
const solutionSet = new Set();
|
|
if (solutionPath) {
|
|
solutionPath.forEach(([r, c]) => solutionSet.add(`${r},${c}`));
|
|
}
|
|
|
|
// Draw cell backgrounds
|
|
for (let row = 0; row < rows; row++) {
|
|
for (let col = 0; col < cols; col++) {
|
|
const x = col * cellSize + wallThickness;
|
|
const y = row * cellSize + wallThickness;
|
|
const key = `${row},${col}`;
|
|
|
|
// Determine cell color
|
|
let color = COLORS.background;
|
|
|
|
if (row === mazeData.start[0] && col === mazeData.start[1]) {
|
|
color = COLORS.start;
|
|
} else if (row === mazeData.end[0] && col === mazeData.end[1]) {
|
|
color = COLORS.end;
|
|
} else if (solutionSet.has(key)) {
|
|
color = COLORS.solution;
|
|
} else if (visitedSet.has(key)) {
|
|
color = COLORS.visited;
|
|
}
|
|
|
|
ctx.fillStyle = color;
|
|
ctx.fillRect(x, y, cellSize - 1, cellSize - 1);
|
|
}
|
|
}
|
|
|
|
// Draw walls
|
|
ctx.strokeStyle = COLORS.wall;
|
|
ctx.lineWidth = wallThickness;
|
|
ctx.lineCap = 'square';
|
|
|
|
for (let row = 0; row < rows; row++) {
|
|
for (let col = 0; col < cols; col++) {
|
|
const cellWalls = mazeData.walls[row][col];
|
|
const x = col * cellSize + wallThickness / 2;
|
|
const y = row * cellSize + wallThickness / 2;
|
|
|
|
// Draw north wall
|
|
if (cellWalls.north) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
ctx.lineTo(x + cellSize, y);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// Draw south wall
|
|
if (cellWalls.south) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y + cellSize);
|
|
ctx.lineTo(x + cellSize, y + cellSize);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// Draw west wall
|
|
if (cellWalls.west) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
ctx.lineTo(x, y + cellSize);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// Draw east wall
|
|
if (cellWalls.east) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x + cellSize, y);
|
|
ctx.lineTo(x + cellSize, y + cellSize);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw start and end markers with text
|
|
drawMarker(mazeData.start[0], mazeData.start[1], 'S', cellSize, wallThickness);
|
|
drawMarker(mazeData.end[0], mazeData.end[1], 'E', cellSize, wallThickness);
|
|
}
|
|
|
|
function drawMarker(row, col, text, cellSize, wallThickness) {
|
|
const x = col * cellSize + wallThickness + cellSize / 2;
|
|
const y = row * cellSize + wallThickness + cellSize / 2;
|
|
|
|
ctx.fillStyle = '#000000';
|
|
ctx.font = `bold ${Math.max(12, cellSize / 2)}px Space Grotesk, monospace`;
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(text, x, y);
|
|
}
|