Visual edit in Lovable
This commit is contained in:
parent
e9d524df70
commit
095c7ccbf7
1 changed files with 139 additions and 189 deletions
|
|
@ -8,36 +8,42 @@ import { Switch } from '@/components/ui/switch';
|
||||||
import { Slider } from '@/components/ui/slider';
|
import { Slider } from '@/components/ui/slider';
|
||||||
import { Dice1, Dice2, Dice3, Dice4, Dice5, Dice6, RotateCcw, Settings, Play } from 'lucide-react';
|
import { Dice1, Dice2, Dice3, Dice4, Dice5, Dice6, RotateCcw, Settings, Play } from 'lucide-react';
|
||||||
import SocialShare from '@/components/SocialShare';
|
import SocialShare from '@/components/SocialShare';
|
||||||
|
|
||||||
interface CrapsGameProps {
|
interface CrapsGameProps {
|
||||||
showSocialShare?: boolean;
|
showSocialShare?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDiceIcon = (value: number) => {
|
const getDiceIcon = (value: number) => {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 1: return <Dice1 className="w-12 h-12" />;
|
case 1:
|
||||||
case 2: return <Dice2 className="w-12 h-12" />;
|
return <Dice1 className="w-12 h-12" />;
|
||||||
case 3: return <Dice3 className="w-12 h-12" />;
|
case 2:
|
||||||
case 4: return <Dice4 className="w-12 h-12" />;
|
return <Dice2 className="w-12 h-12" />;
|
||||||
case 5: return <Dice5 className="w-12 h-12" />;
|
case 3:
|
||||||
case 6: return <Dice6 className="w-12 h-12" />;
|
return <Dice3 className="w-12 h-12" />;
|
||||||
default: return <Dice1 className="w-12 h-12" />;
|
case 4:
|
||||||
|
return <Dice4 className="w-12 h-12" />;
|
||||||
|
case 5:
|
||||||
|
return <Dice5 className="w-12 h-12" />;
|
||||||
|
case 6:
|
||||||
|
return <Dice6 className="w-12 h-12" />;
|
||||||
|
default:
|
||||||
|
return <Dice1 className="w-12 h-12" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const CrapsGame: React.FC<CrapsGameProps> = ({
|
||||||
const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
showSocialShare = false
|
||||||
|
}) => {
|
||||||
const [dice1, setDice1] = useState<number | null>(null);
|
const [dice1, setDice1] = useState<number | null>(null);
|
||||||
const [dice2, setDice2] = useState<number | null>(null);
|
const [dice2, setDice2] = useState<number | null>(null);
|
||||||
const [isRolling, setIsRolling] = useState(false);
|
const [isRolling, setIsRolling] = useState(false);
|
||||||
const [gameResult, setGameResult] = useState<'win' | 'lose' | 'continue' | null>(null);
|
const [gameResult, setGameResult] = useState<'win' | 'lose' | 'continue' | null>(null);
|
||||||
const [rollCount, setRollCount] = useState(0);
|
const [rollCount, setRollCount] = useState(0);
|
||||||
|
|
||||||
// Custom rules state
|
// Custom rules state
|
||||||
const [customWinSums, setCustomWinSums] = useState<number[]>([7, 11]);
|
const [customWinSums, setCustomWinSums] = useState<number[]>([7, 11]);
|
||||||
const [customLoseSums, setCustomLoseSums] = useState<number[]>([2, 3, 12]);
|
const [customLoseSums, setCustomLoseSums] = useState<number[]>([2, 3, 12]);
|
||||||
const [isCustomRules, setIsCustomRules] = useState(false);
|
const [isCustomRules, setIsCustomRules] = useState(false);
|
||||||
const [isRulesModalOpen, setIsRulesModalOpen] = useState(false);
|
const [isRulesModalOpen, setIsRulesModalOpen] = useState(false);
|
||||||
|
|
||||||
// Simulation state
|
// Simulation state
|
||||||
const [simulationRounds, setSimulationRounds] = useState([10]);
|
const [simulationRounds, setSimulationRounds] = useState([10]);
|
||||||
const [isSimulating, setIsSimulating] = useState(false);
|
const [isSimulating, setIsSimulating] = useState(false);
|
||||||
|
|
@ -55,25 +61,22 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
totalTurns: number;
|
totalTurns: number;
|
||||||
completedGames: number;
|
completedGames: number;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
const rollDice = () => {
|
const rollDice = () => {
|
||||||
setIsRolling(true);
|
setIsRolling(true);
|
||||||
setGameResult(null);
|
setGameResult(null);
|
||||||
|
|
||||||
// Simulate rolling animation
|
// Simulate rolling animation
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newDice1 = Math.floor(Math.random() * 6) + 1;
|
const newDice1 = Math.floor(Math.random() * 6) + 1;
|
||||||
const newDice2 = Math.floor(Math.random() * 6) + 1;
|
const newDice2 = Math.floor(Math.random() * 6) + 1;
|
||||||
const sum = newDice1 + newDice2;
|
const sum = newDice1 + newDice2;
|
||||||
|
|
||||||
setDice1(newDice1);
|
setDice1(newDice1);
|
||||||
setDice2(newDice2);
|
setDice2(newDice2);
|
||||||
setRollCount(prev => prev + 1);
|
setRollCount(prev => prev + 1);
|
||||||
|
|
||||||
// Determine game result based on current rules
|
// Determine game result based on current rules
|
||||||
const winSums = isCustomRules ? customWinSums : [7, 11];
|
const winSums = isCustomRules ? customWinSums : [7, 11];
|
||||||
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
||||||
|
|
||||||
if (loseSums.includes(sum)) {
|
if (loseSums.includes(sum)) {
|
||||||
setGameResult('lose');
|
setGameResult('lose');
|
||||||
} else if (winSums.includes(sum)) {
|
} else if (winSums.includes(sum)) {
|
||||||
|
|
@ -81,29 +84,36 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
} else {
|
} else {
|
||||||
setGameResult('continue');
|
setGameResult('continue');
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsRolling(false);
|
setIsRolling(false);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
const simulateGame = () => {
|
const simulateGame = () => {
|
||||||
const winSums = isCustomRules ? customWinSums : [7, 11];
|
const winSums = isCustomRules ? customWinSums : [7, 11];
|
||||||
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
||||||
|
|
||||||
let turns = 1;
|
let turns = 1;
|
||||||
let point: number | null = null;
|
let point: number | null = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const die1 = Math.floor(Math.random() * 6) + 1;
|
const die1 = Math.floor(Math.random() * 6) + 1;
|
||||||
const die2 = Math.floor(Math.random() * 6) + 1;
|
const die2 = Math.floor(Math.random() * 6) + 1;
|
||||||
const sum = die1 + die2;
|
const sum = die1 + die2;
|
||||||
|
|
||||||
if (point === null) {
|
if (point === null) {
|
||||||
// First roll (come out roll)
|
// First roll (come out roll)
|
||||||
if (loseSums.includes(sum)) {
|
if (loseSums.includes(sum)) {
|
||||||
return { result: 'lose', turns, die1, die2, sum };
|
return {
|
||||||
|
result: 'lose',
|
||||||
|
turns,
|
||||||
|
die1,
|
||||||
|
die2,
|
||||||
|
sum
|
||||||
|
};
|
||||||
} else if (winSums.includes(sum)) {
|
} else if (winSums.includes(sum)) {
|
||||||
return { result: 'win', turns, die1, die2, sum };
|
return {
|
||||||
|
result: 'win',
|
||||||
|
turns,
|
||||||
|
die1,
|
||||||
|
die2,
|
||||||
|
sum
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
point = sum;
|
point = sum;
|
||||||
turns++;
|
turns++;
|
||||||
|
|
@ -111,50 +121,63 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
} else {
|
} else {
|
||||||
// Subsequent rolls
|
// Subsequent rolls
|
||||||
if (sum === point) {
|
if (sum === point) {
|
||||||
return { result: 'win', turns, die1, die2, sum };
|
return {
|
||||||
|
result: 'win',
|
||||||
|
turns,
|
||||||
|
die1,
|
||||||
|
die2,
|
||||||
|
sum
|
||||||
|
};
|
||||||
} else if (sum === 7) {
|
} else if (sum === 7) {
|
||||||
return { result: 'lose', turns, die1, die2, sum };
|
return {
|
||||||
|
result: 'lose',
|
||||||
|
turns,
|
||||||
|
die1,
|
||||||
|
die2,
|
||||||
|
sum
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
turns++;
|
turns++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const simulateGameSlow = async (gameNumber: number) => {
|
const simulateGameSlow = async (gameNumber: number) => {
|
||||||
const winSums = isCustomRules ? customWinSums : [7, 11];
|
const winSums = isCustomRules ? customWinSums : [7, 11];
|
||||||
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
const loseSums = isCustomRules ? customLoseSums : [2, 3, 12];
|
||||||
|
|
||||||
let turns = 1;
|
let turns = 1;
|
||||||
let point: number | null = null;
|
let point: number | null = null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Show rolling animation
|
// Show rolling animation
|
||||||
setIsRolling(true);
|
setIsRolling(true);
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
|
||||||
const die1 = Math.floor(Math.random() * 6) + 1;
|
const die1 = Math.floor(Math.random() * 6) + 1;
|
||||||
const die2 = Math.floor(Math.random() * 6) + 1;
|
const die2 = Math.floor(Math.random() * 6) + 1;
|
||||||
const sum = die1 + die2;
|
const sum = die1 + die2;
|
||||||
|
|
||||||
// Update dice display
|
// Update dice display
|
||||||
setDice1(die1);
|
setDice1(die1);
|
||||||
setDice2(die2);
|
setDice2(die2);
|
||||||
setIsRolling(false);
|
setIsRolling(false);
|
||||||
|
|
||||||
// Wait to show the result
|
// Wait to show the result
|
||||||
await new Promise(resolve => setTimeout(resolve, 800));
|
await new Promise(resolve => setTimeout(resolve, 800));
|
||||||
|
|
||||||
if (point === null) {
|
if (point === null) {
|
||||||
// First roll (come out roll)
|
// First roll (come out roll)
|
||||||
if (loseSums.includes(sum)) {
|
if (loseSums.includes(sum)) {
|
||||||
setGameResult('lose');
|
setGameResult('lose');
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
return { result: 'lose', turns };
|
return {
|
||||||
|
result: 'lose',
|
||||||
|
turns
|
||||||
|
};
|
||||||
} else if (winSums.includes(sum)) {
|
} else if (winSums.includes(sum)) {
|
||||||
setGameResult('win');
|
setGameResult('win');
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
return { result: 'win', turns };
|
return {
|
||||||
|
result: 'win',
|
||||||
|
turns
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
setGameResult('continue');
|
setGameResult('continue');
|
||||||
point = sum;
|
point = sum;
|
||||||
|
|
@ -166,11 +189,17 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
if (sum === point) {
|
if (sum === point) {
|
||||||
setGameResult('win');
|
setGameResult('win');
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
return { result: 'win', turns };
|
return {
|
||||||
|
result: 'win',
|
||||||
|
turns
|
||||||
|
};
|
||||||
} else if (sum === 7) {
|
} else if (sum === 7) {
|
||||||
setGameResult('lose');
|
setGameResult('lose');
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
return { result: 'lose', turns };
|
return {
|
||||||
|
result: 'lose',
|
||||||
|
turns
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
setGameResult('continue');
|
setGameResult('continue');
|
||||||
turns++;
|
turns++;
|
||||||
|
|
@ -179,7 +208,6 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const runSimulation = async () => {
|
const runSimulation = async () => {
|
||||||
setIsSimulating(true);
|
setIsSimulating(true);
|
||||||
setCurrentSimulationGame(0);
|
setCurrentSimulationGame(0);
|
||||||
|
|
@ -188,20 +216,23 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
let wins = 0;
|
let wins = 0;
|
||||||
let losses = 0;
|
let losses = 0;
|
||||||
let totalTurns = 0;
|
let totalTurns = 0;
|
||||||
|
|
||||||
if (slowMode) {
|
if (slowMode) {
|
||||||
// Initialize live stats for slow mode
|
// Initialize live stats for slow mode
|
||||||
setLiveSimulationStats({ wins: 0, losses: 0, totalTurns: 0, completedGames: 0 });
|
setLiveSimulationStats({
|
||||||
|
wins: 0,
|
||||||
|
losses: 0,
|
||||||
|
totalTurns: 0,
|
||||||
|
completedGames: 0
|
||||||
|
});
|
||||||
|
|
||||||
// Slow mode: simulate visually
|
// Slow mode: simulate visually
|
||||||
for (let i = 0; i < numGames; i++) {
|
for (let i = 0; i < numGames; i++) {
|
||||||
setCurrentSimulationGame(i + 1);
|
setCurrentSimulationGame(i + 1);
|
||||||
setGameResult(null);
|
setGameResult(null);
|
||||||
const game = await simulateGameSlow(i + 1);
|
const game = await simulateGameSlow(i + 1);
|
||||||
if (game.result === 'win') wins++;
|
if (game.result === 'win') wins++;else losses++;
|
||||||
else losses++;
|
|
||||||
totalTurns += game.turns;
|
totalTurns += game.turns;
|
||||||
|
|
||||||
// Update live stats
|
// Update live stats
|
||||||
setLiveSimulationStats({
|
setLiveSimulationStats({
|
||||||
wins,
|
wins,
|
||||||
|
|
@ -209,7 +240,7 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
totalTurns,
|
totalTurns,
|
||||||
completedGames: i + 1
|
completedGames: i + 1
|
||||||
});
|
});
|
||||||
|
|
||||||
// Brief pause between games
|
// Brief pause between games
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
}
|
}
|
||||||
|
|
@ -217,10 +248,9 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
// Fast mode: simulate in background
|
// Fast mode: simulate in background
|
||||||
for (let i = 0; i < numGames; i++) {
|
for (let i = 0; i < numGames; i++) {
|
||||||
const game = simulateGame();
|
const game = simulateGame();
|
||||||
if (game.result === 'win') wins++;
|
if (game.result === 'win') wins++;else losses++;
|
||||||
else losses++;
|
|
||||||
totalTurns += game.turns;
|
totalTurns += game.turns;
|
||||||
|
|
||||||
// Add a small delay every 10 games to show progress
|
// Add a small delay every 10 games to show progress
|
||||||
if (i % 10 === 0) {
|
if (i % 10 === 0) {
|
||||||
setCurrentSimulationGame(i + 1);
|
setCurrentSimulationGame(i + 1);
|
||||||
|
|
@ -228,7 +258,6 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSimulationResults({
|
setSimulationResults({
|
||||||
wins,
|
wins,
|
||||||
losses,
|
losses,
|
||||||
|
|
@ -239,66 +268,52 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
setLiveSimulationStats(null);
|
setLiveSimulationStats(null);
|
||||||
setIsSimulating(false);
|
setIsSimulating(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetGame = () => {
|
const resetGame = () => {
|
||||||
setDice1(null);
|
setDice1(null);
|
||||||
setDice2(null);
|
setDice2(null);
|
||||||
setGameResult(null);
|
setGameResult(null);
|
||||||
setSimulationResults(null);
|
setSimulationResults(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sum = dice1 && dice2 ? dice1 + dice2 : null;
|
const sum = dice1 && dice2 ? dice1 + dice2 : null;
|
||||||
|
|
||||||
const getResultMessage = () => {
|
const getResultMessage = () => {
|
||||||
if (!gameResult) return null;
|
if (!gameResult) return null;
|
||||||
|
|
||||||
switch (gameResult) {
|
switch (gameResult) {
|
||||||
case 'win':
|
case 'win':
|
||||||
return (
|
return <div className="text-center space-y-2">
|
||||||
<div className="text-center space-y-2">
|
|
||||||
<Badge variant="default" className="bg-green-600 text-white text-lg px-4 py-2">
|
<Badge variant="default" className="bg-green-600 text-white text-lg px-4 py-2">
|
||||||
🎉 You Win! 🎉
|
🎉 You Win! 🎉
|
||||||
</Badge>
|
</Badge>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Rolling {sum} on the first throw wins immediately!
|
Rolling {sum} on the first throw wins immediately!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>;
|
||||||
);
|
|
||||||
case 'lose':
|
case 'lose':
|
||||||
return (
|
return <div className="text-center space-y-2">
|
||||||
<div className="text-center space-y-2">
|
|
||||||
<Badge variant="destructive" className="text-lg px-4 py-2">
|
<Badge variant="destructive" className="text-lg px-4 py-2">
|
||||||
💸 You Lose! 💸
|
💸 You Lose! 💸
|
||||||
</Badge>
|
</Badge>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Rolling {sum} on the first throw loses immediately!
|
Rolling {sum} on the first throw loses immediately!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>;
|
||||||
);
|
|
||||||
case 'continue':
|
case 'continue':
|
||||||
return (
|
return <div className="text-center space-y-2">
|
||||||
<div className="text-center space-y-2">
|
|
||||||
<Badge variant="secondary" className="text-lg px-4 py-2">
|
<Badge variant="secondary" className="text-lg px-4 py-2">
|
||||||
🎲 Game Continues 🎲
|
🎲 Game Continues 🎲
|
||||||
</Badge>
|
</Badge>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Your point is {sum}. Keep playing to win or lose!
|
Your point is {sum}. Keep playing to win or lose!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>;
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return <div className="max-w-4xl mx-auto p-6 space-y-6">
|
||||||
return (
|
|
||||||
<div className="max-w-4xl mx-auto p-6 space-y-6">
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="text-center">
|
<CardHeader className="text-center">
|
||||||
<CardTitle className="text-3xl font-bold text-foreground">Craps: An Exploration</CardTitle>
|
<CardTitle className="text-3xl font-bold text-foreground">Craps: An Exploration</CardTitle>
|
||||||
<CardDescription className="text-lg">
|
<CardDescription className="text-lg">In the game of Craps, we roll two dice, and note the sum S. In the traditional game, if S is 2, 3, or 12, you lose immediately; if the S is 7 or 11, you win immediately, and the game continues otherwise.</CardDescription>
|
||||||
Roll two dice and see what happens on the opening throw of craps!
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-6">
|
<CardContent className="space-y-6">
|
||||||
{/* Simulation Controls */}
|
{/* Simulation Controls */}
|
||||||
|
|
@ -312,52 +327,27 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<label htmlFor="slow-mode" className="text-sm font-medium">Slow Mode</label>
|
<label htmlFor="slow-mode" className="text-sm font-medium">Slow Mode</label>
|
||||||
<Switch
|
<Switch id="slow-mode" checked={slowMode} onCheckedChange={setSlowMode} />
|
||||||
id="slow-mode"
|
|
||||||
checked={slowMode}
|
|
||||||
onCheckedChange={setSlowMode}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">Number of games: {simulationRounds[0]}</label>
|
<label className="text-sm font-medium">Number of games: {simulationRounds[0]}</label>
|
||||||
<Slider
|
<Slider value={simulationRounds} onValueChange={setSimulationRounds} max={25} min={1} step={1} className="w-full" />
|
||||||
value={simulationRounds}
|
|
||||||
onValueChange={setSimulationRounds}
|
|
||||||
max={25}
|
|
||||||
min={1}
|
|
||||||
step={1}
|
|
||||||
className="w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button onClick={runSimulation} disabled={isSimulating} className="w-full gap-2">
|
||||||
onClick={runSimulation}
|
|
||||||
disabled={isSimulating}
|
|
||||||
className="w-full gap-2"
|
|
||||||
>
|
|
||||||
<Play className="w-4 h-4" />
|
<Play className="w-4 h-4" />
|
||||||
{isSimulating
|
{isSimulating ? slowMode ? `Simulating Game ${currentSimulationGame}/${simulationRounds[0]}...` : 'Simulating...' : 'Simulate'}
|
||||||
? (slowMode
|
|
||||||
? `Simulating Game ${currentSimulationGame}/${simulationRounds[0]}...`
|
|
||||||
: 'Simulating...'
|
|
||||||
)
|
|
||||||
: 'Simulate'
|
|
||||||
}
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{(simulationResults || liveSimulationStats) && (
|
{(simulationResults || liveSimulationStats) && <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4 p-4 bg-muted/50 rounded-lg">
|
||||||
<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-center">
|
||||||
<div className="text-2xl font-bold text-green-600">
|
<div className="text-2xl font-bold text-green-600">
|
||||||
{liveSimulationStats ? liveSimulationStats.wins : simulationResults!.wins}
|
{liveSimulationStats ? liveSimulationStats.wins : simulationResults!.wins}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">Wins</div>
|
<div className="text-sm text-muted-foreground">Wins</div>
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{liveSimulationStats
|
{liveSimulationStats ? `(${(liveSimulationStats.wins / Math.max(liveSimulationStats.completedGames, 1) * 100).toFixed(1)}%)` : `(${(simulationResults!.wins / simulationResults!.totalGames * 100).toFixed(1)}%)`}
|
||||||
? `(${((liveSimulationStats.wins / Math.max(liveSimulationStats.completedGames, 1)) * 100).toFixed(1)}%)`
|
|
||||||
: `(${((simulationResults!.wins / simulationResults!.totalGames) * 100).toFixed(1)}%)`
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
|
|
@ -366,26 +356,19 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">Losses</div>
|
<div className="text-sm text-muted-foreground">Losses</div>
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{liveSimulationStats
|
{liveSimulationStats ? `(${(liveSimulationStats.losses / Math.max(liveSimulationStats.completedGames, 1) * 100).toFixed(1)}%)` : `(${(simulationResults!.losses / simulationResults!.totalGames * 100).toFixed(1)}%)`}
|
||||||
? `(${((liveSimulationStats.losses / Math.max(liveSimulationStats.completedGames, 1)) * 100).toFixed(1)}%)`
|
|
||||||
: `(${((simulationResults!.losses / simulationResults!.totalGames) * 100).toFixed(1)}%)`
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="text-2xl font-bold text-blue-600">
|
<div className="text-2xl font-bold text-blue-600">
|
||||||
{liveSimulationStats
|
{liveSimulationStats ? (liveSimulationStats.totalTurns / Math.max(liveSimulationStats.completedGames, 1)).toFixed(1) : simulationResults!.averageTurns.toFixed(1)}
|
||||||
? (liveSimulationStats.totalTurns / Math.max(liveSimulationStats.completedGames, 1)).toFixed(1)
|
|
||||||
: simulationResults!.averageTurns.toFixed(1)
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">Avg Turns</div>
|
<div className="text-sm text-muted-foreground">Avg Turns</div>
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{liveSimulationStats ? `(${liveSimulationStats.completedGames} games)` : 'per game'}
|
{liveSimulationStats ? `(${liveSimulationStats.completedGames} games)` : 'per game'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
)}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
@ -413,66 +396,53 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-4 text-red-600">Loss Sums</h3>
|
<h3 className="font-semibold mb-4 text-red-600">Loss Sums</h3>
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
{Array.from({ length: 11 }, (_, i) => i + 2).map((sum) => (
|
{Array.from({
|
||||||
<div key={`loss-${sum}`} className="flex items-center space-x-2">
|
length: 11
|
||||||
<Checkbox
|
}, (_, i) => i + 2).map(sum => <div key={`loss-${sum}`} className="flex items-center space-x-2">
|
||||||
id={`loss-${sum}`}
|
<Checkbox id={`loss-${sum}`} checked={customLoseSums.includes(sum)} onCheckedChange={checked => {
|
||||||
checked={customLoseSums.includes(sum)}
|
if (checked) {
|
||||||
onCheckedChange={(checked) => {
|
setCustomLoseSums([...customLoseSums.filter(s => s !== sum), sum]);
|
||||||
if (checked) {
|
setCustomWinSums(customWinSums.filter(s => s !== sum));
|
||||||
setCustomLoseSums([...customLoseSums.filter(s => s !== sum), sum]);
|
} else {
|
||||||
setCustomWinSums(customWinSums.filter(s => s !== sum));
|
setCustomLoseSums(customLoseSums.filter(s => s !== sum));
|
||||||
} else {
|
}
|
||||||
setCustomLoseSums(customLoseSums.filter(s => s !== sum));
|
}} />
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<label htmlFor={`loss-${sum}`} className="text-sm">{sum}</label>
|
<label htmlFor={`loss-${sum}`} className="text-sm">{sum}</label>
|
||||||
</div>
|
</div>)}
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-4 text-green-600">Win Sums</h3>
|
<h3 className="font-semibold mb-4 text-green-600">Win Sums</h3>
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
{Array.from({ length: 11 }, (_, i) => i + 2).map((sum) => (
|
{Array.from({
|
||||||
<div key={`win-${sum}`} className="flex items-center space-x-2">
|
length: 11
|
||||||
<Checkbox
|
}, (_, i) => i + 2).map(sum => <div key={`win-${sum}`} className="flex items-center space-x-2">
|
||||||
id={`win-${sum}`}
|
<Checkbox id={`win-${sum}`} checked={customWinSums.includes(sum)} onCheckedChange={checked => {
|
||||||
checked={customWinSums.includes(sum)}
|
if (checked) {
|
||||||
onCheckedChange={(checked) => {
|
setCustomWinSums([...customWinSums.filter(s => s !== sum), sum]);
|
||||||
if (checked) {
|
setCustomLoseSums(customLoseSums.filter(s => s !== sum));
|
||||||
setCustomWinSums([...customWinSums.filter(s => s !== sum), sum]);
|
} else {
|
||||||
setCustomLoseSums(customLoseSums.filter(s => s !== sum));
|
setCustomWinSums(customWinSums.filter(s => s !== sum));
|
||||||
} else {
|
}
|
||||||
setCustomWinSums(customWinSums.filter(s => s !== sum));
|
}} />
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<label htmlFor={`win-${sum}`} className="text-sm">{sum}</label>
|
<label htmlFor={`win-${sum}`} className="text-sm">{sum}</label>
|
||||||
</div>
|
</div>)}
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between gap-4">
|
<div className="flex justify-between gap-4">
|
||||||
<Button
|
<Button variant="outline" onClick={() => {
|
||||||
variant="outline"
|
setCustomWinSums([7, 11]);
|
||||||
onClick={() => {
|
setCustomLoseSums([2, 3, 12]);
|
||||||
setCustomWinSums([7, 11]);
|
setIsCustomRules(false);
|
||||||
setCustomLoseSums([2, 3, 12]);
|
}}>
|
||||||
setIsCustomRules(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Reset to Classic
|
Reset to Classic
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button onClick={() => {
|
||||||
onClick={() => {
|
setIsCustomRules(true);
|
||||||
setIsCustomRules(true);
|
setIsRulesModalOpen(false);
|
||||||
setIsRulesModalOpen(false);
|
resetGame();
|
||||||
resetGame();
|
}}>
|
||||||
}}
|
|
||||||
>
|
|
||||||
Apply Custom Rules
|
Apply Custom Rules
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -483,11 +453,11 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Badge variant="destructive" className="mb-2">Immediate Loss</Badge>
|
<Badge variant="destructive" className="mb-2">Immediate Loss</Badge>
|
||||||
<p>{isCustomRules ? (customLoseSums.length > 0 ? customLoseSums.join(', ') : 'None') : 'Rolling 2, 3, or 12'}</p>
|
<p>{isCustomRules ? customLoseSums.length > 0 ? customLoseSums.join(', ') : 'None' : 'Rolling 2, 3, or 12'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Badge variant="default" className="mb-2 bg-green-600">Immediate Win</Badge>
|
<Badge variant="default" className="mb-2 bg-green-600">Immediate Win</Badge>
|
||||||
<p>{isCustomRules ? (customWinSums.length > 0 ? customWinSums.join(', ') : 'None') : 'Rolling 7 or 11'}</p>
|
<p>{isCustomRules ? customWinSums.length > 0 ? customWinSums.join(', ') : 'None' : 'Rolling 7 or 11'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Badge variant="secondary" className="mb-2">Game Continues</Badge>
|
<Badge variant="secondary" className="mb-2">Game Continues</Badge>
|
||||||
|
|
@ -525,11 +495,7 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
|
|
||||||
<div className="text-center space-y-2">
|
<div className="text-center space-y-2">
|
||||||
<div className={`p-4 rounded-lg border-2 min-w-[80px] ${sum ? 'border-primary bg-primary/10' : 'border-muted'}`}>
|
<div className={`p-4 rounded-lg border-2 min-w-[80px] ${sum ? 'border-primary bg-primary/10' : 'border-muted'}`}>
|
||||||
{sum ? (
|
{sum ? <div className="text-3xl font-bold text-primary">{sum}</div> : <div className="w-12 h-12 bg-muted rounded border-2 border-dashed mx-auto"></div>}
|
||||||
<div className="text-3xl font-bold text-primary">{sum}</div>
|
|
||||||
) : (
|
|
||||||
<div className="w-12 h-12 bg-muted rounded border-2 border-dashed mx-auto"></div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground">Total</p>
|
<p className="text-sm text-muted-foreground">Total</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -545,18 +511,10 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
|
|
||||||
{/* Controls */}
|
{/* Controls */}
|
||||||
<div className="flex justify-center gap-4">
|
<div className="flex justify-center gap-4">
|
||||||
<Button
|
<Button onClick={rollDice} disabled={isRolling} className="px-8 py-3 text-lg">
|
||||||
onClick={rollDice}
|
|
||||||
disabled={isRolling}
|
|
||||||
className="px-8 py-3 text-lg"
|
|
||||||
>
|
|
||||||
{isRolling ? 'Rolling...' : 'Roll Dice'}
|
{isRolling ? 'Rolling...' : 'Roll Dice'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button variant="outline" onClick={resetGame} className="px-8 py-3">
|
||||||
variant="outline"
|
|
||||||
onClick={resetGame}
|
|
||||||
className="px-8 py-3"
|
|
||||||
>
|
|
||||||
<RotateCcw className="w-4 h-4 mr-2" />
|
<RotateCcw className="w-4 h-4 mr-2" />
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -599,17 +557,9 @@ const CrapsGame: React.FC<CrapsGameProps> = ({ showSocialShare = false }) => {
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{showSocialShare && (
|
{showSocialShare && <div className="flex justify-center">
|
||||||
<div className="flex justify-center">
|
<SocialShare title="Craps: First Throw" description="Learn about probability through the classic casino game of craps!" url={`${window.location.origin}/craps-game`} />
|
||||||
<SocialShare
|
</div>}
|
||||||
title="Craps: First Throw"
|
</div>;
|
||||||
description="Learn about probability through the classic casino game of craps!"
|
|
||||||
url={`${window.location.origin}/craps-game`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CrapsGame;
|
export default CrapsGame;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue