Add presents controls
Enhance Presents Puzzle with pause, step, and navigation controls: - Add pause, step next/back, step to start/end buttons - Integrate into existing puzzle controls and state - Enable stepping through simulation without auto-rotation/motion X-Lovable-Edit-ID: edt-d7d358ef-a108-4530-a942-9a6508865305
This commit is contained in:
commit
6f35e0c38e
1 changed files with 212 additions and 31 deletions
|
|
@ -3,7 +3,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import SocialShare from './SocialShare';
|
||||
import { Gift, Play, RotateCw, Zap } from 'lucide-react';
|
||||
import { Gift, Play, RotateCw, Zap, Pause, ChevronRight, ChevronLeft, ChevronsRight, ChevronsLeft } from 'lucide-react';
|
||||
interface PresentsPuzzleProps {
|
||||
showSocialShare?: boolean;
|
||||
shareUrl?: string;
|
||||
|
|
@ -23,6 +23,10 @@ const PresentsPuzzle = ({
|
|||
const [aliceFound, setAliceFound] = useState(0);
|
||||
const [bobFound, setBobFound] = useState(0);
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [aliceOrder, setAliceOrder] = useState<number[]>([]);
|
||||
const [bobOrder, setBobOrder] = useState<number[]>([]);
|
||||
const [winner, setWinner] = useState<'alice' | 'bob' | 'tie' | null>(null);
|
||||
const [simulationResults, setSimulationResults] = useState<SimulationResult>({
|
||||
alice: 0,
|
||||
|
|
@ -80,40 +84,23 @@ const PresentsPuzzle = ({
|
|||
return 'tie'; // Default, though this should never happen
|
||||
};
|
||||
|
||||
// Animate a single simulation
|
||||
const startSimulation = async () => {
|
||||
setIsRunning(true);
|
||||
setWinner(null);
|
||||
setAliceOpened(new Set());
|
||||
setBobOpened(new Set());
|
||||
setAliceFound(0);
|
||||
setBobFound(0);
|
||||
const presents = generatePresents();
|
||||
setPresentBoxes(presents);
|
||||
const aliceOrder = getAliceOrder();
|
||||
const bobOrder = getBobOrder();
|
||||
// Update display for a specific step
|
||||
const updateStep = (step: number) => {
|
||||
const aliceOpenedSet = new Set<number>();
|
||||
const bobOpenedSet = new Set<number>();
|
||||
let aliceCount = 0;
|
||||
let bobCount = 0;
|
||||
let currentWinner: 'alice' | 'bob' | 'tie' | null = null;
|
||||
for (let i = 0; i < 100 && !currentWinner; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 50)); // Animation delay
|
||||
|
||||
for (let i = 0; i <= step; i++) {
|
||||
const aliceBox = aliceOrder[i];
|
||||
const bobBox = bobOrder[i];
|
||||
setAliceOpened(prev => new Set(prev).add(aliceBox));
|
||||
setBobOpened(prev => new Set(prev).add(bobBox));
|
||||
const aliceFoundPresent = presents.has(aliceBox);
|
||||
const bobFoundPresent = presents.has(bobBox);
|
||||
if (aliceFoundPresent) {
|
||||
aliceCount++;
|
||||
setAliceFound(aliceCount);
|
||||
}
|
||||
if (bobFoundPresent) {
|
||||
bobCount++;
|
||||
setBobFound(bobCount);
|
||||
}
|
||||
aliceOpenedSet.add(aliceBox);
|
||||
bobOpenedSet.add(bobBox);
|
||||
|
||||
if (presentBoxes.has(aliceBox)) aliceCount++;
|
||||
if (presentBoxes.has(bobBox)) bobCount++;
|
||||
|
||||
// Check for tie first (both reach 26 on same turn)
|
||||
if (aliceCount === 26 && bobCount === 26) {
|
||||
currentWinner = 'tie';
|
||||
} else if (aliceCount === 26) {
|
||||
|
|
@ -122,10 +109,151 @@ const PresentsPuzzle = ({
|
|||
currentWinner = 'bob';
|
||||
}
|
||||
}
|
||||
|
||||
setAliceOpened(aliceOpenedSet);
|
||||
setBobOpened(bobOpenedSet);
|
||||
setAliceFound(aliceCount);
|
||||
setBobFound(bobCount);
|
||||
setWinner(currentWinner);
|
||||
setCurrentStep(step);
|
||||
};
|
||||
|
||||
// Animate a single simulation
|
||||
const startSimulation = async () => {
|
||||
if (currentStep === 0) {
|
||||
// Start new simulation
|
||||
setIsRunning(true);
|
||||
setIsPaused(false);
|
||||
setWinner(null);
|
||||
setAliceOpened(new Set());
|
||||
setBobOpened(new Set());
|
||||
setAliceFound(0);
|
||||
setBobFound(0);
|
||||
setCurrentStep(0);
|
||||
const presents = generatePresents();
|
||||
setPresentBoxes(presents);
|
||||
const newAliceOrder = getAliceOrder();
|
||||
const newBobOrder = getBobOrder();
|
||||
setAliceOrder(newAliceOrder);
|
||||
setBobOrder(newBobOrder);
|
||||
|
||||
// Start animation from beginning
|
||||
let aliceCount = 0;
|
||||
let bobCount = 0;
|
||||
let currentWinner: 'alice' | 'bob' | 'tie' | null = null;
|
||||
|
||||
for (let i = 0; i < 100 && !currentWinner; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
// Check if paused
|
||||
while (isPaused) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
const aliceBox = newAliceOrder[i];
|
||||
const bobBox = newBobOrder[i];
|
||||
setAliceOpened(prev => new Set(prev).add(aliceBox));
|
||||
setBobOpened(prev => new Set(prev).add(bobBox));
|
||||
setCurrentStep(i);
|
||||
|
||||
const aliceFoundPresent = presents.has(aliceBox);
|
||||
const bobFoundPresent = presents.has(bobBox);
|
||||
if (aliceFoundPresent) {
|
||||
aliceCount++;
|
||||
setAliceFound(aliceCount);
|
||||
}
|
||||
if (bobFoundPresent) {
|
||||
bobCount++;
|
||||
setBobFound(bobCount);
|
||||
}
|
||||
|
||||
if (aliceCount === 26 && bobCount === 26) {
|
||||
currentWinner = 'tie';
|
||||
} else if (aliceCount === 26) {
|
||||
currentWinner = 'alice';
|
||||
} else if (bobCount === 26) {
|
||||
currentWinner = 'bob';
|
||||
}
|
||||
}
|
||||
setWinner(currentWinner);
|
||||
setIsRunning(false);
|
||||
} else {
|
||||
// Resume from current step
|
||||
setIsRunning(true);
|
||||
setIsPaused(false);
|
||||
|
||||
let aliceCount = aliceFound;
|
||||
let bobCount = bobFound;
|
||||
let currentWinner: 'alice' | 'bob' | 'tie' | null = winner;
|
||||
|
||||
for (let i = currentStep + 1; i < 100 && !currentWinner; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
while (isPaused) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
const aliceBox = aliceOrder[i];
|
||||
const bobBox = bobOrder[i];
|
||||
setAliceOpened(prev => new Set(prev).add(aliceBox));
|
||||
setBobOpened(prev => new Set(prev).add(bobBox));
|
||||
setCurrentStep(i);
|
||||
|
||||
const aliceFoundPresent = presentBoxes.has(aliceBox);
|
||||
const bobFoundPresent = presentBoxes.has(bobBox);
|
||||
if (aliceFoundPresent) {
|
||||
aliceCount++;
|
||||
setAliceFound(aliceCount);
|
||||
}
|
||||
if (bobFoundPresent) {
|
||||
bobCount++;
|
||||
setBobFound(bobCount);
|
||||
}
|
||||
|
||||
if (aliceCount === 26 && bobCount === 26) {
|
||||
currentWinner = 'tie';
|
||||
} else if (aliceCount === 26) {
|
||||
currentWinner = 'alice';
|
||||
} else if (bobCount === 26) {
|
||||
currentWinner = 'bob';
|
||||
}
|
||||
}
|
||||
setWinner(currentWinner);
|
||||
setIsRunning(false);
|
||||
}
|
||||
};
|
||||
|
||||
const pauseSimulation = () => {
|
||||
setIsPaused(true);
|
||||
setIsRunning(false);
|
||||
};
|
||||
|
||||
const stepNext = () => {
|
||||
if (aliceOrder.length === 0 || currentStep >= 99 || winner) return;
|
||||
updateStep(currentStep + 1);
|
||||
};
|
||||
|
||||
const stepBack = () => {
|
||||
if (aliceOrder.length === 0 || currentStep <= 0) return;
|
||||
setWinner(null);
|
||||
updateStep(currentStep - 1);
|
||||
};
|
||||
|
||||
const stepToEnd = () => {
|
||||
if (aliceOrder.length === 0) return;
|
||||
updateStep(99);
|
||||
};
|
||||
|
||||
const stepToStart = () => {
|
||||
if (aliceOrder.length === 0) return;
|
||||
setAliceOpened(new Set());
|
||||
setBobOpened(new Set());
|
||||
setAliceFound(0);
|
||||
setBobFound(0);
|
||||
setCurrentStep(0);
|
||||
setWinner(null);
|
||||
};
|
||||
|
||||
// Reset simulation
|
||||
const resetSimulation = () => {
|
||||
setPresentBoxes(new Set());
|
||||
|
|
@ -135,6 +263,10 @@ const PresentsPuzzle = ({
|
|||
setBobFound(0);
|
||||
setWinner(null);
|
||||
setIsRunning(false);
|
||||
setIsPaused(false);
|
||||
setCurrentStep(0);
|
||||
setAliceOrder([]);
|
||||
setBobOrder([]);
|
||||
};
|
||||
|
||||
// Run 100 simulations
|
||||
|
|
@ -235,10 +367,59 @@ const PresentsPuzzle = ({
|
|||
</Card>}
|
||||
|
||||
{/* Control Buttons */}
|
||||
<div className="flex gap-3 justify-center flex-wrap">
|
||||
<Button onClick={startSimulation} disabled={isRunning} className="gap-2">
|
||||
<div className="flex gap-2 justify-center flex-wrap">
|
||||
<Button
|
||||
onClick={startSimulation}
|
||||
disabled={isRunning || (aliceOrder.length > 0 && winner !== null)}
|
||||
className="gap-2"
|
||||
>
|
||||
<Play className="w-4 h-4" />
|
||||
Start
|
||||
{currentStep === 0 ? 'Start' : 'Resume'}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={pauseSimulation}
|
||||
disabled={!isRunning}
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
>
|
||||
<Pause className="w-4 h-4" />
|
||||
Pause
|
||||
</Button>
|
||||
<Button
|
||||
onClick={stepToStart}
|
||||
disabled={isRunning || aliceOrder.length === 0 || currentStep === 0}
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
title="Step to start"
|
||||
>
|
||||
<ChevronsLeft className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={stepBack}
|
||||
disabled={isRunning || aliceOrder.length === 0 || currentStep === 0}
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
title="Step back"
|
||||
>
|
||||
<ChevronLeft className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={stepNext}
|
||||
disabled={isRunning || aliceOrder.length === 0 || currentStep >= 99 || winner !== null}
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
title="Step next"
|
||||
>
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={stepToEnd}
|
||||
disabled={isRunning || aliceOrder.length === 0 || currentStep >= 99}
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
title="Step to end"
|
||||
>
|
||||
<ChevronsRight className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button onClick={resetSimulation} variant="outline" disabled={isRunning} className="gap-2">
|
||||
<RotateCw className="w-4 h-4" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue