概要
rubyでドローポーカーを作ってみる~準備編~
↓
rubyでドローポーカーを作ってみる~test-unit準備編~
↓
rubyでドローポーカーを作ってみる~実装編1(カード)~
↓
rubyでドローポーカーを作ってみる~実装編2(役)~
↓
rubyでドローポーカーを作ってみる~実装編3(プレイヤー)~
↓
rubyでドローポーカーを作ってみる~実装編4(山札)~
に続いて。
ソース: https://github.com/rytkmt/ruby_poker
ゲームの実装
やってきました。
整理することが多そうなので若干びびってますが、一度すべて洗い出してみたら全体像がつかめて案外・・ってなるかもしれないですね。
では、整理していきましょう。
- 山札を作成
- 指定人数分、プレイヤーを作成
- 山札から5枚ずつカードを配る
- 各プレイヤーを順番に変更するカードの確認
- 手札を画面に表示する
- 全カード
- 現在の手札での役
- 変更する場合、枚数分山札からカードを渡し、不要カードを回収し山札の不要カードとして追加する
- 変更後の手札を画面に表示する
- 全カード
- 現在の手札での役
- 手札を画面に表示する
- 全プレイヤーの役を判定する
- 勝者を表示
ゲームの開始
まずゲームは開始するとともに山札を初期化します
module RubyPoker
class Game
def initialize
@deck = Deck.new
end
end
end
ゲームの実行
start
って付けようとしていましたが、gameを行うのはplay
のほうが適切だと思ったのでplay
でいきます
このとき、new.play
って毎回するのもあほらしいので、.play
メソッドを用意してしまいます
def self.play
new.send(:play)
end
private
def play
puts "<ゲーム開始>"
puts "<ゲーム終了>"
end
プレイヤーの名称を保持
毎回プレイヤー番号を渡し続けるのもしんどいので、プレイヤーの名称を保持しておくように機能強化します。
module RubyPoker
class Player
include Comparable
- attr_reader :hand
+ attr_reader :name, :hand
- def initialize(cards:)
+ def initialize(name:, cards:)
プレイヤー人数の決定
プレイヤーを初期化するにあたり、人数を入力してもらい、カードを5枚ずつ配ります
人数の入力は間違うこともあるため、間違っている場合は再度入力を促すようにします
def init_players(count:)
@players = count.times.map { |i| Player.new(name: "プレイヤー#{i + 1}", cards: @deck.draw(count: 5)) }
end
def input_player_count
puts "プレイヤーの参加人数を入力してください(1~7)"
player_count = gets.to_i
return player_count if (1..7).include?(player_count)
puts "入力が間違っています"
input_player_count
end
プレイヤーの手札表示
プレイヤーの手札を表示するために、カード、役などそれぞれ表示用の文字列を生成します。
このとき、コンソール出力はinspect
メソッドを使用するのが一般的なのでそちらで実装します。
プレイヤーは各カードと役を表示します。
なので、カード、役にもそれぞれinspect
を定義し、それを合わせて出力するのをプレイヤーの出力で行うようにします。
また、カードの表示がわりと見にくいので、色を付けて表示するようにしてみます。
色表示用のgemインストール
+gem "rainbow"
$ bundle install
+require "rainbow"
これでputs Rainbow("hoge").red
とかすることでカラー表示できるようになります
カードのinspect
- スートの表示用に記号へ変換
- 数字の記号変換
- スートに応じてカラーを切替
をそれぞれ行います
def inspect
suit_str =
case @suit
when :spade; "♠"
when :heart; "♥"
when :diamond; "♦"
when :club; "♣"
end
number_str =
case @number
when 1; "A"
when 13; "K"
when 12; "Q"
when 11; "J"
else; @number
end
color =
case @suit
when :spade; :blue
when :heart; :red
when :diamond; :yellow
when :club; :green
end
Rainbow("[#{suit_str} #{number_str}]").send(color)
end
役のinspect
def inspect
hand_type_name =
case @hand_type
when :royal_straight_flush; "ロイヤルストレートフラッシュ"
when :straight_flush; "ストレートフラッシュ"
when :four_of_a_kind; "フォーカード"
when :full_house; "フルハウス"
when :flush; "フラッシュ"
when :straight; "ストレート"
when :three_of_a_kind; "スリーカード"
when :two_pair; "ツーペア"
when :one_pair; "ワンペア"
when :high_card; "🐷"
end
"役: #{hand_type_name}"
end
プレイヤーのinspect
最後にプレイヤーです
カード交換の際に番号入力をしてもらうため、各カードに番号をつけて表示します。
def inspect
cards_str = @cards.map.with_index(1) do |card, i|
"#{i}. #{card.inspect}"
end.join(" ")
cards_str + "\n" + @hand.inspect + "\n"
end
これで、p player
をすることで こんな感じになります(色はここでは映らないですが・・)
↓
1. [♥ 5] 2. [♦ 8] 3. [♣ 4] 4. [♠ 10] 5. [♠ 4]
役: ワンペア
プレイヤーのターン処理
- 各プレイヤーの現在の状況を表示
- カード交換を確認
- 入力が間違っていたら再度確認する
- 交換後の手札を表示
def turn(player:)
puts "\n#{player.name} のターンです"
p player
puts "カードの交換ができます"
indexes = input_change_indexes
return if indexes.empty?
new_cards = @deck.draw(count: indexes.size)
trushed = player.change(indexes: indexes, new_cards: new_cards)
@deck.trush(cards: trushed)
p player
end
def input_change_indexes
puts "捨てるカードの番号を半角スペース区切りで入力してください(なければそのままEnter)"
indexes = gets.chomp.split.map(&:to_i)
return indexes.map { |i| i - 1 }.sort if indexes.all? { |i| (1..5).include?(i) }
input_change_indexes
end
プレイヤーの勝敗判定
def judge
puts "----- 結果 -----"
@players.each do |player|
puts "#{player.name} の手札"
p player
puts ""
end
winner = @players.max
puts Rainbow("\n#{winner.name} の勝ち 👏👏").underline
end
実行メソッドにまとめる
def play
puts "<ゲーム開始>"
init_players(count: input_player_count)
@players.each { |player| turn(player: player) }
judge
puts "<ゲーム終了>"
end
ゲームの実行を簡単にする
RubyPoker::Game.play
となりますが、 RubyPoker.paly
がいい。。
def self.play
RubyPoker::Game.play
end
完成
bundle exec console
を実行することでゲームを楽しむことができます。
感想
Qiitaで見た1つの記事をきっかけに「やってみよう」と思い今回の記事を書きながら実装しました。
実際に実装していく流れなどをみなさんがどういう風に行っているのか?というところは、いざ仕事で開発をしていると各個人で頭の中で考えて全て整ったプログラムを確認することばかりのため、
あまり実装のプロセスを覗く機会がない印象があります。
今回の記事が少しでも参考になればうれしいです。
普段仕事ではrailsのプロジェクトなので、railsやgemを触ることはありますが、
単一のrubyプロジェクトを作ることは無かったためGemfile、Rakefileなど改めてこういう感じで進めるんだ~と自分のなかでもふわっとしていたところが理解できました。
普段使わないgemを触るのも楽しかったです。
この記事をもとに同じように刺激をうけ、なにか作ってみよう と思う方がいればうれしいです。
また、流れを公開したことにより、もしここをこういう風にするとより良くなる などのアドバイスがあればぜひ教えてください。お待ちしております。
実際のソースはこちらにあります。 https://github.com/rytkmt/ruby_poker
実装に関しての感想
今回、ポーカーに限った実装でしたが、
カードを共通として、プレイヤーと山札の処理をゲームの種別に応じてモジュールを切り替えることによっていろんなゲームを載せる なども出来そうかなーと思いました。
また、役判定を完全に切り分けることで、ローカルルールで役を追加する(奇数・偶数でのストレートとかあっても面白そう)などもできるかなと思います
今回jokerは考慮せず作ったため、それを追加するのは少し大変だなーとは思いますが、やってみるのも楽しいかもしれないですね。
以上、かなり記事数も多くなりましたが、長々と見ていただいた方、ありがとうございました。