質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • Ruby

    7664questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

ポーカー:最も強い手札がどれか判断する

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 655

yuz55

score 3

前提・実現したいこと

先日、「入力した文字列が、ポーカーのどの役になっているか」を判断するコードに関する質問をしたものです。皆様のお助言のおかげで無事完成させることができました、ありがとうございます。
今度は、複数の手札の情報を入力したときに、それぞれの役名を表示したうえで、どの手札が一番強いかを判断するコードを書いています。

出力例:
card: "H1 H13 H12 H11 H10”,
hand: "Straight_Flush",
best: true

card: "H9 C9 S9 H2 C2”,
hand: "Fullhouse"

この時、「どの手札が一番強いか」を判断するのに、どうしたらよいのか分からず行き詰っています…。この点についてアドバイス頂けたら嬉しいです!
現在、自力で下にあげたコードまで書きました。上の例でいえば、それぞれの手札に対して、cardとhandを出力するところまでです。

該当のソースコード

#ポーカーの役を判定するアプリケーションをつくる。
#複数の五枚のカードの組の情報(例:S8 S7 H6 H5 S4, H1 H13 H12 H11 H10)を入力すると、それが何の役になっているのか判定したうえで、一番強い役がどれかを表示。


#役の配列をつくる。インデックスの大小で役の強弱を表す。
YAKU = ["High_Cards", "One_Pair", "Two_Pair", "Three_of_a_Kind", "Straight", "Flush", "Fullhouse", "Four_of_a_Kind", "Straight_Flush", "Royal_Straight_Flush"]


#役の判断。

def eval_hand
  puts "文字列を入力してください(例:S8 S7 H6 H5 S4, H1 H13 H12 H11 H10)"
  #カンマ(,)で文字列を分割し、いくつかの手札からなる配列を返す。
  hands = gets.split(",")

  hands.each do |h|
  #それそれのカードから、スートの部分だけ、数字の部分だけを取り出した配列を別に作る。
  hand = h.split
  suits = []
  numbers = []

  hand.each do |c|
    suits.push c[0]
    numbers.push c[1].to_i
  end

  case same_number_counts(numbers)
    when [2,1,1,1]
      yaku = YAKU[1]
    when [2,2,1]
      yaku = YAKU[2]
    when [3,1,1]
      yaku = YAKU[3]
    when [3,2]
      yaku = YAKU[6]
    when [4,1]
      yaku = YAKU[7]
    else
      case [straight(numbers), flush(suits)]
      when [true, false]
        yaku = YAKU[4]
      when [false, true]
        yaku = YAKU[5]
      when [true, true]
        if numbers == [1,10,11,12,13]
          yaku = YAKU[9]
        else
          yaku = YAKU[8]
        end
      else
        yaku = YAKU[0]
    end
    puts "card:#{h}\n\nhand:#{yaku}\n\n"
    end
  end
end


def same_number_counts(numbers)
  same_numbers = numbers.group_by{|r|r}.map(&:size).sort.reverse
end

def straight(numbers)
  steps = numbers.sort.map{|r|r - numbers[0]}
  steps == [0,1,2,3,4] || steps == [0,9,10,11,12]
end

def flush(suits)
  suits.uniq.size == 1
end

def end_program
  exit
end

def exception
  puts "入力された値は無効です"
end


#メニューの表示
while true do
  puts "[0]役を判定する"
  puts "[1]アプリを終了する"
  input = gets.to_i

  if input == 0 then
    eval_hand
    elsif input == 1 then
    end_program
    else
    exception
  end
end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

気の付いたバグだけ直しました。2つ目のバグはインデントがおかしいせいでしょうね。

--- old   2017-04-15 22:42:05.194114848 +0900
+++ new   2017-04-15 22:44:32.277113159 +0900
@@ -21,7 +21,7 @@

   hand.each do |c|
     suits.push c[0]
-    numbers.push c[1].to_i
+    numbers.push c[1..-1].to_i
   end

   case same_number_counts(numbers)
@@ -49,9 +49,9 @@
         end
       else
         yaku = YAKU[0]
+      end
     end
     puts "card:#{h}\n\nhand:#{yaku}\n\n"
-    end
   end
 end

@@ -60,8 +60,9 @@
   same_numbers = numbers.group_by{|r|r}.map(&:size).sort.reverse
 end

-def straight(numbers)
-  steps = numbers.sort.map{|r|r - numbers[0]}
+def straight(n)
+  numbers = n.sort
+  steps = numbers.map{|r|r - numbers[0]}
   steps == [0,1,2,3,4] || steps == [0,9,10,11,12]
 end

「どの手札が一番強いか」を判断するのに、どうしたらよいのか分からず行き詰っています…。

カンマで区切られた札の中での比較でいいんですよね。

def eval_hand
  puts "文字列を入力してください(例:S8 S7 H6 H5 S4, H1 H13 H12 H11 H10)"
  #カンマ(,)で文字列を分割し、いくつかの手札からなる配列を返す。
  hands = gets.chomp.split(",")
  scores = hands.map{|hand| score(hand)}
  high_score = scores.max
  puts "一番強いのは"
  scores.each.with_index do |sc,i|
    puts hands[i] if sc==high_score
  end
end
def score(hand)
  hand に対しての点数を数値で返す
end


同点があり得るので、複数の手が表示される事があります。
同じ役の中での強弱の判断はご存じでしょうか?
例:ワンペア⇒ペアのカードが強い方。ペアのカードが同じなら、残りのカードの中の最強のカードが強い方。それも同じならその次に強いカードが強い方。それも同じなら最後のカードが強い方。それも同じなら同点。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

やくに点数をつけてその大小を比較するというのはどうでしょうか?

#encoding: utf-8

=begin
ポーカーのやくはんていプログラム
=end

def PokerHand_Judge(array)
  return "NoPair" if array.length < 2

  mark = []
  num = []

  array.each do |element|
    mark << element.slice!(0)
    num << element.to_i
  end

  mark.uniq!

  tmp = num.group_by{|e| e}.map{|key, val| val}.map{|e| e.length}.sort

  case tmp
  when [1, 1, 1, 2]; return "OnePair"
  when [1, 2, 2]; return "TwoPair"
  when [1, 1, 3]; return "ThreeOfAKind"
  when [2, 3]; return "FullHouse"
  when [1, 4]; return "FourOfAKind"
  end

  return "NoPair" if array.length != 5

  straight = false
  royal = false

  min = num.min
  max = num.max

  if max - min <= 4
    straight = true
  end

  if straight == false
    min = 14 if num.min == 1
    if max - min <= 4
      straight = true
      royal = true
    end
  end

  flush = false

  if mark.length == 1
    flush = true
  end

  if royal && flush; return "RoyalStraightFlush"
  elsif straight && flush; return "StraightFlush"
  elsif flush; return "Flush"
  elsif straight; return "Straight"
  end

  return "NoPair"
end

def Score(str)
  case str
  when "RoyalStraightFlush"; return 0
  when "StraightFlush"; return 1
  when "FourOfAKind"; return 2
  when "FullHouse"; return 3
  when "Flush"; return 4
  when "Straight"; return 5
  when "ThreeOfAKind"; return 6
  when "TwoPair"; return 7
  when "OnePair"; return 8
  when "NoPair"; return 9
  end
end

str = "S8 S7 H6 H5 S4 H1 H13 H12 H11 H10\n"

cards = str.chomp.to_s.split("\s").each_slice(5).to_a

dis = []

cards.each do |element|
  dis << "cards:\s#{element.join(",")}"
  answer = PokerHand_Judge(element)
  dis << "hand:\s#{answer}"
  dis << Score(answer)
end

dis.each_slice(3).to_a.sort_by{|e| e[2]}.each_with_index do |element, i|
  puts element[0]
  puts element[1]
  if i.zero?
    puts "best: true"
  end
  puts ""
end


参考
ポーカーの役判定プログラム(C#)
私のコードは参考にしたページに書いてあるC#のコードをRubyで書き直しただけのものです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

フラッシュはスートによって強さが変わるし、ワンペアは数字によって強さが変わります。
役によって違う以上、場合分けするしかないでしょう。

まずは役自体の強さで比較し、同じだった場合にそれぞれの役の比較に移るという二段階で処理してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/15 23:30

    > フラッシュはスートによって強さが変わるし、

    それはローカルルールでしょうね。

    キャンセル

  • 2017/04/16 05:49

    なるほど。ローカルルールでないものというのはどこを見ればいいんでしょうか?

    キャンセル

  • 2017/04/16 11:50

    私はポーカーの入門書でアメリカカジノのルールを知りました。まあ、「アメリカカジノローカル」と言えば言えますが。
    すぐに見られる物だと、https://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%BC%E3%82%AB%E3%83%BC%E3%83%BB%E3%83%8F%E3%83%B3%E3%83%89%E3%81%AE%E4%B8%80%E8%A6%A7

    キャンセル

  • 2017/04/16 11:59

    ありがとうございます。確かに私の知っているルールはメジャーなものではないようですね。

    ただ、それを見るとストレートやストレートフラッシュの時だけ A の扱いが変わりますし、ローカルルールも、カジノや競技会で変わるのであれば、やはり最初から役によって場合分けするよう作るのがいいのではないかと思いました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7664questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。