×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

ゲームを作ろう! ポーカーその3 役の判定


今回はポーカーの役の判定方法について考えてみます。
前回は、トランプのカード5枚をnumber[1]〜number[5]としました。
このnumber[1]というカードは、実際は数字の1から52の中のどれかです。
例えば、

number[1] = 2
number[2] = 15
number[3] = 51
number[4] = 39
number[5] = 1

こんな感じだったとして、ここから役をどう判定させましょうか。
ポーカーの役については、以下と、ド○クエのポーカーの役名を参考にしてみます。

ポーカー・ハンドの一覧 - Wikipedia

一番簡単そうな「ワンペア」あたりを考えてみましょう。
5枚のうち、2枚同じ数字があるのがワンペアです。
しかし、number[1]と同じ数字をnumber[2]〜number[5]から探す、という方法ではダメですね。
最初に決めた通り、

1〜13:ハートの1〜13
14〜26:ダイヤの1〜13
27〜39:クラブの1〜13
40〜52:スペードの1〜13

ですから、number[1]とは別に、「カードに記された数字」のみを別途計算しておくと良さそうです。
「カードに記された数字」は、「number[?]を13で割った余り」ですね。
ただ、これだと「カードに記された数字」が13の時、余りがゼロなので、これだけ分けて考える必要があります。

For i=1 To 5
  trumpnumber[i] = Math.Remainder(number[i], 13)
  If trumpnumber[i] = 0 Then
    trumpnumber[i] = 13
  EndIf
EndFor

これで、カードに記された数字「trumpnumber[?]」を計算できました。
後は、「number[1]とnumber[2]が同じ」「number[1]とnumber[3]が同じ」「number[1]とnumber[4]が同じ」……と分けて考えて、

  'ワンペア
  If trumpnumber[1] =trumpnumber[2] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[1] = trumpnumber[3] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[1] = trumpnumber[4] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[1] = trumpnumber[5] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[2] = trumpnumber[3] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[2] = trumpnumber[4] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[2] = trumpnumber[5] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[3] = trumpnumber[4] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[3] = trumpnumber[5] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  ElseIf trumpnumber[4] = trumpnumber[5] Then
    GraphicsWindow.DrawText(200, 240, "ワンペア!")
  Else
    GraphicsWindow.DrawText(200, 240, "負け……。")
  EndIf

これでワンペアの判断ができましたね。
同じ数字があることが条件の役「フォーカード」「フルハウス」「スリーカード」「ツーペア」あたりは、この応用で判断できそうですね。
なお、これら「フォーカード」「フルハウス」「スリーカード」「ツーペア」には必ず「ワンペア」が含まれています。
だから、「ワンペア」より先にこれら難しい役の判定を行う必要があります。

「ロイヤルストレートフラッシュ」「ストレートフラッシュ」「フラッシュ」「ストレート」はどうするか考えてみます。

「ロイヤルストレートフラッシュ」は、同じマークかつ「A」「10」「J」「Q」「K」が揃っているという役になります。
ここでの問題は、カードの順番です。
「A」「J」「Q」「K」「10」、「Q」「K」「10」「A」「J」、「10」「Q」「A」「K」「J」……と、順番が異なっていてもカードさえ含まれていればOKなのです。
これを解決する方法は色々とあるでしょうが、

・number[1]〜number[5]を「,」で区切りながらつなげて文章に変換する
・この変換した文章の中に目的の数字があるか検索して判定

という方法を使ってみます。

number[1] = 2
number[2] = 15
number[3] = 51
number[4] = 39
number[5] = 1

ならば、この時、

getnumber = "," + number[1] + "," + number[2] + "," + number[3] + "," + number[4] + "," + number[5]+ ","

このように、このプログラムにて、getnumber「,2,15,51,39,1,」という文章を得ることが出来ます。
Text.IsSubText(text, SubText)を使うと、「text」中に「SubText」が存在するかどうかを判定できますので、例えばハートのロイヤルストレートフラッシュなら、

If Text.IsSubText(getnumber, ",1,") And Text.IsSubText(getnumber, ",10,") And Text.IsSubText(getnumber, ",11,") And Text.IsSubText(getnumber, ",12,") And Text.IsSubText(getnumber, ",13,") Then
  GraphicsWindow.DrawText(200, 240, "ロイヤルストレートフラッシュ!")
EndIf

これで判定ができます。
この、getnumberを使った検索で「ロイヤルストレートフラッシュ」「ストレートフラッシュ」「ストレート」はどうにかできそうです。
「フラッシュ」は「5枚全てのマークが同じ」なので、また別の方法になりそうですから後にします。

「ストレートフラッシュ」「ストレート」の判定では、もう少し捻って考える必要がありそうです。
「ストレートフラッシュ」は同じマークかつ、5枚の数字が連続している、という条件です。
5枚の中で最も小さい数字を「minn」という定数に仮定すると、残り4枚は「minn + 1」「minn + 2」「minn + 3」「minn + 4」のはずです。
これで5枚全ての数字が判定できるので、後は「ロイヤルストレートフラッシュ」のように検索すれば良いはず。
ただ、「minn」の範囲は、例えばハートマークなら「1以上9以下」になります。5枚の中で最大の「minn + 4」の最大値が「13」だから逆算でわかります。

さて、5枚の中で最も小さい数字「minn」はどう求めるか?
これは、2つの値を比較して小さい数字を返してくれる、Math.Min(number1, number2)を使ってみます。
複数の値を比較してくれるオブジェクトがあればもっと楽なのですが……

'ストレートフラッシュ
min1_2 = Math.Min(number[1], number[2])
min3_4 = Math.Min(number[2], number[3])
min1_2_3_4 = Math.Min(min1_2, min3_4)
minn = Math.Min(min1_2_3_4, number[5]) 'Math.Minで5枚の数字を比較して最低値をminnとする

For i = 0 To 4
  min[i] = minn + i 'min[0]〜min[4]が、5枚の数字の最低値から連続した5つの数字
EndFor

If (1 <= min[0] And min[0] <= 9) Or (1+13 <= min[0] And min[0] <= 9+13) Or (1+13*2 <= min[0] And min[0] <= 9+13*2) Or (1+13*3 <= min[0] And min[0] <= 9+13*3) Then
  If Text.IsSubText(getnumber, ","+min[0]+",") And Text.IsSubText(getnumber, ","+min[1]+",") And Text.IsSubText(getnumber, ","+min[2]+",") And Text.IsSubText(getnumber, ","+min[3]+",") And Text.IsSubText(getnumber, ","+min[4]+",") Then
    GraphicsWindow.DrawText(200, 240, "ストレートフラッシュ!")
  EndIf
EndIf

「1 <= min[0] And min[0] <= 9」がハート、「1+13 <= min[0] And min[0] <= 9+13」がダイヤ……というマークの判定を行い、
次の「If Text.IsSubText(getnumber, ","+min[0]+",")……」が、検索している部分です。
「","+min[0]+","」という表記は、数字の区切りを考慮した記述になります。そうしないと「2を含む」の検索に、「2」だけじゃなくて「20」など「2を含む2桁の数」なんかも含まれてしまいます。「,2,」という文字を検索することで解決しているのです。

*「なら(getnumber, ,min[0],)でいいじゃん」、という訳にはいかないのです。プログラム的には「,」は文字列で、「min[0]」は数値です。Small Basicでは文字列を""で挟まないと認識しないというお約束があります。そして、文字列と数値をつなげて記述する時は、その間に「+」を入れなければなりません。

「ストレート」は「ストレートフラッシュ」の応用です。
ただし、「ストレート」はマークが異なっていても連続した数字ならOK、という判定になるので、getnumberではなく、トランプ自体に書かれた数字trumpnumberで判定しなければなりません。

getnumber2 = "," + trumpnumber[1] + "," + trumpnumber[2] + "," + trumpnumber[3] + "," + trumpnumber[4] + "," + trumpnumber[5]+ ","

こんな感じで「getnumber2」を用意しておいて、後は「ストレートフラッシュ」と似た手順になります。

最後に「フラッシュ」ですが、「5枚全てのマークが同じ」ですから、例えば「5枚全てのマークがハート」なら、

If 1 <= number[1] And number[1] <=13 And 1 <= number[2] And number[2] <=13 And 1 <= number[3] And number[3] <=13 And 1 <= number[4] And number[4] <=13 And 1 <= number[5] And number[5] <=13 Then
  GraphicsWindow.DrawText(200, 240, "フラッシュ!")
EndIf

全てのnumberが1から13までの間にある、とすればOKですね。

長くなりましたが、これで役の判定ができそうです。
次がラスト、これまでのプログラムをまとめてみましょう。

次:その4 プログラム全体を作る


▲TOPへ戻る