Ruby1.9のArray#sampleを使ってビンゴカードを作る。

別にビンゴカードを作りたいわけじゃないけど、Ruby1.9のArray#sampleの使いどころを考えてたらビンゴカードが思い浮かんだのでやってみました。

最初は単純に

(1..75).to_a.sample(24)

で良いのかなーと思ったんですけど、wikipediaを読んでみたら

なお、通常はまったくのランダムで番号が書かれているわけではなく、一番左の列は1~15の数字の中から5個選ばれている。同様に、左から2列目は16~30、中央列は31~45、右から2列目は46~60、一番右の列は61~75から5個ずつ選ばれている。

ビンゴ - Wikipedia

って書いてあったので、そのあたりも踏まえつつ、Array#sampleを使ってビンゴカードを作ってみました。

if RUBY_VERSION < '1.9.0'
  # Ruby1.8でもArray#sampleを使えるようにする
  class Array
    def sample n=nil
      n.nil? ? self[rand(self.size)] : self.sort_by{rand}[0,n]
    end
  end
end

ROW_SIZE = 5 # ビンゴカードの列数
NUMBERS = 1..75 # 出現するナンバーの範囲
STEP = NUMBERS.last / ROW_SIZE
CENTER = ROW_SIZE / 2

number_table = []
NUMBERS.step(STEP){|i| number_table << (i..(i - 1 + STEP)).to_a}

INIT_CARD = (1..ROW_SIZE).map{Array.new(ROW_SIZE)} # 5列 * 5行の多次元配列を用意

%w(Taro Jiro Hanako Pochi Tama).each do |member|
  card = INIT_CARD
  number_table.each_with_index do |line, x|
    # Array#sampleの出番
    line.sample(ROW_SIZE).each_with_index do |num, y|
      card[y][x] = num if x != CENTER || y != CENTER
    end
  end

  puts "#{member}'s bingo card"
  card.each do |line|
    puts '  ' << line.map{|num| (num.nil? ? '*' : num.to_s).rjust(2)}.join(', ')
  end
  puts
end

実行すると↓こんな感じで出力されました。

Taro's bingo card
   1, 23, 45, 50, 73
   7, 29, 39, 51, 67
  13, 18,  *, 52, 72
  11, 22, 38, 60, 71
   4, 27, 31, 47, 61

Jiro's bingo card
   1, 20, 38, 49, 61
  12, 29, 36, 60, 65
   7, 26,  *, 46, 64
   9, 24, 43, 48, 74
  14, 18, 35, 56, 72

Hanako's bingo card
   4, 20, 45, 52, 61
   8, 30, 40, 59, 71
  14, 17,  *, 55, 62
  15, 22, 42, 53, 65
   9, 29, 32, 56, 67

Pochi's bingo card
  15, 22, 43, 58, 68
  13, 26, 31, 55, 65
   9, 24,  *, 59, 69
   2, 18, 39, 46, 64
   8, 30, 44, 52, 73

Tama's bingo card
   6, 16, 43, 53, 62
  11, 27, 38, 51, 61
  14, 24,  *, 54, 73
  15, 22, 45, 46, 65
   4, 25, 31, 47, 72

なんかグダグダなコードになってしまったけど、とりあえず成功