はじめに
RubyについてProgateで勉強したので、実際の問題を伊藤さんのサイトにある
アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)
を解きました。各3問ずつ×3回で発信します。
備忘録のために、解答のソースだけでなく考え方も記入しています。
もしソースコードを確認して頂き改善点等あればコメントいただくと幸いです。
問題1 (カレンダー作成問題)
Dateクラスを使って、今月の1日と月末の日付と曜日を求め、次のような形式でカレンダーを表示する
April 2013
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
この問題は、以下のように考えて解いていきました。
### 1. Dateクラスを利用する
・既存のクラスを利用する場合は ```require "クラス名"```
### 2. クラスを利用したインスタンスの作成
・インスタンスの作成は ```クラス名.new(引数)```
### 3.文字列の整列
・```April 2013```の表示は全長20文字の中央揃えで表示する
→ ```表示する文字.center(20)```
・```Su Mo Tu We Th Fr Sa```の表示
① 文字列で```Su Mo Tu We Th Fr Sa```と定義し表示
② 配列で```["Su","Mo","Tu","We","Th","Fr","Sa"]```と定義し、
表示の際、文字列に変換する
→ 今回②を採用する。その際に「""」を何度も定義するのは、面倒なので省略した書き方を使用する
%W記法について
https://www.sejuku.net/blog/46939#i
・日付を2文字右揃えで表示する
→ ```表示する文字.rjust(2)```
### 4.日付の取得
・実行日時を基準とし、Dateクラスに用意されているメソッドを使用
以下のサイトを参考としました。
https://www.javadrive.jp/ruby/date_class/index8.html
https://docs.ruby-lang.org/ja/latest/class/Date.html#I_CWDAY
1.年の取得
2.月名の取得
3.月初日の取得
4.月初日の曜日の取得
5.月末日の取得
### 5.日付の表示処理
1.月初の曜日まで空白を表示する
#### 初日~末日までの表示で以下を繰り返す
2.表示を2文字表示の右づめにする(一桁の数字:「 1」、二桁の数字「10」)
3.1日ごと空白「" "」を用意する
4.土曜日まで日数を入力すると改行する
### 作成したソースコード
```ruby:calender.rb
# dateクラスの定義
require "date"
# 配列を定義
# 要素を何度も「""」でくくるのは面倒なので、%w記法を採用
youbi = %w[Su Mo Tu We Th Fr Sa]
today = Date.today
first_day = Date.new(today.year, today.month , 1);
last_day = Date.new(today.year, today.month , -1);
# dateクラスのstrftimeで、本日の年、月名を取得して表示する
puts today.strftime("%B %Y").center(20)
puts youbi.join(" ")
# 1日目の日付を記載するための空白を設ける
# 曜日を数値(0~6)に変換するメソッドを利用して
# 1日分の記載量 × 数値で空白を決める
space = " " * first_day.wday
count = first_day.wday
print space
# カレンダーの日数を初日~末日まで記載するための繰り返し文を作成する
# 繰り返し時 開始数値..終了数値を記載する
range = first_day.day..last_day.day
range.each do |day|
# 右詰めで日付を1日ずつ表示
# 土曜日まで記載すると改行
print day.to_s.rjust(2)
print " "
count = count + 1
if (count % 7 == 0)
print("\n")
end
end
問題1の気づき
・表示文字のそろえ方(中央揃え、右揃えなど)
・配列の%w記法
・each文の範囲の指定方法
問題2 (カラオケマシン問題)
カラオケで歌うときによく使う、「キーの上げ下げ」をプログラム上でシミュレートする
この問題は、以下のように考えて解いていきました。
まずはクラスを使用せずに作成する。
1. 音階のパターンを抽出
・音階は「ド」~「シ#」の12種類
2. 配列の処理
・文字列を分解する
配列名 = 文字列.split("")
・配列への値の追加
配列名.push(値)
・配列の値を文字列に変換
配列名.join
3. 音階の変換処理
1.入力された音階(#、スペース、|)すべて1つずつ分解する
2.音階を配列の要素番号と紐づける(入力数値でキーを上げ下げするため)
3.キーの上げ下げの数値を入力する(音階は12段階のため -11 ~ +11 )
4.1音ずつ手順2の音階 + キー数値 で変換した音階の要素を格納
作成したソースコード
# 入力されるメロディ
melody = "C D E F |E D C |E F G A |G F E |C C |C C |CCDDEEFF|E D C "
array = melody.split("")
# 音階
key = %w[C C# D D# E F F# G G# A A# B]
# メロディ(音階 → 数値変換用と音階変調用)
middle_melody = []
new_melody = []
# 1音ずつ → 対応する数値に変換
array.each do |n|
if n == "#"
middle_melody.push( middle_melody.pop + "#")
else
middle_melody.push(n)
end
end
# キーチェンジの数値の入力(-11 ~ 11の入力)
puts "キーチェンジの数値を入力してください (-11 ~ 11)"
key_change = gets.to_i
while key_change < -11 || key_change > 11 do
puts "範囲外です。^nキーチェンジの数値を入力してください (-11 ~ 11)"
key_change = gets.to_i
end
# 入力数値に従って変換する
middle_melody.each do |n|
if n == " " || n == "|"
new_melody.push(n)
else
onkai = key.find_index(n).to_i + key_change
if onkai >= 12
onkai = onkai - 12
end
new_melody.push(key[onkai])
end
end
# 配列を文字列に変換
puts new_melody.join
4. クラスを使用して作成する
・クラスの雛形
class クラス名
initialize
メソッド1
メソッド2
end
※ initializeメソッドは
newされた際に一度だけ自動的に実行されるメソッド
5. クラス内の変数のスコープ
・インスタンスごとの共有変数は@を付ける
@変数名 = 何らかの値
作成したソースコード
# クラス定義
class KaraokeMachine
# initializeメソッド
def initialize(melody)
array = melody.split("")
@middle_melody = []
array.each do |n|
if n == "#"
@middle_melody.push( middle_melody.pop + "#")
else
@middle_melody.push(n)
end
end
end
# 音階変換メソッド
def transpose(amount)
key = %w[C C# D D# E F F# G G# A A# B]
key_change = amount
new_melody = []
@middle_melody.each do |n|
if n == " " || n == "|"
new_melody.push(n)
else
onkai = key.find_index(n).to_i + key_change
if onkai >= 12
onkai = onkai - 12
end
new_melody.push(key[onkai])
end
end
print new_melody.join
end
end
# 入力されるメロディ
melody = "C D E F |E D C |E F G A |G F E |C C |C C |CCDDEEFF|E D C "
# インスタンスを作成。音階の変換を実施
karaoke = KaraokeMachine.new(melody)
karaoke.transpose(9)
問題2の気づき
・配列の扱い方
問題3(ビンゴゲーム問題)
1から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
この問題は、以下のように考えて解いていきました。
## 1. case文
・case 変数
when 値1 then
when 値2 then
## 2. BINGOカード作成の手順
1."BINGO"の表示
2.それぞれの列で、値が重複しないようループを実施
3.表示がずれないように数字の表示(2桁)を右詰めする
```ruby:bingo.rb
# 表示のマスは空白を含め25箇所
range = 1..25
B = []
I = []
N = []
G = []
O = []
# BINGOを表示
puts " B | I | N | G | O |"
# B,I,N,G,Oの列でそれぞれ
# 数字が重複しないようにrand関数で
# 値の割り出しを繰り返す
range.each do |count|
case count % 5
when 1 then
num = rand(1..15)
while B.include?(num) do
num = rand(1..15)
end
B.push(num)
print num.to_s.rjust(2)
print " | "
when 2 then
num = rand(16..30)
while I.include?(num) do
num = rand(16..30)
end
I.push(num)
print num.to_s.rjust(2)
print " | "
when 3 then
if count == 13
print " | "
next
else
num = rand(31..45)
while N.include?(num) do
num = rand(31..45)
end
N.push(num)
end
print num.to_s.rjust(2)
print " | "
when 4 then
num = rand(46..60)
while G.include?(num) do
num = rand(46..60)
end
G.push(num)
print num.to_s.rjust(2)
print " | "
else
num = rand(61..75)
while O.include?(num) do
num = rand(61..75)
end
O.push(num)
puts num.to_s.rjust(2)
end
end
3. クラスを使用して作成する
・bingoクラスを作成、今回initializeメソッドは不要
4. ランダムで表示する値を簡潔に記載する
・配列の要素を数個ランダムに返す
配列名.sample(個数)
class Bingo
def make_bingo
range = 0..4
# BINGOを表示
puts " B | I | N | G | O |"
b = (1..15).to_a.sample(5)
i = (16..30).to_a.sample(5)
n = (31..45).to_a.sample(5)
n[2] = " "
g = (46..60).to_a.sample(5)
o = (61..75).to_a.sample(5)
range.each do |count|
[b,i,n,g,o].each do |row|
print row[count].to_s.rjust(2)
print " | "
if row == o
printf "\n"
end
end
end
end
end
b = Bingo.new
b.make_bingo
おわりに
私のまとめが参考になれば幸いです。
以上です。