ライブドアインターンに受かったポーカーのRubyスクリプトを貼ってみる
自分の動作環境
$ruby -v
ruby 1.9.1p243 (2009-07-16 revision 24175) [i686-linux]
#!/usr/bin/env ruby # -*- coding: utf-8 -*- class Game def initialize @deck = Deck::new #山札 @playerA = Player::new("A") #プレイヤー @playerB = Player::new("B") @turn_times = 0 #ゲーム回数カウント end #1ターン経過させる def do_one_turn now_turn player_draw_card compare_yaku print_line end #ターンのカウントと表示 def now_turn @turn_times += 1 puts("Game " + @turn_times.to_s) end #プレイヤーにカードをひかせ、役を表示する def player_draw_card [@playerA,@playerB].each do |player| player.draw_a_hand(@deck.draw_five) player.print_hand{|name, hand, yaku| "Player " + name + ":\n" + " " + hand + " " + yaku} end end #どちらが勝ったか表示する、PlayerクラスはComparableなので比較できる def compare_yaku if @playerA > @playerB then @playerA.shorino_otakebi{|i| "<<<< " + i + " <<<<"} elsif @playerA < @playerB then @playerB.shorino_otakebi{|i| ">>>> " + i + " >>>>"} else puts("---- DRAW ---") end end def print_line puts("------------------------------------------------") end #ループの最初でこれを見てゲームに入れるか確認する def continue? @deck.drawable?([@playerA,@PlayerB].size) end end #山札クラス class Deck #カードをつくり、山札につめ、シャッフルする (:Sスペード、:Dダイヤ、:Hハート、:Cクラブ) def initialize @cards = [:S, :D, :H, :C].inject([]) do |x, y| x.concat((1..13).map {|a| Card::new(y, a)}) end shuffle end #でたらめな値をソートのキーにすることによってシャッフルしている def shuffle @cards = @cards.sort_by {rand} end #人数ぶんカードがデッキに残っているか def drawable?(x) @cards.size >= (5 * x) end #プレイヤーに5枚カードをあげる def draw_five hand = Array::new(5) hand = hand.map do @cards.pop end hand end end #カードクラス一枚のカードを表わしている、to_sでスートと番号を文字にできる class Card attr_reader :suit, :num def initialize(suit, num) @suit = suit @num = num end def to_s @num.to_s + " (" + @suit + ")" end end #プレイヤークラス、ゲームからカードをもらって役の判断を行なう、Coparableでプレイヤー同士の役の大小を判断する class Player attr_reader :yaku include Comparable #役テーブル、インデックスの大小で役の大きさを表わす YAKU = [:NOTHING, :One_Pair, :Two_Pair, :Tree_Card, :Straight, :Flush, :Fullhouse, :Four_Card, :Straight_Flush, :Royal_Straight_Flush] def initialize(name) @name = name @hand = Array::new(5) @yaku = YAKU[0] end def <=>(other) myindex = YAKU.index{|item| @yaku == item} otherindex = YAKU.index{|item| other.yaku == item} myindex <=> otherindex end #手札を表示、ブロックで出力の形式をGameクラスに書けるように def print_hand(&block) stringhand = @hand.inject("") do |string, card| string += card.to_s + " " end puts(block.call(@name, stringhand, @yaku.to_s.gsub(/_/, " "))) end #どこかしらの親(ここではGame)からカードを配列でもらう def draw_a_hand(cards) @hand = cards eval_hand end #勝者表示でプレイヤーネームを表示、ゲッターを使わないためと、大なり小なり記号の出力をGameクラスにさせるためブロックを使う def shorino_otakebi(&block) puts(block.call("PLAYER " + @name + " WINS!")) end private #各役の判断、大きい順からする def eval_hand if royal_straight_flush? then @yaku = YAKU[9] elsif straight_flush? then @yaku = YAKU[8] elsif four_card? then @yaku = YAKU[7] elsif fullhouse? then @yaku = YAKU[6] elsif flush? then @yaku = YAKU[5] elsif straight? then @yaku = YAKU[4] elsif three_card? then @yaku = YAKU[3] elsif two_pair? then @yaku = YAKU[2] elsif one_pair? then @yaku = YAKU[1] else @yaku = YAKU[0] end end #ストレートの判断、手札をソートして並んでいるか判断する、エースからはじまってる場合は2があるか確認して、無かったら10..11..12に飛ぶ、枚数ぶん続いていなかったらbreakしてinjectからnilが返るのでこの関数の戻り値はその場合falseになる def straight? nil != @hand.sort do |a, b| a.num <=> b.num end.inject do |x, y| if x.num + 1 == y.num then y elsif x.num == 1 && y.num == 10 y else break end end end #そのカードがそろっている枚数を配列で返す各numの値が[2,4,2,5,4]だとすると[2,2,2,1,2]が返る def find_same_card @hand.map do |x| @hand.inject(0) do |a, b| if x.num == b.num then a + 1 else a end end end end #フォーカードが揃っているなら配列から4の値が4つ見つかる def four_card? find_same_card.find_all{|x| x == 4}.size == 4 end #スリーカードが揃っているなら配列から3の値が3つ見つかる def three_card? find_same_card.find_all{|x| x == 3}.size == 3 end #ワンペアが揃っているなら配列から2の値が2つ見つかる def one_pair? find_same_card.find_all{|x| x == 2}.size == 2 end #ツーペアが揃っているなら配列から2の値が4つ見つかる def two_pair? find_same_card.find_all{|x| x == 2}.size == 4 end #フルハウスが揃っているならばこの調べかたなら偶然にワンペアかつスリーカードの条件と同じ def fullhouse? one_pair? && three_card? end def flush? @hand.all?{|x| x.suit == @hand[0].suit} end def straight_flush? straight? && flush? end #ロイヤルストレートフラッシュ、エースの値を取りのぞいた一番小さい値が10か def royal_straight_flush? straight_flush? && @hand.map{|x| x.num}.find_all{|x| x != 1}.min == 10 end end my_game = Game::new while my_game.continue? my_game.do_one_turn end