はじめに
B | I | N | G | O
8 | 16 | 36 | 57 | 67
10 | 24 | 33 | 58 | 72
2 | 17 | | 51 | 69
7 | 18 | 45 | 59 | 62
4 | 21 | 37 | 53 | 71
今回は(2)で前回の記事に続き、CodeIQに「ビンゴカード作成問題」を出題しました。みなさんの挑戦をお待ちしてます!を参考にRubyでBINGOカードを作るを作ってみようと思いました。
しかしですね、インプットしかしてなかった人にはBINGOカードと言えど、これをアウトプットするのは多少なりとも苦戦するのではないでしょうか?
今回は、自分なりに順を追ってどのように作成していったかを記載していきます。
本当に、超初心者用にめちゃくちゃ丁寧に手順を記しています。
『そんな基本的な事・・・』と思わずみていただけると幸いです(笑)
そして何よりも、手順も考え方も無茶苦茶ではあると思います。
試行錯誤ある中で学習していきます。
ちなみに(1)の【超初心者用】RubyでBINGOカードを作る手順を丁寧すぎるぐらいに書いてみた(1)が最初です。
作成手順にもっと効率の良い方法などありましたら、是非意見をお待ちしております。
前回の時点
B | I | N | G | O
14 | 30 | 35 | 55 | 64
6 | 23 | 41 | 50 | 71
9 | 19 | 45 | 59 | 74
4 | 24 | 37 | 52 | 70
8 | 22 | 31 | 48 | 68
ランダムな数字をカード形式に作り上げるところまでいきました。
まだ、していない事は
・カード真ん中の空欄を開ける
・B
の列の|
の位置を揃える
・全力のリファクタリング
です。
それでは、実装していきます。
カード真ん中の空欄を開ける
ここでは、string[]
を使います。
[]内で文字の場所を指定します。
今回は、列、行、共に3番目の位置。つまり、インデックス番号でいう2
が真ん中なので。
bingos[2][2]=" "
とします。
defnumbersbingos=[B,I,N,G,O].map{|bingo|bingo.sample(5)}.transposebingos[2][2]=" "bingos.map{|bin|bin.join(" | ")}.join("\n")endputsnumbers
B | I | N | G | O
2 | 26 | 38 | 58 | 63
5 | 20 | 35 | 59 | 64
15 | 19 | | 56 | 71
1 | 23 | 43 | 52 | 62
11 | 30 | 34 | 50 | 70
何とか真ん中を開けることは出来ました。
後は、|
の位置を揃えてあげるだけですね。
列の|
の位置を揃える
ポイントは、BINGO
という文字列とランダムな数字を右詰めにする事です。
しかし、しかし無理やり" "
で空白を作ろうにも1桁の数字と2桁の数字が混在しているので上手くいきません。
右詰めにするメソッドがあれば・・・
と思っていたらありました。(笑)
文字列.rjust
を使ってあげます。
これは、右詰めにした文字列を返すメソッドです。
これで完成まで出来そうですね。
と思ったのですが、、、
defnumbersbingos=[B,I,N,G,O].map{|bingo|bingo.sample(5)}.transposebingos[2][2]=" "bingos.map{|bin|bin.join(" | ").to_s.rjust(2)#.to_s.rjust(2)追加}.join("\n")endputsnumbers
B | I | N | G | O
11 | 28 | 33 | 56 | 66
7 | 27 | 32 | 55 | 61
4 | 25 | | 59 | 63
6 | 24 | 37 | 51 | 71
15 | 22 | 39 | 58 | 72
変わりません。
原因を考えてみます。
おそらく、rjustメソッド
は文字列に対して使うメソッドですから、これが効いていないとなると。
今回使っている場所は文字列に対してではない?のかと思われます。to_s
で文字列に変更しているつもりだったのですが。。。(分かる方、教えてください。)
やり方を変えてみます。
どんっ
defnumbersbingos=[B,I,N,G,O].map{|bingo|bingo.sample(5)}.transposebingos[2][2]=" "bingos.map{|bin|bin.map{|b|b.to_s.rjust(2)}.join(" | ")}.join("\n")end
B | I | N | G | O
8 | 16 | 36 | 57 | 67
10 | 24 | 33 | 58 | 72
2 | 17 | | 51 | 69
7 | 18 | 45 | 59 | 62
4 | 21 | 37 | 53 | 71
bingos.mapの中にもう一つmapメソッド
を足してjoin
とto_s.rjust(2)
を分けてみました。
原因は、joinメソッド
が右詰めの邪魔をしていたのではないか?と思っています。
何とか、これでやっと完成ですね!!!
B=(1..15).to_aI=(16..30).to_aN=(31..45).to_aG=(46..60).to_aO=(61..75).to_adefword[' B',' I',' N',' G',' O'].join(' | ')enddefnumbersbingos=[B,I,N,G,O].map{|bingo|bingo.sample(5)}.transposebingos[2][2]=" "bingos.map{|bin|bin.map{|b|b.to_s.rjust(2)}.join(" | ")}.join("\n")endputswordputsnumbers
これが現時点でのソースコードですが、
まだまだ、リファクタリングのしがいがありそうです。
リファクタリングしていく
まずは、
B=(1..15).to_aI=(16..30).to_aN=(31..45).to_aG=(46..60).to_aO=(61..75).to_a
の部分ですね。
まとめていきます。
この変数たちは、『15個の数字の配列』を示しているわけですから。
何か良い方法でまとめられそうです。
each_sliceメソッド
を使う
each_sliceメソッドは配列を分割するのに使うメソッドです。
これを上手く使っていきます。
B=(1..15).to_aI=(16..30).to_aN=(31..45).to_aG=(46..60).to_aO=(61..75).to_abingos=[B,I,N,G,O].map{|bingo|bingo.sample(5)}.transpose
こちらが現時点のコード。これをeach_sliceメソッドを使って変更していく。
これが何とも見事。
bingos=(1..75).each_slice(15).map{|bingo|bingo.sample(5)}.transpose
6行から1行へとこんなにも短くなりました!
空白+文字列(' '+文字列)で作った見た目の悪い配列をどうにかする
defword[' B',' I',' N',' G',' O'].join(' | ')end
これですね。' B'
では、空白+文字列で無理やり文字を作りました。
どうにかしていきます。
charsメソッド
を使います
これは、文字列の文字を一文字ずつ配列へと返すメソッドです。
"banana".chars#=> ["b", "a", "n", "a", "n", "a"]
これを使います。
["BINGO".chars]#[' B', ' I', ' N', ' G', ' O']を変更
ですが、これでは空白がなくなってしまいましたね。
このまま出力すると
B | I | N | G | O
11 | 24 | 40 | 53 | 73
5 | 21 | 33 | 52 | 70
10 | 28 | | 46 | 75
12 | 20 | 38 | 48 | 71
1 | 26 | 42 | 56 | 63
空白をどうにかしましょう。
ここでもう一度、ここまでで使ったメソッドを思い出してみます。
文字数を調節するメソッドがありました。右詰めにするヤツ。
そうです。
・rjustメソッド
です
ちなみに現在のコードは
defword["BINGO".chars].join(' | ')enddefnumbersbingos=(1..75).each_slice(15).map{|bingo|bingo.sample(5)}.transposebingos[2][2]=" "bingos.map{|bin|bin.map{|b|b.to_s.rjust(2)}.join(" | ")}.join("\n")endputswordputsnumbers
rjustメソッドは一度使っているのでその位置にまとめることが出来そうですね。
やってみましょう。
仕上げにかかります
まずは、def word
とdef numbers
をまとめます。
そして、変数の名前も分かりやすいように変更していきます。
出来たものがこちら。
defbingowords=["BINGO".chars]numbers=(1..75).each_slice(15).map{|number|number.sample(5)}.transposenumbers[2][2]=" "cards=words+numberscards.map{|card|card.map{|c|c.to_s.rjust(2)}.join(" | ")}.join("\n")endputsbingo
B | I | N | G | O
3 | 19 | 39 | 46 | 69
8 | 21 | 35 | 50 | 61
13 | 22 | | 58 | 68
10 | 16 | 44 | 55 | 74
1 | 28 | 40 | 56 | 66
完成です。お疲れ様でした。