「アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた」のをワンライナーっぽく解いてみた(前半)
はじめに
こちらの記事の問題が結構楽しそうだと思ったので解いてみました。
最初は普通に書いていたのですが、リファクタリングしていくうちにどんどんワンライナーに寄ってきたので、かなりワンライナーっぽくなっています。
全10問中8問まで解いてあり、4問目まで紹介します。
コード
1. カレンダー作成問題
今月のカレンダーを文字列として返すクラスを作成する。
require 'Date' class Calendar def self.generate [ Date.today.strftime('%b %Y').center(20), [ *Date::DAYNAMES.each_with_object(0..1).map(&:slice), *Array.new(Date.today.cwday % 7), *1..Date.new(Time.now.year, Time.now.month, -1).day ].map(&:to_s).each_with_object(2).map(&:rjust) .each_slice(7).each_with_object(' ').map(&:join) ].join("\n") end end
軽く解説すると、
[ *Date::DAYNAMES.each_with_object(0..1).map(&:slice), *Array.new(Date.today.cwday % 7), *1..Date.new(Time.now.year, Time.now.month, -1).day ]
ここの返り値が[mo, tu, ..(曜日部分).. , nil, nil, ..(曜日のズレの数だけnil).. , 1, 2, 3, ..(日付)..]という1次元配列になっている。
それを.map(&:to_s).each_with_object(2).map(&:rjust)
で2文字の右寄せの文字列に変換し、
.each_slice(7).each_with_object(' ').map(&:join)
で7個ずつ連結した文字列にしている。
2. カラオケマシン問題
仕様はこちら。
class KaraokeMachine KEYS = %w[A A# B C C# D D# E F F# G G#].freeze def initialize(melody) @melody = melody end def transpose(amount) @melody.gsub(/[A-G]#?/) { |k| KEYS[(KEYS.index(k) + amount) % 12] } end end
配列を作っておいて、うまくmodを取ってずらしてやるだけ。
3. ビンゴカード作成問題
仕様はこちら。
class Bingo def self.generate_card [ 'BINGO'.chars, *(1..75).each_slice(15).each_with_object(5).map(&:sample).transpose.tap { |nums| nums[2][2] = nil } ].map do |row| row.map(&:to_s).each_with_object(2).map(&:rjust).join(' | ') end.join("\n") end end
カレンダーと似た発想で解く。
(1..75).each_slice(15).each_with_object(5).map(&:sample).transpose.tap { |nums| nums[2][2] = nil }
で、いい感じに数字が入った二次元配列ができる。tapメソッドを使って、メソッドチェーン中で真ん中の数字をnilにしているのがRubyっぽい。
4. ボーナスドリンク問題
仕様はこちら。
class BonusDrink def self.total_count_for(amount) (amount - 1) / 2 + amount end end
再帰のようで、実は閉じた式で表せる。
後編に続きます。