プログラミング漫遊記

思ったことや、勉強したことをつらつらと。

ビンゴカード作成問題にチャレンジしてみた。

前提

フィヨルドブートキャンプ(以下、フィヨルド)というプログラミングスクールで学習しています。

フィヨルドでは、分野ごとにたくさんのプラクティスがあり、Rubyのプラクティスもそのうちの一つになります。 他にもDB設計のプラクティスがあったり、sinatraを使って簡単なWebアプリケーションを作るプラクティスがあったりするのですが、その間にどうしてもRubyことを忘れてしまうことがありました。

そこで、フィヨルドのDiscordで「rubyでアウトプット定期的にしていきたいけど、何やったらいいんだろうか?」と呟いたところ『プロを目指す人のためのRuby入門(通称チェリー本🍒)』でお馴染みのメンターの伊藤さんから以下のブログを紹介してもらったので、少しずつ解いていったものを忘備録も兼ねてブログに残していくことにしました。

blog.jnito.com

全部で何題挑戦するかはわかりませんが、まずはビンゴカード作成問題に挑戦しました。

ビンゴカード作成問題

概要

blog.jnito.com

  • ビンゴカードには1から75までの数字が記載される
  • 5x5の大きさで真ん中は穴が空いている
  • 列は左からB列、I列、N列、G列、O列となっている
  • B列:1〜15のどれか
  • I列:16〜30のどれか
  • N列:31〜45のどれか
  • G列:46〜60のどれか
  • O列:61〜75のどれか

出力例をブログから拝借しました。

 B |  I |  N |  G |  O
13 | 22 | 32 | 48 | 61
 3 | 23 | 43 | 53 | 63
 4 | 19 |    | 60 | 65
12 | 16 | 44 | 50 | 75
 2 | 28 | 33 | 56 | 68

作ったプログラム

class Bingo
  def self.generate_card
    new.generate_card
  end
  
  def generate_card
    rows = []
    5.times do |i|
      range = ((1+i*15)..(1+14+i*15)).to_a
      rows << range.shuffle.first(5).map { |n| n.to_s.rjust(2)}
    end
    puts " B |  I |  N |  G |  O"
    format_cols(rows).map { |row| puts row.join(' | ')}
  end 

  private

  def format_cols(rows)
    rows[2][2] = '  '
    rows.transpose
  end
end

Bingo.generate_card

まずビンゴクラスを作成して、クラスメソッドからインスタンスメソッド(genarate_card)を呼び出しています。

列の整形

range = ((1+I*15)..(1+14+i**15)).to_a

この部分は各列の数の範囲を配列化したのもです。 iには0,1,2,3,4まで数字が入るので 実質、以下のような意味になっています。

range1 = (1..15).to_a
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
range2 = (16..30).to_a
# => [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
range3 = (31..45).to_a
# => [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]
range4 = (46..60).to_a
# => [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
range5 = (61..75).to_a
# => [61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75]
rows << range.shuffle.first(5).map { |n| n.to_s.rjust(2)}

上記はshuffleメソッドで数字をランダムにシャッフルし、fisrtメソッドで先頭5つの数字の配列を作っています。 .map{ |n| n.to_s.rjust(2) }はrjustメソッドで2桁でけた揃えして右寄せにしています。その際文字列でないとrjustメソッドは使えないためto_sを使って文字列化しています。

ここはもっとスッキリ書けそうな気がするのですが、今現在の力ではこんなもんです。

p rows
# => [["15", " 8", " 6", " 4", " 7"], ["16", "23", "18", "25", "29"], ["35", "33", "37", "34", "31"], ["51", "50", "58", "60", "55"], ["74", "62", "63", "64", "61"]]

rowsはこんな感じで各列にあたる部分が1つの要素として収まっている状態です。

def format_cols(rows)
    rows[2][2] = '  '
    rows.transpose
  end

このメソッドは真ん中(N列)に穴を開け、transposeで行と列を入れ替えています。 実行例はこんな感じ

# 真ん中に穴を開けて行と列を入れ替える
p format_cols(rows)
[["10", "29", "41", "48", "66"], [" 5", "19", "34", "52", "73"], [" 1", "21", "  ", "60", "61"], ["12", "18", "33", "53", "69"], [" 3", "24", "38", "46", "72"]]

表示部分

puts " B |  I |  N |  G |  O"
format_cols(rows).map { |row| puts row.join(' | ')}

ヘッダー部分は素直に作って、あとは' | 'でjoinさせています。

感想

各列に範囲があったので、プログラムでそれをどう表すか悩みました。

もっとスッキリ書けそうな部分はあるのでしょうが、それは成長した未来の自分に任せることにします。 もし何かあればコメントで指摘してください。

BINGOカード作成問題はアウトプット10題の中では比較的簡単なプログラムだと思いますので是非挑戦してみてください!