ブラックジャックの Ruby プログラム

ブラックジャックの Ruby プログラム

以下は、Ruby によるブラックジャックのプログラムの一例です。


#!/usr/bin/env ruby

BEGIN {
}

END {
}

class Stack
  #定数
  #なし

  #クラス変数
  #なし

  #クラスメソッド
  #なし

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

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

    for s in ['S', 'H', 'D', 'C']#spade, heart, diamond, club
      1.upto(9) do |n|
        deck.push(s + 0.to_s + n.to_s)
      end
      10.upto(13) do |n|
        deck.push(s +          n.to_s)
      end
    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
  #定数
  #なし

  #クラス変数
  #なし

  #クラスメソッド
  def self.suit(card)
    #「アルファベットと数字」のアルファベットを取出す
    card =~ /^([SHDC])(\d{1,2})$/#選択 S|H|D|C は遅い
    return($1)
  end

  def self.number(card)
    #「アルファベットと数字」の数字を取出す
    card =~ /^([SHDC])(\d{1,2})$/#選択 S|H|D|C は遅い
    return($2)
  end

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

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

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

  #クラス変数
  #なし

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

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

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

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

class Blackjack < Game#ブラックジャックはトランプゲームのサブクラス
  #定数
  NDECK = 1#実際のカジノでは、6 デックを 1 スタックとすることが多い
           #(ブラックジャックの場合)

  #クラス変数
  #なし

  #クラスメソッド
  #ブラックジャックを行う
  def self.run()
    nround      = 0               #ラウンド数
    playerPoint = 0               #プレーヤーの合計点数
    dealerPoint = 0               #ディーラーの合計点数
    playerHands = Array.new       #プレーヤーの手札
    dealerHands = Array.new       #ディーラーの手札
    stack       = Stack.new(NDECK)#カードの山

    super(stack)

    while (stack.size() > 10) do
      playerHands.clear
      dealerHands.clear

      nround += 1
      STDERR.printf "--- Round %d ---\n", nround

      #カードを配る
      0.upto(1) do
        playerHands.push(stack.next())
        dealerHands.push(stack.next())
      end

      #合計点数を計算する
      playerPoint = calc(playerHands)
      dealerPoint = calc(dealerHands)

      #プレーヤーの処理を行う
      playerPoint = player(stack, playerHands, playerPoint, dealerHands, dealerPoint)

      #ディーラーの処理を行う
      dealerPoint = dealer(stack, dealerHands, dealerPoint) if (playerPoint > 0)

      #カードを画面に表示する
      display(1, playerHands, playerPoint, dealerHands, dealerPoint)
    end

    STDERR.print "--- Dealer doesn't have enough cards to continue. ---\n"
  end

  #合計点数を計算する
  def self.calc(hands)
    point   = 0        #合計点数
    na      = 0        #A の枚数
    numbers = Array.new#カードの数字

    #数字を取出す
    hands.each do |x|
      numbers.push(Card.number(x).to_i)
    end

    for n in numbers
      if (n <= 10)
        point += n

        na += 1 if (n == 1)#A の枚数を数える
      else
        point += 10
      end
    end
 
    if    (point <= 11)#A は 1 点としても 11 点としてもよい
      point += 10 if (na > 0)
    elsif (point >= 22)#合計点数が 21 点を超えていたら 0 点にする
      point = 0
    end
    return(point)
  end

  #カードを画面に表示する
  def self.display(flag, playerHands, playerPoint, dealerHands, dealerPoint)
    super(playerHands, "Player : ", " [#{playerPoint}]")

    if    (flag == 0)
      super(dealerHands, "Dealer : ", ", ?", 0, 0)
    elsif (flag == 1)
      super(dealerHands, "Dealer : ", " [#{dealerPoint}]")

      if    (playerPoint == 0)
        STDERR.print "Player Busted.\n"
      elsif (dealerPoint == 0)
        STDERR.print "Dealyer Busted.\n"
      elsif (playerPoint >  dealerPoint)
        STDERR.print "Player Won.\n"
      elsif (playerPoint <  dealerPoint)
        STDERR.print "Dealer Won.\n"
      elsif (playerPoint == dealerPoint) 
        STDERR.print "Push.\n"
      end
    end
  end

  #プレーヤーの処理を行う
  def self.player(stack, playerHands, playerPoint, dealerHands, dealerPoint)
    loop do
      #カードを画面に表示する
      display(0, playerHands, playerPoint, dealerHands, dealerPoint)

      STDERR.print "  Draw(D, d) or Stand(S, s) or Quit(Q, q)? : "
      i = gets.chomp
      if    ((i == 'D') || (i == 'd')) #カードを引く
        STDERR.print "  Draw\n"
        playerHands.push(stack.next())
        playerPoint = calc(playerHands)
        break if (playerPoint == 0)
      elsif ((i == 'S') || (i == 's')) #カードを引かない
        STDERR.print "  Stand\n"
        break
      elsif ((i == 'Q') || (i == 'q')) #終了する
        exit(0)#正常終了
      else
        STDERR.print "Input Error!\n"
      end
    end
    return(playerPoint)
  end

  #ディーラーの処理を行う
  def self.dealer(stack, dealerHands, dealerPoint)
    loop do
      break if (dealerPoint >= 17)#16 でドロー(ヒット)/17 でスタンド(ステイ)

      dealerHands.push(stack.next())
      dealerPoint = calc(dealerHands)
      break if (dealerPoint == 0)
    end
    return(dealerPoint)
  end

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

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

#関数的メソッド
#なし

#トップレベル

#定数
#なし

#グローバル変数
#なし

#ローカル変数
#なし

Blackjack.run()

exit(0)#正常終了

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