Add simulation functionality
This commit is contained in:
parent
ad9dfb54b0
commit
189c4bde54
1 changed files with 128 additions and 2 deletions
|
|
@ -4,7 +4,8 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
|||
import { Badge } from '@/components/ui/badge';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Dice1, Dice2, Dice3, Dice4, Dice5, Dice6, RotateCcw, Settings } from 'lucide-react';
|
||||
import { Slider } from '@/components/ui/slider';
|
||||
import { Dice1, Dice2, Dice3, Dice4, Dice5, Dice6, RotateCcw, Settings, Play } from 'lucide-react';
|
||||
import SocialShare from '@/components/SocialShare';
|
||||
|
||||
interface CrapsGameProps {
|
||||
|
|
@ -35,6 +36,16 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
|||
const [customLoseSums, setCustomLoseSums] = useState<number[]>([2, 3, 12]);
|
||||
const [isCustomRules, setIsCustomRules] = useState(false);
|
||||
const [isRulesModalOpen, setIsRulesModalOpen] = useState(false);
|
||||
|
||||
// Simulation state
|
||||
const [simulationRounds, setSimulationRounds] = useState([10]);
|
||||
const [isSimulating, setIsSimulating] = useState(false);
|
||||
const [simulationResults, setSimulationResults] = useState<{
|
||||
wins: number;
|
||||
losses: number;
|
||||
averageTurns: number;
|
||||
totalGames: number;
|
||||
} | null>(null);
|
||||
|
||||
const rollDice = () => {
|
||||
setIsRolling(true);
|
||||
|
|
@ -66,11 +77,75 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
|||
}, 1000);
|
||||
};
|
||||
|
||||
const simulateGame = () => {
|
||||
const winSums = isCustomRules ? customWinSums : [7, 11];
|
||||
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
||||
|
||||
let turns = 1;
|
||||
let point: number | null = null;
|
||||
|
||||
while (true) {
|
||||
const die1 = Math.floor(Math.random() * 6) + 1;
|
||||
const die2 = Math.floor(Math.random() * 6) + 1;
|
||||
const sum = die1 + die2;
|
||||
|
||||
if (point === null) {
|
||||
// First roll (come out roll)
|
||||
if (loseSums.includes(sum)) {
|
||||
return { result: 'lose', turns };
|
||||
} else if (winSums.includes(sum)) {
|
||||
return { result: 'win', turns };
|
||||
} else {
|
||||
point = sum;
|
||||
turns++;
|
||||
}
|
||||
} else {
|
||||
// Subsequent rolls
|
||||
if (sum === point) {
|
||||
return { result: 'win', turns };
|
||||
} else if (sum === 7) {
|
||||
return { result: 'lose', turns };
|
||||
} else {
|
||||
turns++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const runSimulation = async () => {
|
||||
setIsSimulating(true);
|
||||
const numGames = simulationRounds[0];
|
||||
let wins = 0;
|
||||
let losses = 0;
|
||||
let totalTurns = 0;
|
||||
|
||||
// Add small delays to show progress
|
||||
for (let i = 0; i < numGames; i++) {
|
||||
const game = simulateGame();
|
||||
if (game.result === 'win') wins++;
|
||||
else losses++;
|
||||
totalTurns += game.turns;
|
||||
|
||||
// Add a small delay every 10 games to show progress
|
||||
if (i % 10 === 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
}
|
||||
}
|
||||
|
||||
setSimulationResults({
|
||||
wins,
|
||||
losses,
|
||||
averageTurns: totalTurns / numGames,
|
||||
totalGames: numGames
|
||||
});
|
||||
setIsSimulating(false);
|
||||
};
|
||||
|
||||
const resetGame = () => {
|
||||
setDice1(null);
|
||||
setDice2(null);
|
||||
setGameResult(null);
|
||||
setRollCount(0);
|
||||
setSimulationResults(null);
|
||||
};
|
||||
|
||||
const sum = dice1 && dice2 ? dice1 + dice2 : null;
|
||||
|
|
@ -127,6 +202,57 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
|||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
{/* Simulation Controls */}
|
||||
<Card className="bg-accent/5">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Simulation</CardTitle>
|
||||
<CardDescription>
|
||||
Run multiple games to analyze win/loss statistics
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Number of games: {simulationRounds[0]}</label>
|
||||
<Slider
|
||||
value={simulationRounds}
|
||||
onValueChange={setSimulationRounds}
|
||||
max={25}
|
||||
min={1}
|
||||
step={1}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={runSimulation}
|
||||
disabled={isSimulating}
|
||||
className="w-full gap-2"
|
||||
>
|
||||
<Play className="w-4 h-4" />
|
||||
{isSimulating ? 'Simulating...' : 'Simulate'}
|
||||
</Button>
|
||||
|
||||
{simulationResults && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4 p-4 bg-muted/50 rounded-lg">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-green-600">{simulationResults.wins}</div>
|
||||
<div className="text-sm text-muted-foreground">Wins</div>
|
||||
<div className="text-xs">({((simulationResults.wins / simulationResults.totalGames) * 100).toFixed(1)}%)</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-red-600">{simulationResults.losses}</div>
|
||||
<div className="text-sm text-muted-foreground">Losses</div>
|
||||
<div className="text-xs">({((simulationResults.losses / simulationResults.totalGames) * 100).toFixed(1)}%)</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold text-blue-600">{simulationResults.averageTurns.toFixed(1)}</div>
|
||||
<div className="text-sm text-muted-foreground">Avg Turns</div>
|
||||
<div className="text-xs">per game</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Rules */}
|
||||
<Card className="bg-muted/50">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue