python練習問題〜シリーズ1第7回、レベル超初級の初級6延長戦〜

Python

前回のおさらい

さて、前回は延長戦第2回となる、仮想プレーヤー2名での対戦でした。

playerクラスの設定や、手役ランクを設定して強弱判定などしていきました。

ただ、最後まとめで書いたように、ポーカなのに同一手役だとドローとなってしまっていました。
これは流石に微妙ですよね、同一手役の場合に、カードのハイスコアで勝敗を判断できるようにしてきたいと思います。

連載回数実施内容
第5回ドロー5枚で手役の発生確率を計算してみよう
第6回コードが汚い、さぁリファクタリングだ
〜初心者でも最低限やれるリファクタリング〜
第7回仮想プレーヤーと対戦してみよう

さぁ簡易対戦機能作成の最終回いってみたいと思います。

ゴールイメージ

ハイカードでも勝敗がつきました

ハイカードでも勝敗結果を表示できるようになりました。単純に手役ランクで勝利した場合、win:plyaerNameで結果表示していましたが、ハイカード勝利の場合、win_as_high: playerNameとして表示されるようにしています。サンプルではAのハイカードでplayer1が勝利していますね。

実際のコード

それでは実際のコードをみていきましょう。

mport random
import poker_hand_check4card_mark as pkg

class player:
    def __init__(self, hand):
        self._hand = hand

    def hand_result(self):
        return list(check_roll(self._hand).values())


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


def straight_check(hand_nums):
    #ストレートの判定

    #1がある場合だけ、14とみなしてストレート判定(数値跨ぎ想定)
    if 1 in hand_nums and 10 in hand_nums:
        hand_nums.remove(1)
        hand_nums.append(14)

    #最大値と最小値の差が4になる、平均値の±1の値のカードが含まれる
    max_num = max(hand_nums)
    min_num = min(hand_nums)
    ave_num = (max_num + min_num) / 2

    if max_num - min_num == 4 and ave_num in hand_nums and ave_num - 1 in hand_nums and ave_num + 1 in hand_nums:
        return True

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]

    max_num = max(hand_nums)

    if pkg.mark_check(hand_marks) == 5 and straight_check(hand_nums) != True:
        return {"flash!!": 6}
    elif len(set(hand_nums)) == 4 and pkg.pair_check(hand_nums) == 2:
        return {"1ペア": 2}
    elif len(set(hand_nums)) == 3 and pkg.pair_check(hand_nums) == 3:
        return {"3カード": 4}
    elif len(set(hand_nums)) == 3 and pkg.pair_check(hand_nums) == 2:
        return {"2ペア": 3}
    elif len(set(hand_nums)) == 2 and pkg.pair_check(hand_nums) == 4:
        return {"4カード": 8}
    elif straight_check(hand_nums) and pkg.mark_check(hand_marks) != 5:
        return {"Straight!!": 5}
    elif len(set(hand_nums)) == 2 and pkg.pair_check(hand_nums) == 3:
        return {"フルハウス": 7}
    elif straight_check(hand_nums) and pkg.mark_check(hand_marks) == 5:
        if 1 in hand_nums and 10 in hand_nums:
            return {"ロイヤルストレートフラッシュ": 10}
        else:
            return {"ストレートフラッシュ": 9}
    else:
        high = max(hand_nums)
        roll = "high card:{}".format(high)
        return {roll: 1}

def battle(player1, player2, hand, hand2, *args, **kwargs):

    if player1 > player2:
        return "win: player1"
    elif player1 < player2:
        return "win:player2"
    else:
        return max_num_battle(hand, hand2)

def max_num_battle(hand, hand2):
    max_hand = max([c.num for c in hand])
    max_hand2 = max([c.num for c in hand2])

    if max_hand > max_hand2:
        return "win_as_high: player1"
    elif max_hand < max_hand2:
        return "win_as_high: player2"
    elif max_hand == max_hand2:
        return "draw"
    else:
        return "something error"

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

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


    hand = bill[:5]
    hand2 = bill[6:11]

    ##playerを2人作りハンドの強さ(dict_value)を取得
    player1 = player(hand).hand_result()
    player2 = player(hand2).hand_result()

    ##手役強弱結果表示
    result = battle(player1=player1, player2=player2, hand=hand, hand2=hand2)

    print(result)

    ##表示用データ作成
    hand_nums = [c.num for c in hand]
    hand_marks = [c.mark for c in hand]

    hand_nums2 = [c.num for c in hand2]
    hand_marks2 = [c.mark for c in hand2]

    ##手札表示
    print("player1手札")
    print("-"*20)
    for i in range(len(hand_nums)):
        print("カード",i+1,":",hand_nums[i], hand_marks[i])
    print("手役:", check_roll(hand).keys())

    print("player2手札")
    print("-" * 20)
    for i in range(len(hand_nums2)):
        print("カード", i + 1, ":", hand_nums2[i], hand_marks2[i])
    print("手役:", check_roll(hand2).keys())

表示機能も含めて130行ぐらいになり、だいぶ長くなってきましたね。ただ、これまでひとつづつ積み上げてきたコードの累積なので、ほとんどみたことあるコードだと思います。

さて、いつもと同様変更点を中心に少し紹介します。

手役ランク勝負で引き分け時の対応を変えよう

さて、前回作成したbattle関数ですが、今回もここの変更からです。前回と比較しながらみていくとわかりやすいかと思いますので、参考に前回コードも載せておきます。

変更点は黄色マーカ部分です。これまでは手役結果だけで判断できたので、battle関数の引数は各プレーヤの手役ランクだけ引き渡していましたが、今回は追加でハイカードの大小も検証する必要があるため、同一関数ないに無理やり双方プレーヤのハンド情報を引数で渡しています。

【今回のコード】

def battle(player1, player2, hand, hand2, *args, **kwargs):

    if player1 > player2:
        return "win: player1"
    elif player1 < player2:
        return "win:player2"
    else:
        return max_num_battle(hand, hand2)

【前回のコード】

def battle(player1, player2, *args, **kwargs):

    if player1 > player2:
        return "win: player1"
    elif player1 < player2:
        return "win:player2"
    else:
        return "draw"

ハイカードの大小を検証するmax_num_battle関数の作成

手役ランクがドローだった場合に動作する、max_num_battle関数です。battle関数の最後に、battle関数で引数に渡されたhand/hand2の値を利用して検討していきます。hand/hand2にはobjが入ってくることを想定して、最初に各引数をリスト化して、最大値を取得しています。

その他は、普通の大小比較ですので、特段難しいことはないですかね。

def max_num_battle(hand, hand2):
    max_hand = max([c.num for c in hand])
    max_hand2 = max([c.num for c in hand2])

    if max_hand > max_hand2:
        return "win_as_high: player1"
    elif max_hand < max_hand2:
        return "win_as_high: player2"
    elif max_hand == max_hand2:
        return "draw"
    else:
        return "something error"

main関数内で、battleに渡す値を変えよう

##手役強弱結果表示
    result = battle(player1=player1, player2=player2, hand=hand, hand2=hand2)

さて、引数が4つになって順番等はよくわからなくなってくる頃ですね。ということで、名前付きで引数を渡す形にしてみましょう。何が変わったかは、前回のコードと比較するとわかりやすいですね。

黄色のアンダーライン部分が引数に渡す際の名前としてのplayer/player2...となっています。他方で、赤色のアンダーライン部分が実際の引数で前回も利用したものになります。前回と今回で同一部分が赤色アンダーラインになりますので、イメージしやすいかと思います。

【前回のコード】

##手役強弱結果表示
    result = battle(player1, player2)
    print(result)

まとめ

さぁやっと仮想対戦が成り立つレベルまできました。みなさん本当にお疲れ様でした。

後は、暇な時にリファクタリング題材として、再度poker課題がお目見えすることになりますが、基本機能としては一旦ここまでで打ち止めにします。

超初級題材としては、最低限のレベルの問題だったかなと思います。ノンプロ研のpython初級コース入る前にやってみるにはちょうどいい(?)くらいな、と勝手に思って作ってましたが、実際はどうですかねw

興味がある方は、是非ノンプロ研にもご参加お待ちしております(回し者ではありませんし、一切リターンも入ってきませんw 私も単なる課金勢ですのでw)

ノンプログラマーのためのスキルアップ研究会【月額】
ノンプログラマーがプログラミングなどのスキルを身に着ける支援をするコミュニティ「ノンプログラマーのためのスキルアップ研究会」に参加をすることができます。 職場や周囲にスキルを上げ続けるための環境や仲間に恵まれないノンプログラマー向けに定期的に集まり、コミュニケーションをとり、学び合う場を提供しています。 「教えても...
Python
Advertisements
シェアする
ks_Accountingをフォローする
経営管理deプログラミング

コメント