Changes
This commit is contained in:
parent
652ee82849
commit
0ca6682288
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 { Button } from '@/components/ui/button';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import SocialShare from './SocialShare';
|
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 {
|
interface PresentsPuzzleProps {
|
||||||
showSocialShare?: boolean;
|
showSocialShare?: boolean;
|
||||||
shareUrl?: string;
|
shareUrl?: string;
|
||||||
|
|
@ -23,6 +23,10 @@ const PresentsPuzzle = ({
|
||||||
const [aliceFound, setAliceFound] = useState(0);
|
const [aliceFound, setAliceFound] = useState(0);
|
||||||
const [bobFound, setBobFound] = useState(0);
|
const [bobFound, setBobFound] = useState(0);
|
||||||
const [isRunning, setIsRunning] = useState(false);
|
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 [winner, setWinner] = useState<'alice' | 'bob' | 'tie' | null>(null);
|
||||||
const [simulationResults, setSimulationResults] = useState<SimulationResult>({
|
const [simulationResults, setSimulationResults] = useState<SimulationResult>({
|
||||||
alice: 0,
|
alice: 0,
|
||||||
|
|
@ -80,40 +84,23 @@ const PresentsPuzzle = ({
|
||||||
return 'tie'; // Default, though this should never happen
|
return 'tie'; // Default, though this should never happen
|
||||||
};
|
};
|
||||||
|
|
||||||
// Animate a single simulation
|
// Update display for a specific step
|
||||||
const startSimulation = async () => {
|
const updateStep = (step: number) => {
|
||||||
setIsRunning(true);
|
const aliceOpenedSet = new Set<number>();
|
||||||
setWinner(null);
|
const bobOpenedSet = new Set<number>();
|
||||||
setAliceOpened(new Set());
|
|
||||||
setBobOpened(new Set());
|
|
||||||
setAliceFound(0);
|
|
||||||
setBobFound(0);
|
|
||||||
const presents = generatePresents();
|
|
||||||
setPresentBoxes(presents);
|
|
||||||
const aliceOrder = getAliceOrder();
|
|
||||||
const bobOrder = getBobOrder();
|
|
||||||
let aliceCount = 0;
|
let aliceCount = 0;
|
||||||
let bobCount = 0;
|
let bobCount = 0;
|
||||||
let currentWinner: 'alice' | 'bob' | 'tie' | null = null;
|
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 aliceBox = aliceOrder[i];
|
||||||
const bobBox = bobOrder[i];
|
const bobBox = bobOrder[i];
|
||||||
setAliceOpened(prev => new Set(prev).add(aliceBox));
|
aliceOpenedSet.add(aliceBox);
|
||||||
setBobOpened(prev => new Set(prev).add(bobBox));
|
bobOpenedSet.add(bobBox);
|
||||||
const aliceFoundPresent = presents.has(aliceBox);
|
|
||||||
const bobFoundPresent = presents.has(bobBox);
|
if (presentBoxes.has(aliceBox)) aliceCount++;
|
||||||
if (aliceFoundPresent) {
|
if (presentBoxes.has(bobBox)) bobCount++;
|
||||||
aliceCount++;
|
|
||||||
setAliceFound(aliceCount);
|
|
||||||
}
|
|
||||||
if (bobFoundPresent) {
|
|
||||||
bobCount++;
|
|
||||||
setBobFound(bobCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for tie first (both reach 26 on same turn)
|
|
||||||
if (aliceCount === 26 && bobCount === 26) {
|
if (aliceCount === 26 && bobCount === 26) {
|
||||||
currentWinner = 'tie';
|
currentWinner = 'tie';
|
||||||
} else if (aliceCount === 26) {
|
} else if (aliceCount === 26) {
|
||||||
|
|
@ -122,10 +109,151 @@ const PresentsPuzzle = ({
|
||||||
currentWinner = 'bob';
|
currentWinner = 'bob';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAliceOpened(aliceOpenedSet);
|
||||||
|
setBobOpened(bobOpenedSet);
|
||||||
|
setAliceFound(aliceCount);
|
||||||
|
setBobFound(bobCount);
|
||||||
setWinner(currentWinner);
|
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);
|
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
|
// Reset simulation
|
||||||
const resetSimulation = () => {
|
const resetSimulation = () => {
|
||||||
setPresentBoxes(new Set());
|
setPresentBoxes(new Set());
|
||||||
|
|
@ -135,6 +263,10 @@ const PresentsPuzzle = ({
|
||||||
setBobFound(0);
|
setBobFound(0);
|
||||||
setWinner(null);
|
setWinner(null);
|
||||||
setIsRunning(false);
|
setIsRunning(false);
|
||||||
|
setIsPaused(false);
|
||||||
|
setCurrentStep(0);
|
||||||
|
setAliceOrder([]);
|
||||||
|
setBobOrder([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run 100 simulations
|
// Run 100 simulations
|
||||||
|
|
@ -235,10 +367,59 @@ const PresentsPuzzle = ({
|
||||||
</Card>}
|
</Card>}
|
||||||
|
|
||||||
{/* Control Buttons */}
|
{/* Control Buttons */}
|
||||||
<div className="flex gap-3 justify-center flex-wrap">
|
<div className="flex gap-2 justify-center flex-wrap">
|
||||||
<Button onClick={startSimulation} disabled={isRunning} className="gap-2">
|
<Button
|
||||||
|
onClick={startSimulation}
|
||||||
|
disabled={isRunning || (aliceOrder.length > 0 && winner !== null)}
|
||||||
|
className="gap-2"
|
||||||
|
>
|
||||||
<Play className="w-4 h-4" />
|
<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>
|
||||||
<Button onClick={resetSimulation} variant="outline" disabled={isRunning} className="gap-2">
|
<Button onClick={resetSimulation} variant="outline" disabled={isRunning} className="gap-2">
|
||||||
<RotateCw className="w-4 h-4" />
|
<RotateCw className="w-4 h-4" />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue