4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

「大石泉すきポーカー」の役判定プログラムをPythonで書きました

Posted at

概要

  • よ一ど ♀(@yo_do_53)さんが、診断メーカーで「大石泉すき」診断を作る
    • 「大石泉すき」の5種類の文字から重複順列がランダムに取り出される
    • 「大石泉すき」と並ぶ確率は1 / (5 ** 5) = 1 / 3125
  • 桜花(@ikmesyk3)さんが、↑の並びをポーカーに見立てた「大石泉すきポーカー」を提案
  • 私が、その役判定プログラムを書く ←New!

先にソースコードを載せておきます

Wandboxへのリンク

import itertools
import collections
from typing import List

def judge_hand(name : str) -> str:
    """手役を判定する

    Parameters
    ----------
    name : str
        「大石泉すき」から重複を許して5文字取って並べたもの

    Returns
    -------
    str
        判定された役
    """

    # 各文字をバラす
    name_char = list(name)

    # 各文字の出現回数を数え、出現回数部分だけ抽出したもの。
    # 例:「大大すすき」→[2, 2, 1]
    char_count = collections.Counter(name_char).values()

    # 手役の判定処理
    if name == '大石泉すき':
        # 説明不要
        return 'ロイヤルストレートフラッシュ'
    elif len(set(name_char)) == 1:
        # uniq処理を施して1つしか残らない=ファイブカード
        return 'ファイブカード'
    elif 4 in char_count:
        # ある文字が4つある=フォーカード
        return 'フォーカード'
    elif len(char_count) == 5:
        # 5種類ある=元の文字列が5文字なので各文字ある=ストレートフラッシュ
        return 'ストレートフラッシュ'
    elif 2 in char_count and 3 in char_count:
        # 出現回数に「2」と「3」がある=フルハウス
        return 'フルハウス'
    elif 'すき' in name:
        # すき
        return 'すき'
    elif 3 in char_count:
        # 出現回数に「3」がある=スリーカード
        return 'スリーカード'
    elif 2 in char_count and len(char_count) == 3:
        # 出現回数が3文字分あって「2」が含まれる=消去法からツーペア
        return 'ツーペア'
    return 'ブタ'

# メインルーチン
if __name__ == '__main__':
    # 使用する文字の種類
    chars = '大石泉すき'

    # itertools.productを利用して、重複順列を作り出し、1セットづつname_charに取り出す
    for name_char in itertools.product(chars, repeat=5):
        # name_charの全文字を結合したものをnameとする
        name = ''.join(name_char)
      
        # 判定を行い、結果を表示する
        print(f"{name} {judge_hand(name)}")
result1.txt
大大大大大 ファイブカード
大大大大石 フォーカード
大大大大泉 フォーカード
(中略)
大石泉すす ブタ
大石泉すき ロイヤルストレートフラッシュ
大石泉き大 ブタ
(中略)
きききき泉 フォーカード
ききききす フォーカード
ききききき ファイブカード

ポイント

  • 文字列(str型)に対してlist()を適用すると、1文字づつにバラけます
    • 例:list('大石泉すき')  # => ['大', '石', '泉', 'す', 'き']
  • collections.Counter()を使えば、配列の各要素における個数を数えられます
    • 例:[0, 1, 1, 2, 2, 2, 3]  # => {0 => 1, 1 => 2, 2 => 3, 3 => 1}
  • set()を使えば重複した文字を実質取り除けます。リストに戻したければlist()で更に囲みます
    • 例:set([0, 1, 1, 2, 2, 2, 3])  # => {0, 1, 2, 3}
  • itertools.product()を使えば、重複順列を自動で生成してくれます
    • 本来itertools.product([0, 1, 2], repeat=5)のように使いますが、Pythonはstr型もイテレーション可能なので……

おまけ:確率を計算

後ろの部分をちょいちょいと書き換えるだけでOKです。

Wandboxへのリンク

if __name__ == '__main__':
    # 使用する文字の種類
    chars = '大石泉すき'

    # itertools.productを利用して、重複順列を作り出し、1セットづつname_charに取り出す
    temp = []
    for name_char in itertools.product(chars, repeat=5):
        # name_charの全文字を結合したものをnameとする
        name = ''.join(name_char)
      
        # 判定を行い、結果を格納する
        temp.append(judge_hand(name))

    # カウントした結果を表示する
    from pprint import pprint
    pprint(collections.Counter(temp))
result2.txt
Counter({'ブタ': 984,
         'ツーペア': 765,
         'スリーカード': 516,
         'すき': 435,
         'フルハウス': 200,
         'ストレートフラッシュ': 119,
         'フォーカード': 100,
         'ファイブカード': 5,
         'ロイヤルストレートフラッシュ': 1})
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?