用Python模拟CRAPS花旗骰游戏:从概率分析到代码实现
在编程学习过程中,将数学概念与趣味性案例结合往往能事半功倍。CRAPS游戏作为概率论的经典案例,为我们提供了绝佳的学习素材。本文将带你从零开始,用Python构建完整的游戏模拟器,并通过数据分析揭示背后的概率规律。
1. 游戏规则与概率基础
CRAPS游戏的核心机制建立在两个六面骰子的随机组合上。每次投掷会产生2到12之间的点数,但不同点数的出现概率并不相同。理解这一点是进行准确模拟的前提。
骰子点数概率分布表:
| 点数 | 组合方式 | 组合数 | 概率 |
|---|---|---|---|
| 2 | (1,1) | 1 | 1/36 |
| 3 | (1,2),(2,1) | 2 | 2/36 |
| 4 | (1,3),(2,2),(3,1) | 3 | 3/36 |
| 5 | (1,4),(2,3),(3,2),(4,1) | 4 | 4/36 |
| 6 | (1,5),(2,4),(3,3),(4,2),(5,1) | 5 | 5/36 |
| 7 | (1,6),(2,5),(3,4),(4,3),(5,2),(6,1) | 6 | 6/36 |
| 8 | (2,6),(3,5),(4,4),(5,3),(6,2) | 5 | 5/36 |
| 9 | (3,6),(4,5),(5,4),(6,3) | 4 | 4/36 |
| 10 | (4,6),(5,5),(6,4) | 3 | 3/36 |
| 11 | (5,6),(6,5) | 2 | 2/36 |
| 12 | (6,6) | 1 | 1/36 |
游戏规则可分解为两个阶段:
- 初投阶段:首次投掷决定直接胜负或进入下一阶段
- 续投阶段:若初投未分胜负,则持续投掷直到满足条件
注意:虽然规则看似简单,但精确计算各结果的概率需要考虑条件概率和马尔可夫链的概念。
2. 基础模拟器实现
我们先构建一个最小可行版本,逐步完善功能。核心是random模块的合理使用和游戏状态的准确跟踪。
import random def roll_dice(): """模拟两个骰子的投掷""" return random.randint(1, 6) + random.randint(1, 6) def craps_game(): """单局游戏模拟""" first_roll = roll_dice() print(f"初投点数: {first_roll}") # 初投判定 if first_roll in (7, 11): return "玩家胜" elif first_roll in (2, 3, 12): return "庄家胜" # 续投阶段 while True: next_roll = roll_dice() print(f"续投点数: {next_roll}") if next_roll == 7: return "庄家胜" elif next_roll == first_roll: return "玩家胜" # 测试单局游戏 result = craps_game() print(f"游戏结果: {result}")这个基础版本已经包含了完整的游戏逻辑,但缺乏以下重要功能:
- 胜负统计
- 概率计算
- 资金管理
- 用户交互
3. 概率分析与模拟优化
通过大规模模拟,我们可以验证理论概率。蒙特卡洛方法在此类问题中表现出色。
def probability_simulation(num_games=100000): """大规模模拟计算胜负概率""" player_wins = 0 house_wins = 0 for _ in range(num_games): first_roll = roll_dice() if first_roll in (7, 11): player_wins += 1 continue if first_roll in (2, 3, 12): house_wins += 1 continue while True: next_roll = roll_dice() if next_roll == 7: house_wins += 1 break if next_roll == first_roll: player_wins += 1 break p_win = player_wins / num_games p_lose = house_wins / num_games return p_win, p_lose # 运行百万次模拟 win_prob, lose_prob = probability_simulation(1000000) print(f"玩家胜率: {win_prob:.2%}") print(f"庄家胜率: {lose_prob:.2%}")典型输出结果:
玩家胜率: 49.29% 庄家胜率: 50.71%与理论计算值(玩家49.29%,庄家50.71%)高度吻合,验证了模拟的准确性。
4. 完整游戏模拟器开发
现在我们将所有功能整合,创建一个交互式的游戏模拟器,包含资金管理和策略测试功能。
class CrapsSimulator: def __init__(self, initial_balance=1000): self.balance = initial_balance self.stats = { 'wins': 0, 'losses': 0, 'win_streak': 0, 'max_win_streak': 0, 'current_streak': 0 } def roll_dice(self): return random.randint(1, 6) + random.randint(1, 6) def play_round(self, bet): if bet > self.balance: print("下注超过当前余额!") return False first_roll = self.roll_dice() print(f"\n初投结果: {first_roll}") # 初投判定 if first_roll in (7, 11): self.balance += bet self._update_stats(True) print(f"玩家胜!当前余额: {self.balance}") return True elif first_roll in (2, 3, 12): self.balance -= bet self._update_stats(False) print(f"庄家胜!当前余额: {self.balance}") return True # 续投阶段 point = first_roll print(f"进入续投阶段,目标点数: {point}") while True: next_roll = self.roll_dice() print(f"续投结果: {next_roll}") if next_roll == 7: self.balance -= bet self._update_stats(False) print(f"庄家胜!当前余额: {self.balance}") return True elif next_roll == point: self.balance += bet self._update_stats(True) print(f"玩家胜!当前余额: {self.balance}") return True def _update_stats(self, is_win): if is_win: self.stats['wins'] += 1 self.stats['current_streak'] += 1 if self.stats['current_streak'] > self.stats['max_win_streak']: self.stats['max_win_streak'] = self.stats['current_streak'] else: self.stats['losses'] += 1 self.stats['current_streak'] = 0 def get_stats(self): total = self.stats['wins'] + self.stats['losses'] win_rate = self.stats['wins'] / total if total > 0 else 0 return { 'win_rate': f"{win_rate:.1%}", 'max_win_streak': self.stats['max_win_streak'], 'current_balance': self.balance } # 使用示例 simulator = CrapsSimulator(1000) while simulator.balance > 0: bet = int(input(f"\n当前余额: {simulator.balance} 请输入下注金额 (0退出): ")) if bet == 0: break simulator.play_round(bet) stats = simulator.get_stats() print("\n游戏统计:") print(f"胜率: {stats['win_rate']}") print(f"最长连胜: {stats['max_win_streak']}次") print(f"最终余额: {stats['current_balance']}")这个完整版本提供了以下增强功能:
- 资金管理系统
- 游戏统计跟踪
- 连胜记录
- 交互式界面
5. 策略测试与优化
了解游戏概率后,我们可以测试不同的下注策略。以下是三种常见策略的模拟实现:
def test_strategy(strategy_func, initial_balance=1000, num_rounds=1000): """测试特定策略的表现""" simulator = CrapsSimulator(initial_balance) strategy = strategy_func(simulator) for _ in range(num_rounds): if simulator.balance <= 0: break bet = next(strategy) simulator.play_round(bet) return simulator.get_stats() # 固定下注策略 def fixed_bet(simulator): while True: yield 10 # 每次固定下注10单位 # 马丁格尔策略(输后加倍) def martingale(simulator): base_bet = 10 current_bet = base_bet while True: yield current_bet if simulator.stats['current_streak'] < 0: # 最近一次输了 current_bet *= 2 else: current_bet = base_bet # 斐波那契策略 def fibonacci(simulator): sequence = [1, 1] index = 1 while True: if simulator.stats['current_streak'] < 0: # 输了前进一位 index = min(index + 1, len(sequence) - 1) else: # 赢了后退两位 index = max(index - 2, 0) yield sequence[index] * 10 if index >= len(sequence) - 1: sequence.append(sequence[-1] + sequence[-2]) # 策略对比测试 strategies = { "固定下注": fixed_bet, "马丁格尔": martingale, "斐波那契": fibonacci } results = {} for name, strategy in strategies.items(): results[name] = test_strategy(strategy) print(f"{name}策略结果: {results[name]}")策略测试通常会显示:
- 固定下注:最稳定,波动最小
- 马丁格尔:高风险高波动,可能短期获利但长期必然亏损
- 斐波那契:介于两者之间,但仍无法改变负期望值
重要发现:没有任何策略能改变游戏的负期望值,这与概率论的基本结论一致。