Initial commit

This commit is contained in:
2025-11-20 22:58:11 -05:00
commit 6d75c8e94e
51 changed files with 5141 additions and 0 deletions

125
web/static/js/visualizer.js Normal file
View File

@@ -0,0 +1,125 @@
// 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);
}