HSP3 ゲームのプログラミング
 ポーカー・ゲーム制作 前へ 目次へ 次へ 

(7) 役判定

 カード解析処理で、解析結果が表の通り配列に格納される。役判定の処理ではこれらの配列を調べることになる。

配列 内容
hcnt(0)〜(14) 数字ごとの枚数
hnum(0)〜(4) 種類ごとの数字の並び(10進数)
hsn(0)〜(3) 種類ごとの数字の並び(2進数)
hnn(0)〜(3) 種類ごとの枚数
hsn(4) 数字の並び(2進数)

 判定した役は数値で得られるようにする。次の表のように、強い役の方が大きい数値になるようにする。

役名 役点数 カードの組合わせ
ファイブカード 1000 同じ数のカード4枚とジョーカー
ロイヤルストレートフラッシュ 900 5枚とも同じ種類で、10, J, Q, K, Aの連番
ストレートフラッシュ 800 5枚とも同じ種類で、5枚連番
フォーカード 700 同じ数のカードが4枚、残りの1枚は何でも良い
フルハウス 600 同じ数のカードが3枚と別のカードで同じ数のカード2枚
フラッシュ 500 5枚とも同じ種類
ストレート 400 種類はバラバラで、5枚連番
スリーカード 300 同じ数のカードが3枚、ほかの2枚は何でも良い
ツーペア 200 同じ数が2枚の組が2組、残りの1枚は何でも良い
ワンペア 100 同じ数が2枚の組が1組、残りの3枚は何でも良い
ノーペア 0 役なし

 表の役点数は基本になる点数である。例えば、2のワンペアと3のワンペアでは3のワンペアの方が勝ちであるが、両方とも100としたのでは勝敗が判定できない。役点数に役を構成するカードの数字を加算すると、2のワンペアは102、3のワンペアは103となり、103の方が大きいので3のワンペアの勝ちと判定できる。
 役の点は次のようになる。

◆ Kのワンペア … 113     ◆ Aのワンペア … 114
◆ 5, 6, 7, 8, 9のストレート … 409   ◆ 5, 6, 7, 8, 9のストレートフラッシュ … 809
◆ スペードのフラッシュ … 504   ◆ ハートのフラッシュ … 503
◆ ダイヤのフラッシュ … 502    ◆ クローバーのフラッシュ … 501



○ 同じ数字の枚数で役を構成

 役の判定処理は強い役から判定していき、その役ができていれば役の点数を変数yakuに格納してreturn命令で戻るようにする。
 一番強い役は、ファイブカードであるが、同じ数字の枚数で構成される役が次の6種類ある。これらは数字(A〜K)ごとの枚数が格納されている配列hcnt(0)〜(14)を調べて判定することになるので、まとめて判定することにする(hcnt(0)(1)は省略可)。

ファイブカード、 フォーカード、 フルハウス、 スリーカード、 ツーペア、 ワンペア
一つ目 二つ目 ジョーカーhnum(4)の有(1)無(0)
hcnt(cnt) = 2 (ワンペア) なし … ワンペア 有 … スリーカード 確定
無 … ワンペア 確定
hcnt(cnt) = 2 … ツーペア 有 … フルハウス 確定
無 … ツーペア 確定
hcnt(cnt) = 3 … フルハウス 確定
hcnt(cnt) = 3 (スリーカード) なし … スリーカード 有 … フォーカード 確定
無 … スリーカード 確定
hcnt(cnt) = 2 … フルハウス 確定
hcnt(cnt) = 4 (フォーカード) なし … フォーカード 有 … ファイブカード 確定
無 … フォーカード 確定

 次にプログラムリストを示す。カード解析の後に追加する。

    ;役判定
    ;1000ファイブカード:同じ数のカード4枚とジョーカー
    ;700フォーカード:同じ数のカードが4枚、残りの1枚は何でも良い
    ;600フルハウス:同じ数のカードが3枚と別のカードで同じ数のカード2枚
    ;300スリーカード:同じ数のカードが3枚、ほかの2枚は何でも良い
    ;200ツーペア:同じ数が2枚の組が2組、残りの1枚は何でも良い
    ;100ワンペア:同じ数が2枚の組が1組、残りの3枚は何でも良い
    yaku = 0    ;役の返却値
    repeat 15
        if yaku / 100 = 3 & hcnt(cnt) = 2 : yaku += 300 : break         ;フルハウス(スリー+ワン)
        if yaku / 100 = 1 & hcnt(cnt) = 3 : yaku = 600 + cnt : break    ;フルハウス(ワン+スリー)
        if yaku / 100 = 1 & hcnt(cnt) = 2 : yaku = 200 + cnt    ;ツーペア(ワン+ワン)
       if yaku = 0 & hcnt(cnt) = 2 : yaku = 100 + cnt    ;ワンペア
        if yaku = 0 & hcnt(cnt) = 3 : yaku = 300 + cnt    ;スリーカード
        if yaku = 0 & hcnt(cnt) = 4 : yaku = 700 + cnt    ;フォーカード
    loop
    if yaku / 100 = 7 & hnum(4) = 1 : yaku += 300    ;ファイブカード(フォー+Joker)
    if yaku / 100 = 3 & hnum(4) = 1 : yaku += 400    ;フォーカード(スリー+Joker)
    if yaku / 100 = 2 & hnum(4) = 1 : yaku += 400    ;フルハウス(ツー+Joker)
    if yaku / 100 = 1 & hnum(4) = 1 : yaku += 200    ;スリーカード(ワン+Joker)
    if yaku ! 0 : return
 ワンペアの場合、yaku = 100 + cnt としているが、役点数100にワンペアの数字cntを加算して役の点としている。これで、2のワンペアはyaku=102、3のワンペアはyaku=103となりyakuiを比較すれば勝敗が判定できる。
 条件式のyaku / 100は、yakuが整数型なので役点数の百の位以上の数が整数で得られ、どの役か判定することができる。例えば、2のワンペアも3のワンペアもyaku/100は1となり、ワンペアであることがわかる。
 繰り返しの中の判定文のグループの順序を変えると正しく役の点数が計算できなくなる。理由は考えてみよう。実際に試してみるのもよい。
    repeat 15
       if yaku / 100 = 3 & hcnt(cnt) = 2 : ……
        if yaku / 100 = 1 & hcnt(cnt) = 3 : ……
        if yaku / 100 = 1 & hcnt(cnt) = 2 : ……

        if yaku = 0 & hcnt(cnt) = 2 : ……
        if yaku = 0 & hcnt(cnt) = 3 : ……
        if yaku = 0 & hcnt(cnt) = 4 : ……
    loop
  →       repeat 15
        if yaku = 0 & hcnt(cnt) = 2 : ……
        if yaku = 0 & hcnt(cnt) = 3 : ……
        if yaku = 0 & hcnt(cnt) = 4 : ……

        if yaku / 100 = 3 & hcnt(cnt) = 2 : ……
        if yaku / 100 = 1 & hcnt(cnt) = 3 : ……
        if yaku / 100 = 1 & hcnt(cnt) = 2 : ……
    loop



○ 同じ種類と数字の並びで役を構成

 5枚すべてが同じ種類で連番であるときストレートフラッシュ、特に連番がAKQJ10のときはロイヤルストレートフラッシュと判定する。また、5枚すべてが同じ種類で連番になっていないときはフラッシュと判定する。さらに、ジョーカーが関係する。ただし、種類の違う連番はストレートであるが、別の判定とする。
 種類と並びで判定するので、配列hnum(0)〜(3)、hsn(0)〜(3)とhnn(0)〜(3)の値で判定する。

 配列hsnは各けた数が数字に対応する16文字で、数字のカードがあれば1、なければ0で表す。この2進数の文字列を10進数で格納しているのが配列hnumである。添字(0)はスペード、(1)はハート、(2)はダイヤ、(3)はクローバーである。
 配列hnnには種類ごとの枚数が格納されている。

 次にプログラムリストを示す。先の役判定の後に追加する。

    ;900ロイヤルストレートフラッシュ:5枚とも同じ種類で、10, J, Q, K, Aの連番"0111110000000000"
    ;800ストレートフラッシュ:5枚とも同じ種類で、5枚連番
    ;500フラッシュ:5枚とも同じ種類
    repeat 4    ;4種類
        ;ロイヤルストレートフラッシュ
        if hnum(cnt) = 31744 {    ;31744 = "0111110000000000"
            yaku = 900 + 4 - cnt
            break
        }
        ;joker & KQJ10 | AQJ10 | AKJ10 | AKQ10 | AKQJ
        if hnum(4) = 1 & (hnum(cnt) = 15360 | hnum(cnt) = 23552 | hnum(cnt) = 27648 | hnum(cnt) = 29696 | hnum(cnt) = 30720) {
            yaku = 900 + 4 - cnt
            break
        }
        ;ストレートフラッシュ
       if instr(hsn(cnt), 0, "11111") ! -1 {
           yaku = 800 + 4 - cnt
           break
       }
       ;joker & ストレートフラッシュ
       if hnum(4) = 1 & (instr(hsn(cnt), 0, "1111") ! -1 | instr(hsn(cnt), 0, "10111") ! -1 | instr(hsn(cnt), 0, "11011") ! -1 | instr(hsn(cnt), 0, "11101") ! -1) {
           yaku = 800 + 4 - cnt
           break
       }
        ;フラッシュ
        if hnn(cnt) = 5 | (hnum(4) = 1 & hnn(cnt) = 4) {
            yaku = 500 + 4 - cnt
            break
        }
    loop
    if yaku ! 0 : return
 役の点数計算でyaku = 900 + 4 - cnt としているのは、スペードはcnt=0、ハートはcnt=1、ダイヤはcnt=2、クローバーはcnt=3なのでスペードの点数が高くなるように「4-cnt」を役点数に加算している。
 ロイヤルストレートフラッシュの判定は、if hsn(cnt) = "0111110000000000"でもよい。
 ジョーカーの入ったロイヤルストレートフラッシュは、KQJ10、AQJ10、AKJ10、AKQ10、AKQJが該当する。1と0の並びとその10進数で表すと次のようになる。
  KQJ10 = "0011110000000000" = 15360
  AQJ10 = "0101110000000000" = 23552
  AKJ10 = "0110110000000000" = 27648
  AKQ10 = "0111010000000000" = 29636
  AKQJ = "0111100000000000" = 30720
 ストレートフラッシュは同じ種類の連番なので、"11111"がhsn(cnt)の中のどこかにあればよい。これを判定するのにinstr命令(関数)を使っている。「instr(hsn(cnt), 0, "11111")」は、hsn(cnt)の0けた目(先頭)から"11111"と同じ部分があるか検索する。あれば、左からのけた数が得られる。けた数は一番左を0と数える。ないときは-1が得られる。例えば、hsn(cnt)が"0000011111000000"のとき、instr(hsn(cnt), 0, "11111")で5が得られ、hsn(cnt)が"0000011101001000"のとき、instr(hsn(cnt), 0, "11111")で-1が得られる。



○ ストレート

 種類ごとの並びは配列hsn(0)〜(3)に格納されており、それらをまとめたものがhsn(4)に格納されている。次に例を示す。
  hsn(0) ="0000001000001000"
  hsn(1) ="0000000010000000"
  hsn(2) ="0000001000000000"
  hsn(3) ="0000000100000000"
  hsn(4) ="0000001110001000"
 ストレートは、連番であればよく、種類は関係しないので、hsn(4)だけを調べる。

 次にプログラムリストを示す。先の役判定の後に追加する。

    ;400ストレート:種類はバラバラで、5枚連番
    if instr(hsn(4), 0, "11111") ! -1 {
        yaku = 400 + 15 - instr(hsn(4), 0, "1")
    }
    ;joker & ストレート
    if hnum(4) = 1 & (instr(hsn(4), 0, "1111") ! -1 | instr(hsn(4), 0, "10111") ! -1 | instr(hsn(4), 0, "11011") ! -1 | instr(hsn(4), 0, "11101") ! -1) {
        yaku = 400 + 15 - instr(hsn(4), 0, "1")
    }
    if yaku ! 0 : return
 ストレートフラッシュはhsn(0)〜(3)の4種類を調べているが、このストレートはhsn(4)だけを調べればよい。判定文はほぼ同じである。



○ ノーペア

 ノーペアの場合の役の点数は5枚のカードの内、一番強いカード(スペードのA)が最も高い点数になるように決める。ただし、100を超えないようにする。方法としては、5枚のカードから最も小さい通番を探す。通番は一番強いカード(スペードのA)の0から始まって51番まであるので、「52-通番」の計算をすれば一番強いカードが最も高い点数になる。
 ここでは、別の方法てプログラムしている。並びから点数を計算する。リストを参照のこと。

 次にプログラムリストを示す。先の役判定の後に追加する。

    ;0ノーペア:役なし
    ;100ワンペア:+Joker
    repeat 4
        pr = instr(hsn(cnt), 0, "1")
        if pr ! -1 : yaku = cnt * 20 + pr : break
    loop
    yaku = 80 - yaku
    ;joker & ノーペア
    if hnum(4) = 1 : yaku = 100 + 15 - instr(hsn(4), 0, "1")    ;ワンペア
    return



課題(poker64.hsp)
 役判定のサブルーチンpoker_hanteiを完成する。

 サブルーチンの確認用プログラムとして、次の処理を追加する。確認がすんだら削除しておく。
    ;確認用プログラム
    oya = 1 : gosub *poker_hantei : test1 = yaku
    oya = 0 : gosub *poker_hantei : test2 = yaku
    dialog "親=" + test1 + "\nプ=" + test2
    goto *restart
;親のカード処理 -----
 実行して、賭点と交換するカードを決めると親とプレイヤーの役の点数がダイアログに表示される。点数から役を読みとってカードと比べてみる。
 例えば、役の点数が107なら7のワンペア、311ならJのスリーカードというように、百の位が役を表し、十と一の位がその役を構成する数字である。205は5のツーペアでもう一組のペアの数字はわからない(4以下であることはわかる)。また、役の点数が504ならスペードのフラッシュ、801ならクローバーのストレートフラッシュである。同じ種類で構成する役は一の位が種類である。4はスペード、3はハート、2はダイヤ、1はクローバーである。


(リスト)


 ポーカー・ゲーム制作 前へ 目次へ 次へ 
2007 © Hiroshi Masuda 

 

 

inserted by FC2 system