TechCraft – エンジニアのためのスキルアップメモ

エンジニアのスキルアップを少しでも加速する技術ブログ

Pythonでポーカー

Pythonでポーカーを再現!

〜役判定からシミュレーション、勝敗決定まで〜

1. はじめに

トランプゲームの中でも戦略性が高い「ポーカー」は、確率と論理の世界が詰まったゲームです。
Pythonでポーカーを再現することで、データ構造・アルゴリズム・確率シミュレーションのスキルを磨くことができます。

本記事では、シンプルな「5カード・ドローポーカー」の実装を通じて、以下を学びます:

  • カードの扱い(文字列とランク)
  • 役の判定
  • 勝敗ロジック
  • シミュレーションによる役の出現確率
  • 応用アイデア紹介

2. 前提ルールと準備

  • 各プレイヤーは5枚の手札
  • ドローやベットなし(単純比較)
  • 勝敗は役の強さで決定
  • デッキは毎回シャッフル

必要なPython標準モジュール:

import random
from collections import Counter

3. カードとデッキ

suits = ['♠', '♥', '♦', '♣']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
deck = [r + s for s in suits for r in ranks]

4. 役の判定関数

def rank_to_num(rank):
    face = {'J':11, 'Q':12, 'K':13, 'A':14}
    return face.get(rank, int(rank))

def is_straight(values):
    values = sorted(set(values))
    # A-2-3-4-5もストレートとして認識
    if values == [2, 3, 4, 5, 14]:
        return True
    return len(values) == 5 and max(values) - min(values) == 4

def evaluate_hand(hand):
    ranks = [card[:-1] for card in hand]
    suits = [card[-1] for card in hand]
    values = [rank_to_num(r) for r in ranks]

    count = Counter(ranks).values()
    flush = len(set(suits)) == 1
    straight = is_straight(values)

    if flush and straight:
        return 'Straight Flush'
    elif 4 in count:
        return 'Four of a Kind'
    elif sorted(count) == [2, 3]:
        return 'Full House'
    elif flush:
        return 'Flush'
    elif straight:
        return 'Straight'
    elif 3 in count:
        return 'Three of a Kind'
    elif list(count).count(2) == 2:
        return 'Two Pair'
    elif 2 in count:
        return 'One Pair'
    else:
        return 'High Card'

5. 手札を配って勝者を決める

hand_rankings = [
    'High Card', 'One Pair', 'Two Pair', 'Three of a Kind',
    'Straight', 'Flush', 'Full House', 'Four of a Kind', 'Straight Flush'
]

def compare_hands(h1, h2):
    r1 = hand_rankings.index(evaluate_hand(h1))
    r2 = hand_rankings.index(evaluate_hand(h2))
    if r1 > r2:
        return "Player 1 wins"
    elif r1 < r2:
        return "Player 2 wins"
    else:
        return "Draw"

6. 実行例:プレイヤー同士で対戦

def play_game():
    d = deck[:]
    random.shuffle(d)
    p1 = deal_hand(d)
    p2 = deal_hand(d)

    print("Player 1:", p1, "→", evaluate_hand(p1))
    print("Player 2:", p2, "→", evaluate_hand(p2))
    print("Result:", compare_hands(p1, p2))

def deal_hand(deck, n=5):
    return [deck.pop() for _ in range(n)]

play_game()

実行出力例(毎回変わる)

Player 1: ['7♣', '8♣', '9♣', '10♣', 'J♣'] → Straight Flush  
Player 2: ['5♠', '5♦', '5♥', '2♣', '2♦'] → Full House  
Result: Player 1 wins

7. シミュレーションで役の出現率を見る

def simulate_games(n=100000):
    results = Counter()
    for _ in range(n):
        d = deck[:]
        random.shuffle(d)
        hand = deal_hand(d)
        result = evaluate_hand(hand)
        results[result] += 1
    return results

stats = simulate_games(10000)
for k, v in stats.items():
    print(f'{k:16s}: {v} ({v / 10000:.2%})')

8. 応用アイデアと拡張

💡 応用ネタ集

  • カード交換を導入(1回だけドロー可能)
  • 複数プレイヤー対応(4〜6人戦)
  • 手役の重み比較を強化(同じ役同士での勝敗)
  • 戦略付きAI実装(ランダム or 役確率で判断)
  • ベット機能追加(簡易ポーカーゲーム)

📈 教育的な効果

  • 集合操作(set)
  • Counterによる頻度解析
  • ソートと判定ロジックの実装力
  • シミュレーションによる統計的思考

9. まとめ

ポーカーは遊びながら論理的思考と確率の感覚を鍛えられる最高の題材です。
Pythonでの再現を通じて、手続き的な処理とデータ構造の扱いを身につけ、
さらにAIやゲーム制作へと発展させることも可能です。