ポーカー

 

流れは以下の通りです。

1.回数と手札が表示される

2.交換するのカード番号を入力

3.交換後の手札が表示される

4.完成した役が表示表示される

5.1から繰り返し(終了はカード番号で99を入力)

 

-ソース------------------------------------------------------

# ポーカー

import random as rnd

 

#カードデータを内部で扱いやすくするために3桁の数値で表現する

#100の位を0~3とし、それぞれ、S(スペード)、H(ハート)、D(ダイヤ)、C(クラブ)とする

#下2桁を1~13とし、1~13をA23456789TJQKとする

#例:スペードのQ:表示=S-Q、内部データ=12、ハートのA:表示=H-A、内部データ=101

#ジョーカーは表示=Joker、内部データ=400

#カードの枚数は52枚+ジョーカーの枚数

#カードの交換はカード番号を続けて入力する(1番と4番を交換する場合は「14」と入力する)

#カード交換不要の場合は何も入力せずEnterキー押下

 

Mark=["S-","H-","D-","C-","Joker"]

Numb=["","A","2","3","4","5","6","7","8","9","T","J","Q","K"]

Yaku=["ブタ","ワンペアー","ツーペアー","スリーカード","ストレート","フラッシュ","フルハウス"

      ,"フォーカード","ストレートフラッシュ","ロイヤルストレートフラッシュ"

      ,"ファイブカード","オールジョーカー"]

 

#役判定関数

def Fivecard(Ncnt):

    #数の種類が0 ※全てジョーカー

    if Ncnt==0:

        return 11

    #数の種類が1

    elif Ncnt==1:

        return 10

   

def RoyStraflush(Mcnt,Ncnt,Nwk):

    #マークの種類が1&数が全て違う値

    if Mcnt==1 and Ncnt==len(Nwk):

        #ロイヤル判定

        if Roychk(Nwk)==0:

            return 9

 

def Straflush(Mcnt,Ncnt,Nwk):

    #マークの種類が1&数が全て違う値

    if Mcnt==1 and Ncnt==len(Nwk):

        #数がストレート範囲内

        if Strahanichk(Nwk)==0:

            return 8

 

def Fourcard(Ncnt,Nwk):

    #数が2種類

    if Ncnt==2:

        #数の最初か最後の個数が1

        if Nwk.count(Nwk[0])==1 or Nwk.count(Nwk[len(Nwk)-1])==1:

            return 7

 

def Fullhouse(Ncnt):

    #数が2種類 ※フォーカードの形は判定済み

    if Ncnt==2:

        return 6

 

def Flush(Mcnt):

    #マークが1種類

    if Mcnt==1:

        return 5

 

def Stra(Ncnt,Nwk):

    #数が全て違う値

    if Ncnt==len(Nwk):

        #数がストレート範囲内orロイヤル

        if Strahanichk(Nwk)==0 or Roychk(Nwk)==0:

            return 4

 

def Threecard(Ncnt,Nwk):

    #数が3種類

    if Ncnt==3:

        #個数=1が2種類以上

        cnt=0

        for i in set(Nwk):

            if Nwk.count(i)==1:

                cnt+=1

        if cnt>=2:

            return 3

 

def Twop(Ncnt,Nwk):

    #数が3種類

    if Ncnt==3:

        #個数=1が1種類

        cnt=0

        for i in set(Nwk):

            if Nwk.count(i)==1:

                cnt+=1

        if cnt==1:

            return 2

 

def Onep(Ncnt):

    #数が4種類

    if Ncnt==4:

        return 1

   

def Roychk(Nwk):

    #ロイヤルの数のみ

    chk=[1,10,11,12,13]

    for i in Nwk:

        if i not in chk:

            return None

    return 0    

 

def Strahanichk(Nwk):

    #数の最大-最小が5未満

    if Nwk[len(Nwk)-1]-Nwk[0]<5:

        return 0    

 

#Joker枚数指定

jcnt=2

 

#プレイ回数カウンター

kaisu=0

 

while True:

    #山札作成

    l=[]

    for j in range(4):

        for i in range(13):

            l.append((j)*100+(i+1))

    for j in range(jcnt):

        l.append(400)

    rnd.shuffle(l)

       

    #手札を5枚配る

    Te=[]

    Teoutput=""

    for i in range(5):

        Te.append(l[i])

        Teoutput+=str(i+1)+":"+Mark[Te[i]//100]+Numb[Te[i]%100]+" "

    kaisu+=1

    print("-- "+str(kaisu)+" 回目 --")

    print(Teoutput)

 

    #交換するカード番号を入力

    print("交換するカード番号を入力してください(終了は99を入力)")

    inp=input()

    if inp=="99":

        print("終了します")

        break

 

    if len(inp)>0:

        print(str(len(inp))+" 枚交換します")

        for i in range(len(inp)):

            Te[int(inp[i])-1]=l[5+i]

 

    #交換後の手札を表示

    Teoutput=""

    for i in range(5):

        Teoutput+=str(i+1)+":"+Mark[Te[i]//100]+Numb[Te[i]%100]+" "

    print(Teoutput)

 

    #役判定準備

    #手札からジョーカーを外し、マークと数にバラして数は昇順ソートする

    Mwk=[]

    Nwk=[]

    for i in Te:

        if i!=400:

            Mwk.append(i//100)

            Nwk.append(i%100)

        Nwk.sort()

 

    #マークと数の種類を求める

    Mcnt=len(set(Mwk))

    Ncnt=len(set(Nwk))

 

    #役判定

    r=None

    r=Fivecard(Ncnt)

    if r==None:

        r=RoyStraflush(Mcnt,Ncnt,Nwk)

    if r==None:

        r=Straflush(Mcnt,Ncnt,Nwk)

    if r==None:

        r=Fourcard(Ncnt,Nwk)

    if r==None:

        r=Fullhouse(Ncnt)

    if r==None:

        r=Flush(Mcnt)

    if r==None:

        r=Stra(Ncnt,Nwk)

    if r==None:

        r=Threecard(Ncnt,Nwk)

    if r==None:

        r=Twop(Ncnt,Nwk)

    if r==None:

        r=Onep(Ncnt)

    if r==None:

        r=0

 

    #役表示

    print(Yaku[r])

    print("")

-------------------------------------------------------

 

初心者視点で一番難易度が高いのは役判定の部分だと思われます。

 

ポーカーの役には「複数の条件」を同時に満たすことで、より高位の役として扱う場合が複数あります。この様な場合は役の要素をバラして考えると割と単純な判定で済みます。

 

・マークは「全て同じ」以外にマーク関連の役は付きません。

 

・ロイヤルストレート(A,10,J,Q,K)はストレート(A~Kの間で5枚続き)とは別に考えると簡単になります。

 

・同じ数が複数枚必要な役は仲間外れ側をチェックする(例:フォーカードなら1枚仲間外れ)方がジョーカーの考慮を外せるので簡単になります。

 

・上位の役から順に判定することで、同一条件を持つ下位の役を判定せずに役を確定出来ます。

 

今回は手札からジョーカーを排除して役判定出来る様にしました。

但し、ジョーカーの枚数を5枚以上に設定して手が全てジョーカーになった場合、役がファイブカードだと味気ないので「オールジョーカー」という特別な役名が表示されるようにしました。

 

なんとなくですが、役判定の部分はもっと上手く作れそうな気がします。

 

-実行結果------------------------------------------------------

-- 1 回目 --
1:S-A 2:H-A 3:H-2 4:S-5 5:D-8 
交換するカード番号を入力してください(終了は99を入力)
345
3 枚交換します
1:S-A 2:H-A 3:D-5 4:D-4 5:C-3
ワンペアー

-- 2 回目 --
1:H-8 2:S-3 3:H-Q 4:H-5 5:S-J
交換するカード番号を入力してください(終了は99を入力)
134
3 枚交換します
1:C-A 2:S-3 3:Joker 4:C-T 5:S-J
ワンペアー

 

…………………………………………

…… こんな感じで繰り返します ……

…………………………………………

 

-- 7 回目 --
1:S-Q 2:S-J 3:C-Q 4:C-9 5:C-4
交換するカード番号を入力してください(終了は99を入力)
245
3 枚交換します
1:S-Q 2:H-3 3:C-Q 4:H-A 5:S-2
ワンペアー

-- 8 回目 --
1:H-8 2:H-K 3:C-K 4:H-2 5:S-A
交換するカード番号を入力してください(終了は99を入力)
145
3 枚交換します
1:Joker 2:H-K 3:C-K 4:H-6 5:Joker
フォーカード

-- 9 回目 --
1:S-A 2:C-9 3:H-6 4:S-3 5:S-Q
交換するカード番号を入力してください(終了は99を入力)
99
終了します

-------------------------------------------------------

 

役が成立した場合に掛け金に応じた倍率で配当がもらえる様にしたり、ダブルアップで配当を更に増やせるゲームを追加すると面白いかも知れません。

 

ただそれだと常に持ち金を全額掛けてダブルアップを降りるタイミングを見極めるだけのゲームになりそうな気がするので止めておきます。

 

以上です。