Add playback speed for best game
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import SnakeCanvas from './SnakeCanvas';
|
import SnakeCanvas from './SnakeCanvas';
|
||||||
import type { Network } from '../../lib/snakeAI/network';
|
import type { Network } from '../../lib/snakeAI/network';
|
||||||
|
|
||||||
@@ -8,6 +9,8 @@ interface BestSnakeDisplayProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function BestSnakeDisplay({ network, gridSize, fitness }: BestSnakeDisplayProps) {
|
export default function BestSnakeDisplay({ network, gridSize, fitness }: BestSnakeDisplayProps) {
|
||||||
|
const [playbackSpeed, setPlaybackSpeed] = useState(15);
|
||||||
|
|
||||||
if (!network) return null;
|
if (!network) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -19,6 +22,22 @@ export default function BestSnakeDisplay({ network, gridSize, fitness }: BestSna
|
|||||||
<span className="value">{Math.round(fitness)}</span>
|
<span className="value">{Math.round(fitness)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="playback-controls" style={{ padding: '0 10px 10px 10px' }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', fontSize: '0.8rem', color: '#888' }}>
|
||||||
|
<span>Replay Speed:</span>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
value={playbackSpeed}
|
||||||
|
onChange={(e) => setPlaybackSpeed(Number(e.target.value))}
|
||||||
|
style={{ flex: 1, accentColor: '#4ecdc4' }}
|
||||||
|
/>
|
||||||
|
<span style={{ minWidth: '3ch', textAlign: 'right' }}>{playbackSpeed}x</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="best-canvas-wrapper">
|
<div className="best-canvas-wrapper">
|
||||||
<SnakeCanvas
|
<SnakeCanvas
|
||||||
network={network}
|
network={network}
|
||||||
@@ -26,6 +45,7 @@ export default function BestSnakeDisplay({ network, gridSize, fitness }: BestSna
|
|||||||
size="large"
|
size="large"
|
||||||
showGrid={true}
|
showGrid={true}
|
||||||
showStats={true}
|
showStats={true}
|
||||||
|
playbackSpeed={playbackSpeed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ interface SnakeCanvasProps {
|
|||||||
showGrid?: boolean;
|
showGrid?: boolean;
|
||||||
size?: 'small' | 'normal' | 'large';
|
size?: 'small' | 'normal' | 'large';
|
||||||
showStats?: boolean; // Show score/length/steps even in small mode
|
showStats?: boolean; // Show score/length/steps even in small mode
|
||||||
|
playbackSpeed?: number; // Steps per second (default: 15)
|
||||||
}
|
}
|
||||||
|
|
||||||
const CELL_SIZES = {
|
const CELL_SIZES = {
|
||||||
@@ -19,7 +20,7 @@ const CELL_SIZES = {
|
|||||||
|
|
||||||
const CANVAS_PADDING = 10;
|
const CANVAS_PADDING = 10;
|
||||||
|
|
||||||
export default function SnakeCanvas({ network, gridSize, showGrid = true, size = 'normal', showStats = false }: SnakeCanvasProps) {
|
export default function SnakeCanvas({ network, gridSize, showGrid = true, size = 'normal', showStats = false, playbackSpeed = 15 }: SnakeCanvasProps) {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const [currentGame, setCurrentGame] = useState<GameState | null>(null);
|
const [currentGame, setCurrentGame] = useState<GameState | null>(null);
|
||||||
const animationFrameRef = useRef<number>();
|
const animationFrameRef = useRef<number>();
|
||||||
@@ -43,7 +44,7 @@ export default function SnakeCanvas({ network, gridSize, showGrid = true, size =
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!network || !currentGame) return;
|
if (!network || !currentGame) return;
|
||||||
|
|
||||||
const STEPS_PER_SECOND = 10; // Speed of game playback
|
const STEPS_PER_SECOND = playbackSpeed; // Use prop
|
||||||
const UPDATE_INTERVAL = 1000 / STEPS_PER_SECOND;
|
const UPDATE_INTERVAL = 1000 / STEPS_PER_SECOND;
|
||||||
|
|
||||||
const animate = (timestamp: number) => {
|
const animate = (timestamp: number) => {
|
||||||
@@ -82,7 +83,7 @@ export default function SnakeCanvas({ network, gridSize, showGrid = true, size =
|
|||||||
cancelAnimationFrame(animationFrameRef.current);
|
cancelAnimationFrame(animationFrameRef.current);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [network?.id, !!currentGame, gridSize]); // Use ID and boolean existence check to prevent loop restart on every frame
|
}, [network?.id, !!currentGame, gridSize, playbackSpeed]); // Added playbackSpeed dependency
|
||||||
|
|
||||||
// Set canvas size once when props change (not on every render)
|
// Set canvas size once when props change (not on every render)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user