python練習問題〜シリーズ1第3回、レベル超初級の初級3〜

Python

前回のおさらい

さて、前回はカード4枚というポーカにはまだ程遠い状態でしたが、2ペアまで出てきました。これからさらに少しずつ本物のポーカに近ずけていきましょう。最後はテキサスホールデム作りたい(あくまで個人的な趣味です)

前回の記事は以下です。

連載回数カードの前提
第1回山札20枚、カード3枚ドロー、数値1〜5、カードマークなし
第2回山札52枚、カード4枚ドロー、数値1〜13、カードマークなし
第3回山札52枚、カード4枚ドロー、数値1〜13、カードマークあり
第4回山札52枚、カード5枚ドロー、数値1〜13、カードマークあり

今回は第3回なので、ついにカードのマークがついてきます。ということで、新規手役でフラッシュが作れます(まぁ4枚しかないのにフラッシュと呼ぶか否かは置いといて)。

カードに数値以外の属性(アトリビュート)を持たせるため、classを作っていきます。まぁ今回みたいな、属性2つくらいまででパターンもシンプルなものなら、リスト内にタプル持たせても全く問題はないのですが、一応練習がてらclass作ってやっていきます。

ゴール(役判定結果の表示)

こんな感じの内容がアウトプットされれば成功です(山札やドローが毎回変わりますので、どんなカードが配られるか、手役が何かは当然違いますが)

第3回 役判定してみよう(山札52枚、カード4枚ドロー、カードマークあり)

さて、第3回の前提条件はタイトルにあるように山札52枚、カード4枚ドロー、カードマークあり。第2回との違いはカードマークがあるところでしょう。

カードマークがあるので、フラッシュが追加されます。

  • 3カード
  • 4カード
  • フラッシュ
  • 1ペア
  • 2ペア
  • ブタ(high card)

さて、実際のコードは以下。

import random
from pprint import pprint


class card:
    def __init__(self, mark, num):
        self.num = num
        self.mark = mark


def pair_check(cards_num):
    card_multi = 0
    for s in set(cards_num):
        if card_multi < cards_num.count(s):
            card_multi = cards_num.count(s)
    return card_multi


def mark_check(cards_mark):
    mark_multi = 0
    for s in set(cards_mark):
        if mark_multi < cards_mark.count(s):
            mark_multi = cards_mark.count(s)
    return mark_multi


def check_roll(cards):
    hand = [card for card in cards]
    hand_nums = [c.num for c in hand]
    hand_marks = [c.mark for c in hand]

    if mark_check(hand_marks) == 4:
        return "flash!!"
    elif len(set(hand_nums)) == 3:
        return "1ペア"
    elif len(set(hand_nums)) == 2 and pair_check(hand_nums) == 3:
        return "3カード"
    elif len(set(hand_nums)) == 2 and pair_check(hand_nums) == 2:
        return "2ペア"
    elif len(set(hand_nums)) == 1:
        return "4カード"
    else:
        high = max(hand_nums)
        roll = "high card:{}".format(high)
        return roll


if __name__ == '__main__':
    bill = []
    marks = ('♣', '♦', '♥', '♠')

    bill = [card(k, j) for k in marks for j in range(1, 14)]
    random.shuffle(bill)


    hand = bill[:4]
    #同じコードが2回出てきているので、本来は手札表示関数を作って利用した方がいい
    hand_nums = [c.num for c in hand]
    hand_marks = [c.mark for c in hand]

    for i in range(len(hand_nums)):
        print("カード",i+1,":",hand_nums[i], hand_marks[i])
    print("手役:", check_roll(hand))

簡易コード解説

第1回からの変化点をメインに解説していきます。

手役判定

def check_roll(cards):
    hand = [card for card in cards]
    hand_nums = [c.num for c in hand]
    hand_marks = [c.mark for c in hand]

    if mark_check(hand_marks) == 4:
        return "flash!!"
    elif len(set(hand_nums)) == 3:
        return "1ペア"
    elif len(set(hand_nums)) == 2 and pair_check(hand_nums) == 3:
        return "3カード"
    elif len(set(hand_nums)) == 2 and pair_check(hand_nums) == 2:
        return "2ペア"
    elif len(set(hand_nums)) == 1:
        return "4カード"
    else:
        high = max(hand_nums)
        roll = "high card:{}".format(high)
        return roll

ついにカードマーク役のフラッシュが登場しました。と言っても、やってることは2ペア・3カード判定(第2回のテーマ)と同じで、マークの重複枚数を調べる関数を作成して、そこが4(全て重複)になった場合、フラッシュと判断するだけです。

def mark_check(cards_mark):
    mark_multi = 0
    for s in set(cards_mark):
        if mark_multi < cards_mark.count(s):
            mark_multi = cards_mark.count(s)
    return mark_multi

関数名と引数は変わっていますが、重複数値カード枚数をカウントするのと要は同じですね。

ちなみにですが、このような関数を使わなくとも、こんな方法でも処理可能です。

if len(set(hand_marks)) == 1:
        return "flash!!"

要は、ハンド内のカードマークについて、len(set())でとって、1であれば全部同じマークということですね。

少しだけClassを使ってみよう

class card:
    def __init__(self, mark, num):
        self.num = num
        self.mark = mark

非常にシンプルなクラスで、methodも何も保持させていませんが、初期化すると各オブジェクトに数値とマークを保持させるclassを作成しています。説明不要なほどシンプル。。

山札を作って手札を4枚ドローしよう

if __name__ == '__main__':
    bill = []
    marks = ('♣', '♦', '♥', '♠')

    bill = [card(k, j) for k in marks for j in range(1, 14)]
    random.shuffle(bill)


    hand = bill[:4]
    #同じコードが2回出てきているので、本来は手札表示関数を作って利用した方がいい
    hand_nums = [c.num for c in hand]
    hand_marks = [c.mark for c in hand]

    for i in range(len(hand_nums)):
        print("カード",i+1,":",hand_nums[i], hand_marks[i])
    print("手役:", check_roll(hand))

今までと同様山札を作って手札をドローするのですが、ここで山札を作る際にclass cardを利用しています。(bill = [card(k, j) for k in marks for j in range(1, 14)]の部分)

card classの第1引数がmarkなので、kのfor in の中では、marksを使用しています。まぁ別にrange(4)でもいいのですが、マークが0,1,2,3とかだと非常に味気なかったので。。

for i in range(len(hand_nums)):
        print("カード",i+1,":",hand_nums[i], hand_marks[i])

この部分はカード4枚の内容を確認するために、手札内容の表示をしているだけです。手札が何かわからないと、手役判定結果が正しいかもわかりにくいですしね。

まとめ

ついにカードマークが登場しました。フラッシュ、なかなか出ないんですよね。。

第4回はドローが5枚になりますので、ついにストレートおよびストレート関連役(ロイヤルストレートフラッシュ・ストレートフラッシュ)が発生します。ふと思うとこのシリーズ1人でポーカやっててつまんないので、もう1人足してどっちの手役が強いか戦い合わせてみようかなとも思います(第5回以降、やる気が続けば。。)。

ただ、次回は第4回をアップする前に、現状で発生する手役の種類別確率でも出してみたいなと思います。手役でないなぁと思う方も多いと思うので、5000回くらいの施行で、第3回までの条件でどんな手役がどの程度発生するのか、確認することもいいかと思いました(というか、単にwhile文使うステップ作れなかったので、足しただけなんですが。。)

Python
Advertisements
シェアする
ks_Accountingをフォローする
経営管理deプログラミング

コメント

  1. […] […]