LoginSignup
0
1

More than 3 years have passed since last update.

【超初心者用】RubyでBINGOカードを作る手順を丁寧すぎるぐらいに書いてみた(2)

Last updated at Posted at 2020-05-11

はじめに

 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が真ん中なので。

bingo.rb
bingos[2][2] = "  " 

とします。

bingo.rb
def numbers
  bingos = [B, I, N, G, O].map { |bingo| bingo.sample(5) }.transpose
  bingos[2][2] = "  "
  bingos.map  { |bin|
    bin.join(" | ")
  }.join("\n")
end

puts numbers
 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を使ってあげます。
これは、右詰めにした文字列を返すメソッドです。

これで完成まで出来そうですね。

と思ったのですが、、、

bingo.rb
def numbers
  bingos = [B, I, N, G, O].map { |bingo| bingo.sample(5) }.transpose
  bingos[2][2] = "  "
  bingos.map  { |bin|
    bin.join(" | ").rjust(2) #.rjust(2)追加
  }.join("\n")
end

puts numbers
 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

変わりません。

原因を考えてみます。

@scivolaさんの指摘でわかりました。bin.join(" | ")では11 | 28 | 33 | 56 | 66のような文字列が出来てしまっています。

つまり、rjustで長さが2の文字列を右ずめにしようとしましたが、11 | 28 | 33 | 56 | 66は2どころか10以上の1つの文字列が出来てしまっているため、効きませんでした。

それを踏まえた上で修正します。

bingo.rb
def numbers
  bingos = [B, I, N, G, O].map { |bingo| bingo.sample(5) }.transpose
  bingos[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メソッドを足してjointo_s.rjust(2)を分けてみました。

何とか、これでやっと完成ですね!!!

bingo.rb
B = (1..15).to_a
I = (16..30).to_a
N = (31..45).to_a
G = (46..60).to_a
O = (61..75).to_a

def word
  [' B', ' I', ' N', ' G', ' O'].join(' | ')
end

def numbers
  bingos = [B, I, N, G, O].map { |bingo| bingo.sample(5) }.transpose
  bingos[2][2] = "  "
  bingos.map  { |bin|
    bin.map { |b| b.to_s.rjust(2) }.join(" | ")
  }.join("\n")
end

puts word
puts numbers

これが現時点でのソースコードですが、

まだまだ、リファクタリングのしがいがありそうです。

リファクタリングしていく

まずは、

bingo.rb
B = (1..15).to_a
I = (16..30).to_a
N = (31..45).to_a
G = (46..60).to_a
O = (61..75).to_a

の部分ですね。
まとめていきます。

この変数たちは、『15個の数字の配列』を示しているわけですから。
何か良い方法でまとめられそうです。

each_sliceメソッドを使う

each_sliceメソッドは配列を分割するのに使うメソッドです。

これを上手く使っていきます。

bingo.rb
B = (1..15).to_a
I = (16..30).to_a
N = (31..45).to_a
G = (46..60).to_a
O = (61..75).to_a

bingos = [B, I, N, G, O].map { |bingo| bingo.sample(5) }.transpose

こちらが現時点のコード。これをeach_sliceメソッドを使って変更していく。

これが何とも見事。

bingo.rb
bingos = (1..75).each_slice(15).map { |bingo| bingo.sample(5) }.transpose

6行から1行へとこんなにも短くなりました!

空白+文字列(' '+文字列)で作った見た目の悪い配列をどうにかする

bingo.rb
def word
  [' B', ' I', ' N', ' G', ' O'].join(' | ')
end

これですね。' B'では、空白+文字列で無理やり文字を作りました。
どうにかしていきます。

charsメソッドを使います(%w()でも出来ます)

これは、文字列の文字を一文字ずつ配列へと返すメソッドです。

sample.rb
"banana".chars #=> ["b", "a", "n", "a", "n", "a"]

これを使います。

bingo.rb
["BINGO".chars] #[[' B', ' I', ' N', ' G', ' O']]を変更

#または

[%w(B I N G O)] ##[[' B', ' I', ' N', ' G', ' O']]

(この後、mapメソッドが2つあって、2つ展開するからここでは『配列の配列』を作っている?)

ですが、これでは空白がなくなってしまいましたね。

このまま出力すると

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メソッドです

ちなみに現在のコードは

bingo.rb
def word
  ["BINGO".chars].join(' | ')
end

def numbers
  bingos = (1..75).each_slice(15).map { |bingo| bingo.sample(5) }.transpose
  bingos[2][2] = "  "
  bingos.map  { |bin|
    bin.map { |b| b.to_s.rjust(2) }.join(" | ")
  }.join("\n")
end

puts word
puts numbers

rjustメソッドは一度使っているのでその位置にまとめることが出来そうですね。

やってみましょう。

仕上げにかかります

まずは、def worddef numbersをまとめます。

そして、変数の名前も分かりやすいように変更していきます。

出来たものがこちら。

bingo.rb
def card
  bingo = ["BINGO".chars]
  numbers = (1..75).each_slice(15).map { |number| number.sample(5) }.transpose
  numbers[2][2] = "  "
  rows = bingo + numbers
  rows.map  { |row|
    row.map { |r| r.to_s.rjust(2) }.join(" | ")
  }.join("\n")
end

puts card
 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

完成です。お疲れ様でした。

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1