Fix tie detection in Presents Puzzle

- Both players now properly tie when they find all 26 presents on the same turn
- Single simulation displays "It's a tie!" message when both finish together
- Batch simulation (100 rounds) now tracks and displays ties separately
- Updated results grid to show three columns: Alice, Bob, and Ties
- Fixed logic to check both players on the same iteration
- No longer unfairly favors Alice in tie scenarios
This commit is contained in:
Claude 2025-11-19 02:35:15 +00:00
parent d0582d3fe5
commit 489df7b113
No known key found for this signature in database

View file

@ -23,7 +23,7 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
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 [winner, setWinner] = useState<'alice' | 'bob' | null>(null); const [winner, setWinner] = useState<'alice' | 'bob' | 'tie' | null>(null);
const [simulationResults, setSimulationResults] = useState<SimulationResult>({ alice: 0, bob: 0, ties: 0 }); const [simulationResults, setSimulationResults] = useState<SimulationResult>({ alice: 0, bob: 0, ties: 0 });
const [hasSimulated, setHasSimulated] = useState(false); const [hasSimulated, setHasSimulated] = useState(false);
@ -49,7 +49,7 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
}; };
// Simulate one round // Simulate one round
const simulateRound = (presents: Set<number>): 'alice' | 'bob' => { const simulateRound = (presents: Set<number>): 'alice' | 'bob' | 'tie' => {
const aliceOrder = getAliceOrder(); const aliceOrder = getAliceOrder();
const bobOrder = getBobOrder(); const bobOrder = getBobOrder();
@ -57,18 +57,21 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
let bobCount = 0; let bobCount = 0;
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {
if (presents.has(aliceOrder[i])) { const aliceFoundPresent = presents.has(aliceOrder[i]);
aliceCount++; const bobFoundPresent = presents.has(bobOrder[i]);
if (aliceCount === 26) return 'alice';
}
if (presents.has(bobOrder[i])) { if (aliceFoundPresent) aliceCount++;
bobCount++; if (bobFoundPresent) bobCount++;
if (bobCount === 26) return 'bob';
} // Check if both reached 26 on the same turn (tie)
if (aliceCount === 26 && bobCount === 26) return 'tie';
// Check individual winners
if (aliceCount === 26) return 'alice';
if (bobCount === 26) return 'bob';
} }
return 'alice'; // Default, though this should never happen return 'tie'; // Default, though this should never happen
}; };
// Animate a single simulation // Animate a single simulation
@ -88,7 +91,7 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
let aliceCount = 0; let aliceCount = 0;
let bobCount = 0; let bobCount = 0;
let currentWinner: 'alice' | 'bob' | null = null; let currentWinner: 'alice' | 'bob' | 'tie' | null = null;
for (let i = 0; i < 100 && !currentWinner; i++) { for (let i = 0; i < 100 && !currentWinner; i++) {
await new Promise(resolve => setTimeout(resolve, 50)); // Animation delay await new Promise(resolve => setTimeout(resolve, 50)); // Animation delay
@ -99,20 +102,26 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
setAliceOpened(prev => new Set(prev).add(aliceBox)); setAliceOpened(prev => new Set(prev).add(aliceBox));
setBobOpened(prev => new Set(prev).add(bobBox)); setBobOpened(prev => new Set(prev).add(bobBox));
if (presents.has(aliceBox)) { const aliceFoundPresent = presents.has(aliceBox);
const bobFoundPresent = presents.has(bobBox);
if (aliceFoundPresent) {
aliceCount++; aliceCount++;
setAliceFound(aliceCount); setAliceFound(aliceCount);
if (aliceCount === 26) {
currentWinner = 'alice';
}
} }
if (presents.has(bobBox)) { if (bobFoundPresent) {
bobCount++; bobCount++;
setBobFound(bobCount); setBobFound(bobCount);
if (bobCount === 26 && !currentWinner) { }
currentWinner = 'bob';
} // Check for tie first (both reach 26 on same turn)
if (aliceCount === 26 && bobCount === 26) {
currentWinner = 'tie';
} else if (aliceCount === 26) {
currentWinner = 'alice';
} else if (bobCount === 26) {
currentWinner = 'bob';
} }
} }
@ -140,8 +149,10 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
const winner = simulateRound(presents); const winner = simulateRound(presents);
if (winner === 'alice') { if (winner === 'alice') {
results.alice++; results.alice++;
} else { } else if (winner === 'bob') {
results.bob++; results.bob++;
} else {
results.ties++;
} }
} }
@ -236,7 +247,10 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
<CardContent className="pt-6"> <CardContent className="pt-6">
<div className="text-center"> <div className="text-center">
<div className="text-2xl font-bold text-primary"> <div className="text-2xl font-bold text-primary">
{winner === 'alice' ? '🎉 Alice' : '🎉 Bob'} found all 26 presents first! {winner === 'tie'
? "🤝 It's a tie! Both found all 26 presents at the same time!"
: `🎉 ${winner === 'alice' ? 'Alice' : 'Bob'} found all 26 presents first!`
}
</div> </div>
</div> </div>
</CardContent> </CardContent>
@ -285,7 +299,7 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
<CardTitle className="text-lg">Results from 100 Simulations</CardTitle> <CardTitle className="text-lg">Results from 100 Simulations</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-3 gap-4">
<div className="text-center space-y-2"> <div className="text-center space-y-2">
<div className="text-4xl font-bold text-blue-600 dark:text-blue-400"> <div className="text-4xl font-bold text-blue-600 dark:text-blue-400">
{simulationResults.alice} {simulationResults.alice}
@ -304,15 +318,26 @@ const PresentsPuzzle = ({ showSocialShare = false, shareUrl }: PresentsPuzzlePro
{((simulationResults.bob / 100) * 100).toFixed(1)}% {((simulationResults.bob / 100) * 100).toFixed(1)}%
</div> </div>
</div> </div>
<div className="text-center space-y-2">
<div className="text-4xl font-bold text-orange-600 dark:text-orange-400">
{simulationResults.ties}
</div>
<div className="text-sm font-medium">Ties</div>
<div className="text-xs text-muted-foreground">
{((simulationResults.ties / 100) * 100).toFixed(1)}%
</div>
</div>
</div> </div>
<div className="mt-4 pt-4 border-t border-border"> <div className="mt-4 pt-4 border-t border-border">
<p className="text-sm text-muted-foreground text-center"> <p className="text-sm text-muted-foreground text-center">
{simulationResults.alice > simulationResults.bob {simulationResults.alice > simulationResults.bob && simulationResults.alice > simulationResults.ties
? '💡 Alice tends to win more often!' ? '💡 Alice tends to win more often!'
: simulationResults.bob > simulationResults.alice : simulationResults.bob > simulationResults.alice && simulationResults.bob > simulationResults.ties
? '💡 Bob tends to win more often!' ? '💡 Bob tends to win more often!'
: '💡 They appear equally likely to win!' : simulationResults.ties > simulationResults.alice && simulationResults.ties > simulationResults.bob
? '💡 Ties are most common!'
: '💡 The results are quite balanced!'
} }
</p> </p>
</div> </div>