ビンゴカード作成問題を解いてみた
問題はこちら。
最初に書いたコード
class Bingo SIZE = 5 def generate_card format_a_row = Proc.new do |array| array.map {|f| f.to_s.rjust(3)}.join(' |') end header = format_a_row("BINGO".chars) rows = (1..SIZE).map do |i| (1..SIZE).map {rand((i-1)*15+1..i*15)} end.transpose rows[(SIZE-1)/2][(SIZE-1)/2] = "" rows.map! {|r| format_a_row(r)} puts [header, *rows].join("\n") end end Bingo.new.generate_card
出力結果は以下。
B | I | N | G | O 9 | 21 | 40 | 46 | 74 9 | 29 | 45 | 59 | 67 6 | 22 | | 56 | 61 12 | 18 | 34 | 51 | 66 7 | 28 | 36 | 47 | 62
transposeすぐ発想できたのはよかった。
ん…?数字重複してるじゃん!これじゃだめだ。
修正したコード
解答例もみる。
あと考えたらheaderとbodyの整形まとめた方がいいな。
class Bingo SIZE = 5 FORMAT = Array.new(5, '%3s').join(' |') def generate_card rows = (1..SIZE) .map {|i| [*((i-1)*15-1..i*15)].sample(5)} .transpose.tap {|t| t[(SIZE-1)/2][(SIZE-1)/2] = ""} puts rows.unshift("BINGO".chars).map {|r| FORMAT % r}.join("\n") end end Bingo.new.generate_card
tapってこうやってつかうんやな…すっきりやな…。
学んだこと
String#%(args)
sprintf的なフォーマットができる。リファレンス
> "--%s--" % "hoge" # => "--hoge--" # 引数に配列もわたせる > "--%s--%s--" % ["hoge", "fuga"] # => "--hoge--fuga--" # 幅も指定できる(右寄せになる) > "--%10s--" % "hoge" # => "-- hoge--"
ランダムな値
をとるときには、重複を許容する/しないを意識すべし。