Animation added

This commit is contained in:
2025-11-20 23:16:04 -05:00
parent 6d75c8e94e
commit 9197e464a5
8 changed files with 526 additions and 15 deletions

View File

@@ -4,6 +4,15 @@ const API_BASE = '/api';
let currentMazeId = null;
let currentMazeData = null;
let animationState = {
isAnimating: false,
isPaused: false,
currentStep: 0,
visitedCells: [],
solutionPath: [],
animationId: null,
speed: 50 // milliseconds per step
};
// DOM Elements
const generateBtn = document.getElementById('generateBtn');
@@ -15,15 +24,18 @@ const solveDfsBtn = document.getElementById('solveDfsBtn');
const solveBfsBtn = document.getElementById('solveBfsBtn');
const analyzeBtn = document.getElementById('analyzeBtn');
const benchmarkBtn = document.getElementById('benchmarkBtn');
const pauseBtn = document.getElementById('pauseBtn');
const stopBtn = document.getElementById('stopBtn');
const speedSlider = document.getElementById('speedSlider');
const algorithmSelect = document.getElementById('algorithm');
const rowsInput = document.getElementById('rows');
const colsInput = document.getElementById('cols');
const seedInput = document.getElementById('seed');
const solverSelect = document.getElementById('solver');
const resultsContent = document.getElementById('resultsContent');
const mazeInfo = document.getElementById('mazeInfo');
const animationControls = document.getElementById('animationControls');
// Disable buttons initially
function disableActionButtons() {
@@ -56,6 +68,9 @@ solveDfsBtn.addEventListener('click', () => solveMaze('dfs'));
solveBfsBtn.addEventListener('click', () => solveMaze('bfs'));
analyzeBtn.addEventListener('click', analyzeMaze);
benchmarkBtn.addEventListener('click', runBenchmark);
pauseBtn.addEventListener('click', togglePause);
stopBtn.addEventListener('click', stopAnimation);
speedSlider.addEventListener('input', updateSpeed);
// Generate Maze
async function generateMaze() {
@@ -209,13 +224,16 @@ async function loadMazeFile(filename) {
}
}
// Solve Maze
// Solve Maze with Animation
async function solveMaze(algorithm) {
if (currentMazeId === null) {
showError('No maze to solve');
return;
}
// Stop any ongoing animation
stopAnimation();
const btn = algorithm === 'dfs' ? solveDfsBtn : solveBfsBtn;
setLoading(btn, true);
@@ -227,21 +245,141 @@ async function solveMaze(algorithm) {
});
const data = await response.json();
setLoading(btn, false);
if (data.success) {
renderMaze(currentMazeData, data.visited, data.path);
// Start animated solving
startSolvingAnimation(data);
displaySolutionInfo(data);
showSuccess(`Maze solved using ${data.algorithm}!`);
} else {
showError('Failed to solve maze');
}
} catch (error) {
showError('Network error: ' + error.message);
} finally {
setLoading(btn, false);
}
}
// Animation Control Functions
function startSolvingAnimation(solutionData) {
animationState.isAnimating = true;
animationState.isPaused = false;
animationState.currentStep = 0;
animationState.visitedCells = solutionData.visited;
animationState.solutionPath = solutionData.path;
// Show animation controls
animationControls.style.display = 'block';
pauseBtn.textContent = 'PAUSE';
// Disable solve buttons during animation
solveDfsBtn.disabled = true;
solveBfsBtn.disabled = true;
// Start animation
animateStep();
}
function animateStep() {
if (!animationState.isAnimating || animationState.isPaused) {
return;
}
const { currentStep, visitedCells, solutionPath } = animationState;
if (currentStep < visitedCells.length) {
// Show visited cells up to current step
const visibleVisited = visitedCells.slice(0, currentStep + 1);
// Don't show solution path yet, only when all cells are visited
renderMaze(currentMazeData, visibleVisited, null);
animationState.currentStep++;
// Schedule next step
animationState.animationId = setTimeout(animateStep, animationState.speed);
} else if (currentStep < visitedCells.length + solutionPath.length) {
// Now animate the solution path
const pathStep = currentStep - visitedCells.length;
const visiblePath = solutionPath.slice(0, pathStep + 1);
renderMaze(currentMazeData, visitedCells, visiblePath);
animationState.currentStep++;
// Schedule next step (slower for solution path)
animationState.animationId = setTimeout(animateStep, animationState.speed * 2);
} else {
// Animation complete
finishAnimation();
}
}
function togglePause() {
if (!animationState.isAnimating) return;
animationState.isPaused = !animationState.isPaused;
if (animationState.isPaused) {
pauseBtn.textContent = 'RESUME';
if (animationState.animationId) {
clearTimeout(animationState.animationId);
}
} else {
pauseBtn.textContent = 'PAUSE';
animateStep();
}
}
function stopAnimation() {
if (!animationState.isAnimating) return;
animationState.isAnimating = false;
animationState.isPaused = false;
if (animationState.animationId) {
clearTimeout(animationState.animationId);
animationState.animationId = null;
}
// Hide animation controls
animationControls.style.display = 'none';
// Re-enable solve buttons
solveDfsBtn.disabled = false;
solveBfsBtn.disabled = false;
// Show final result if we have solution data
if (animationState.visitedCells.length > 0 && animationState.solutionPath.length > 0) {
renderMaze(currentMazeData, animationState.visitedCells, animationState.solutionPath);
} else {
renderMaze(currentMazeData);
}
}
function finishAnimation() {
animationState.isAnimating = false;
// Hide animation controls
animationControls.style.display = 'none';
// Re-enable solve buttons
solveDfsBtn.disabled = false;
solveBfsBtn.disabled = false;
// Show final result
renderMaze(currentMazeData, animationState.visitedCells, animationState.solutionPath);
showSuccess('Solving animation complete!');
}
function updateSpeed(event) {
// Speed slider: 1 (slow) to 100 (fast)
// Convert to delay: 200ms (slow) to 10ms (fast)
const sliderValue = parseInt(event.target.value);
animationState.speed = 210 - (sliderValue * 2);
}
// Analyze Maze
async function analyzeMaze() {
if (currentMazeId === null) {