paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

スリーカードポーカーゲームを作りたい シミュレータ作る編

細かい修正はあるものの前回の記事でゲーム作成は一段落しました。
しかしユニットテストの作成まではこのシリーズとして続けたいと思います。


プログラミングでやってみたかった事の1つはシミュレータの作成です。
疑似ではあるもののとても現実的ではない試行回数でのデータが取れます。

という訳でスリーカードポーカーのシミュレータを作ります。

やりたいこと

勝負を指定回数行い以下の統計を出します。

  • プレーヤーの勝率
  • 手役の確率

コード

試行回数は多いほうがデータの信憑性が増えますので50万回まわしてみます。
本体のコードはゲームとして作ったのでシミュレータコードは別ファイルで作ります。

本体のファイルからクラスをインポートして、ディーラーとの勝負まで似たようなコードを書いて計算処理を書くだけです。
クラスを使いまわせてすごく楽ちんで便利です。
これがオブジェクト指向かー。

  • simulater.py
import pokerapp
import collections

match_list = []
hand_list = []

trial = 500000

def Trials():
    for _ in range(trial):

        deck = pokerapp.Deck()
        deck.shuffle()

        player = pokerapp.Handout(deck)
        dealer = pokerapp.Handout(deck)

        match_result = pokerapp.Match(player, dealer)
        hand_result = pokerapp.Handcheck(player).get_role()[0][0]
        
        match_list.append(match_result)
        hand_list.append(hand_result)

def Wins():
    for w in collections.Counter(match_list).items():
        if w[0] == 0:
            print('Player {} wins.'.format(w[1]))
        else:
            print('Dealer {} wins.'.format(w[1]))

def Hands():

    # Sort percntages in descending order
    hand_dict = collections.Counter(hand_list)
    sorted_hand_dict = sorted(hand_dict.items(), key=lambda x:x[1], reverse=True)

    for hand, prob in sorted_hand_dict:
        # Convert to str to use rjust
        p  = str(round((prob / trial) * 100, 3))

        shaped_hand = hand.ljust(16)
        shaped_propotion = (p + '%').rjust(10)

        print(shaped_hand, shaped_propotion)

def main():

    print('Three card poker simulator start.')
    print('The simulator trials {} times.'.format(trial))

    Trials()

    print('\n=== Probabliry of winning or losing ===\n')

    Wins()

    print('\n=== Percentage of Players hands ===\n')
    
    Hands()

if __name__ == '__main__':
    main()

動かすとこんな感じ

せっかくなので時間も測りましょう。

サブ機のubuntuで作っているのですが、古いマシンなので低スペックです。

CPU: Corei5-2400
メモリ: 4GB

ですw

f:id:paloma69:20200509111830p:plain

  • 実行

50万回のテストで32秒かかりました。
回数に対して遅い…のか?相場がわかりませんw

でも実際のカードやGTA内で検証するより遥かに早いスピードです。

masashi@PC-ubuntu:~/Three-card-poker$ time python3 simulater.py 
Three card poker simulator start.
The simulator trials 500000 times.

=== Probabliry of winning or losing ===

Dealer 249505 wins.
Player 250495 wins.

=== Percentage of Players hands ===

High card!          74.657%
One Pair!           16.926%
Flash!               5.008%
Straight!            2.971%
Three of a kind!     0.249%
Straight Flash!      0.188%

real    0m32.916s
user    0m32.904s
sys 0m0.012s

結果を分析

分析なんて大層な物ではないですが、結果を見てみましょう。

  • 勝率
Dealer 249505 wins.
Player 250495 wins.

勝率は大体5分ですね。
手札は運任せなので大勝ちはできませんね。

本体の勝敗判定をもう少し細かくすればちゃんとしか結果が出そうです。
同役の場合一番高いカードの番号しか見ていないので、3枚目まで見て判定すればちゃんとした勝敗が出ます。

  • 役の分布

試行回数の中で出た役が高い順にソートしてます。
上手くできたもので配当(ペアプラスボーナス)の低い順になってますね。

手役はほとんどハイカードです。
3枚のポーカーと言えど中々揃いません。
スリーカード、ストレートフラッシュはこのゲームでもレアモノですね。

High card!          74.657%
One Pair!           16.926%
Flash!               5.008%
Straight!            2.971%
Three of a kind!     0.249%
Straight Flash!      0.188%

勝ったパターンのみの手役統計を出せばより良かったかもしれません。

チップを賭けていたらどうなるのか

スリーカードポーカーはペアプラスボーナスとアンティボーナスの払い戻しがベットとは別に返ってきますが、チップの賭け方まで意識して計算したらどうなるのでしょうか?

カジノのゲームとして考えるとゲームの勝敗よりチップを増やすのが本質なので、どう賭けたらチップを増やして帰れるのかというのが見えるかもしれません。

と考えたところで今回はここまでしか作成していないので、また続きは次回以降にしたいと思います。