ドロー・ポーカーの Ruby プログラム

ドロー・ポーカーの Ruby プログラム

以下は、Ruby によるドロー・ポーカーのプログラムの一例です。


#!/usr/bin/env ruby

BEGIN {
}

END {
}

class Stack
  #定数
  #なし

  #クラス変数
  #なし

  #クラスメソッド
  #なし

  #インスタンスメソッド
  def initialize(ndeck)
    #インスタンス変数
    @stack = Array.new#カードの山

    deck = Array.new#1 組 52 枚のカード

    0.upto(Card::IMAX - 1) do |i|
      deck.push(i)
    end

    0.upto(ndeck - 1) do
      deck.each do |x|
        @stack.push(x)
      end
    end
  end

  #カードを混ぜる
  def shuffle()
    if (RUBY_VERSION >= '1.8.7')
      @stack.shuffle!
    else
      @stack = @stack.sort_by{rand}
    end
  end

  def next()
    return(@stack.shift)
  end

  def size()
    return(@stack.size)
  end

  #アクセスメソッド(アクセサ)
  #なし
end

class Card
  #定数
  IMAX  = 52#1 組 52 枚のカード
  SUITS = [ #カードの印
    'S',#spade
    'H',#heart
    'D',#diamond
    'C' #club
  ]

  #クラス変数
  #なし

  #クラスメソッド
  def self.suit(card)
    return((card % IMAX) / 13)
  end

  def self.number(card)
    return((card % IMAX) % 13)
  end

  #インスタンスメソッド
  #なし

  #アクセスメソッド(アクセサ)
  #なし
end

class Game#トランプゲーム
  #定数
  NDECK = 1

  #クラス変数
  #なし

  #クラスメソッド
  #トランプゲームを行う
  def self.run(stack)
    #カードを混ぜる
    stack.shuffle()
  end

  #カードを画面に表示する
  def self.display(player, pre = '', post = '', from = 0, to = player.size - 1)
    STDERR.print pre
    from.upto(to) do |i|
      STDERR.printf "%s%02d", Card::SUITS[Card.suit(player[i])], Card.number(player[i]) + 1
      STDERR.print  ", " if (i != to)
    end
    STDERR.print post, "\n"
  end

  #インスタンスメソッド
  #なし

  #アクセスメソッド(アクセサ)
  #なし
end

class Poker < Game#ポーカーはトランプゲームのサブクラス
  #定数
  HANDS = [#役の種類
    'No Pair',
    'One Pair',
    'Two Pair',
    'Three of a Kind',
    'Straight',
    'Flush',
    'Full House',
    'Four of a Kind',
    'Straight Flush',
    'Royal Straight Flush'
  ]

  #クラス変数
  #なし

  #クラスメソッド
  #役を確認する
  def self.check(player)
    npair = 0                             #ペアの数
    s     = Array.new(Card::SUITS.size, 0)#印毎の枚数
    n     = Array.new(13,               0)#数字毎の枚数
    flag  = Hash.new                      #確認フラグ

    player.each do |x|
      #番号をカードに換算し、印と数字の枚数を追加する
      s[Card.suit  (x)] += 1
      n[Card.number(x)] += 1
    end

    #フラッシュ系
    flag['flush'] = flush?(player, s)#フラッシュの確認フラグ

    #ストレート系
    0.upto(9) do |i|#ストレートの低位の数字は 1 から 10 まで
      if (straight?(player, i, n))
        if (flag['flush'])
          if (i == 9)
            return(9)#ロイヤル・ストレート・フラッシュ
          else
            return(8)#ストレート・フラッシュ
          end
        else
          return(4)#ストレート
        end
        break
      end
    end
    return(5) if (flag['flush'])#フラッシュ

    #ペア系
    flag['three'] = false#スリーカードの確認フラグ
    0.upto(12) do |i|
      if    (n[i] == 4)
        return(7)#フォーカード
      elsif (n[i] == 3)
        flag['three'] = true
      elsif (n[i] == 2)
        npair += 1
      end
    end
    if (flag['three'])
      if (npair == 1)
        return(6)#フルハウス
      else
        return(3)#スリーカード
      end
    else
      if    (npair == 2)
        return(2)#ツーペア
      elsif (npair == 1)
        return(1)#ワンペア
      end
    end
    return(0)#ノーペア
  end

  def self.flush?(player, s)
    0.upto(s.size - 1) do |i|
      return(true) if (s[i] == player.size)
    end
    return(false)
  end

  def self.straight?(player, i, n)
    0.upto(player.size - 1) do |j|
      return(false) if (n[(i + j) % 13] != 1)#13 は 1 と連なる
    end
    return(true)
  end

  #インスタンスメソッド
  #なし

  #アクセスメソッド(アクセサ)
  #なし
end

class Draw < Poker#ドロー・ポーカーはポーカーのサブクラス
  #定数
  NDECK = 1#実際のカジノでは、6 デックを 1 スタックとすることが多い
           #(ブラックジャックの場合)
  M     = 5#手札の枚数
  N     = 5#交換可能な枚数

  #クラス変数
  #なし

  #クラスメソッド
  #ドロー・ポーカーを行う
  def self.run()
    stack  = Stack.new(NDECK)#カードの山
    player = Array.new       #プレーヤーの手札

    super(stack)

    #カードを配る
    0.upto(M - 1) do
      player.push(stack.next())
    end

    #カードを画面に表示する
    display(player)

    #カードを交換する
    change(player, stack)

    #カードを画面に表示する
    display(player)

    #役を確認する
    STDERR.printf "%s\n", HANDS[check(player)]
  end

  #カードを交換する
  def self.change(player, stack)
    nflag = 0                            #真の flag の数
    flag  = Array.new(player.size, false)#カードの交換フラグ

    #交換するカードを決定する
    loop do
      STDERR.print "Please select the card(s) you want to change (1 - 5). "
      STDERR.print "To finish, input 0.\n"
      i = gets.chomp

      if    (i =~ /^[1-M]$/)
        if (flag[i.to_i - 1])
          next
        else
          flag[i.to_i - 1] = true
        end

        nflag += 1
        break if (nflag == N)
#      elsif (i =~ /^0$/)
      elsif (i == '0')#正規表現より処理が早い
        break
      else
        STDERR.print "Input Error!\n"
      end
    end

    #カードを交換する
    0.upto(player.size - 1) do |i|
      player[i] = stack.next() if (flag[i])
    end
  end

  #インスタンスメソッド
  #なし

  #アクセスメソッド(アクセサ)
  #なし
end

#関数的メソッド
#なし

#トップレベル

#定数
#なし

#グローバル変数
#なし

#ローカル変数
#なし

Draw.run()

exit(0)#正常終了

各クラスや各メソッドについて、以下に説明します。