0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby初心者問題を解いてみる(No.1~No.3)

Last updated at Posted at 2019-10-06

はじめに

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の音階 + キー数値 で変換した音階の要素を格納

作成したソースコード

music.rb
# 入力されるメロディ
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. クラス内の変数のスコープ

・インスタンスごとの共有変数は@を付ける
@変数名 = 何らかの値

作成したソースコード

music2.rb
# クラス定義
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(個数)

bingo2.rb
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

おわりに

私のまとめが参考になれば幸いです。
以上です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?