#1.はじめに
Rubyって楽しいですね。独特の言い回しはあるけれど、ささっと書けるのが素敵です。今回は自分がどこまでRubyを理解しているのかを知るために、なにかつくってみることにしました。チンチロゲームです。
#2. チンチロとは?
サイコロをつかった賭博ゲームです。サイコロ3つを振り、出た目で役が決まります。親を交代しながら、掛け金が移動していきます。私はカイジでこのゲームを知りました。
チンチロゲームを作ろうと思ったのは、適当な難易度だと思ったからです。カードゲームのようにマークや残数を考えなくていいし、手札を表示させる必要もありません。
※ピンゾロサイやシゴロサイは出ません。
#3. 全体の仕様決定
##3-1. ルール
ルール/役はカイジの地下チンチロを適用します。勝敗は自分で適当に
http://ketto.com/zw/tintiro_rule.shtml
##3-2. ゲームの流れ
1. 親決め
2. 掛け金決定
3. サイコロを振り役を決める(親が最初、子も振る)
4. 役に応じて掛け金の移動
5. 掛け金が0になったら負け もしくは親を二巡して掛け金が多い人が勝ち
3-3.実装に必要な処理
□ サイコロを振る/役の決定
□ 掛け金の移動
□ 勝利/敗北判定
□ 親の決定
□ 親の移動
□ メイン画面・メッセージ出力
これで全体的なものがなんとなく見えてきました。
#4. 役の決定までをつくる
今回の記事では「サイコロを振る/役の決定」の機能をつくってみます。なにかしらの関数が必要になるでしょう。roll_dice()
関数とします。引数はなし、戻り値はサイコロの出目と役です。ハッシュ形式で
{eye: eye_on_the_dices, hand: dice_hand}
とできればいいですね。書きます。
def roll_dice()
eye_on_the_dices = [rand(1..6),rand(1..6) ,rand(1..6)]
eye_on_the_dices.sort!
if eye_on_the_dices === [1,1,1] then
dice_hand = 'ピンゾロ'
elsif eye_on_the_dices === [1,2,3] then
dice_hand = 'ヒフミ'
elsif eye_on_the_dices === [4,5,6] then
dice_hand = 'シゴロ'
elsif eye_on_the_dices.uniq.size == 1 then
dice_hand = 'ゾロ目'
elsif eye_on_the_dices.uniq.size == 2 then
# ????
else
dice_hand = '目なし'
end
{eye: eye_on_the_dices, hand: dice_hand}
end
Rubyは関数の戻り値にreturn
を使わないのが一般的らしいです。ちょっとびっくり。
はじめのeye_on_the_dicesには1~6のサイコロの出た目を入れます。次にsortをすることで配列の中を昇順の並びにします。こうすることで、[1,3,5]と[3,5,1]が同じものとして扱われます。
次に出た目の判定です。ピンゾロ、ヒフミ、シゴロ、ゾロ目は単純です。しかし、通常の目の判定がちょっと難しかったです。「3つのサイコロのうち2つが同じ目」となるからです。しかものこりの1個のサイコロの目で役の強さが変わるのでそれも取得する必要があります。
すこし悩んだ結果、こうなりました。
#...略
elsif eye_on_the_dices.uniq.size == 2 then
group_eye_dices = eye_on_the_dices.group_by{|value|value}
#ハッシュ形式で整形する ex. group_eye ={2=>[2,2], 5=>[5]}
uniq_array = group_eye_dices.select{|key,value| value.size == 1}
#重複していない要素のみを取り出す ex. uniq_array ={5=>[5]}
uniq_value = uniq_array.values.flatten.first
#取り出した要素を抽出 ex. uniq_array ={5=>[5]}
dice_hand = '通常の目(' + uniq_value.to_s + ')'
else
#...略
group_by
やselect
で値を整形します。できました。
5.テスト
はじめてですが、テストコードというのを書いてみます。チェリー本に書いてあった、minitestを使います。サイコロ3つの全パターン(216通り)をそれぞれassert equal
で判定させました。もっとよいやりかたがあるかもしれません。だれか教えてください。
require 'minitest/autorun'
require './lib/dice_roll'
class DiceTest < Minitest::Test
def test_dice
# 1
assert_equal 'ピンゾロ', roll_dice([1,1,1])
assert_equal '通常の目(2)', roll_dice([1,1,2])
assert_equal '通常の目(3)', roll_dice([1,1,3])
assert_equal '通常の目(4)', roll_dice([1,1,4])
assert_equal '通常の目(5)', roll_dice([1,1,5])
assert_equal '通常の目(6)', roll_dice([1,1,6])
assert_equal '通常の目(2)', roll_dice([1,2,1])
assert_equal '通常の目(1)', roll_dice([1,2,2])
assert_equal 'ヒフミ', roll_dice([1,2,3])
assert_equal '目なし', roll_dice([1,2,4])
assert_equal '目なし', roll_dice([1,2,5])
#めっちゃ略....
end
end
テストのため関数に引数/戻り値を設定しなおしました。この方法があっているのか疑問ですが....
テストは無事に通りました。よかったです。
6. 次回予告
次はプレイヤーをclassで定義し、役によって掛け金が移動するようにします。
今回のコードはこちらのリポジトリに追記していきます。