【Ruby】FizzBuzz問題を解いてみよう!


FizzBuzz問題とは

このゲームをコンピュータ画面に表示させるプログラムとして作成させることで、コードが書けないプログラマ志願者を見分ける手法をJeff AtwoodがFizzBuzz問題 (FizzBuzz Question) として提唱した。その提唱はインターネットの様々な場所で議論の対象になっている。

オンラインスクールの勉強会で、開催されていたので(残念ながら出席できなかったですが)気になって、チャレンジした結果をまとめてみました。

今回のルール

1〜30の数字を表示する
・「3の倍数」の場合、「Fizz」を出力
・「5の倍数」の場合、「Buzz」を出力
・「15の倍数」の場合、「FizzBuzz」を出力
・「それ以外」の場合、数字をそのまま出力

環境

Ruby 2.7.2

対象者

Ruby初学者
(Progate1周して、なんとなくわかる程度の方を想定)

解答例(2パターン紹介)

解答例をみる前に、自身でも考えてみましょう。
ヒントは、くり返し処理です
考えたら、解答例にすすみましょう!

解答例①

最初の解答は、基本的なくり返し処理の1つであるfor文で考えました。
for文の解説を前に、条件分岐のif文から一緒にみていきましょう。

if文とは?

「もし〇〇ならば、▲▲をおこなう」という条件分岐のこと。
では、「3の倍数」の場合、「Fizz」をif文で出力してみましょう。

ヒント①:if文は、下記のように処理されます。

  if 条件式 then   #thenは省略可
   処理
  end

ヒント②:3の倍数
変数が3で割り切れる(=余りが0)という意味です。

答え
試しに「変数 = 3」を追加してみましょう。
処理が上手くできていれば、"Fizz"が出力されます。

  i = 3
  if i % 3 == 0
    puts "Fizz"
  end
  #Fizz

「3の倍数」が出力できれば、あとは「5の倍数」と「15の倍数」「それ以外の数字」を加えて、if文を考えてみましょう!複数の条件式の組み立て方が、わからない方は「Ruby if文」で検索してみるといいですよ。

答え
いかがでしたか?
まずは複数の条件組み方をみていきましょう!
「もし〇〇と等しければ▲▲、〇〇でなくもし■■と等しければ□□、いずれでもなければ☆☆を行う」は、下記のように組むことができます。

   i = ☆☆
   if i == 〇〇
     puts "▲▲"
   elsif i == ■■
   puts "□□"
  else
     puts "☆☆"
   end

  # ☆☆

これに、先程の「3の倍数」「5の倍数」「15の倍数」「それ以外の数字」をあてはめてみましょう!
下記のように組むことができます。

  if i % 15 == 0    i % 3 == 0 && i % 5 == 0 でもOK
    puts "FizzBuzz"
  elsif i % 5 == 0
    puts "Buzz"
  elsif i % 3 == 0
    puts "Fizz"
  else
    puts i 
  end

ここでPOINTは、⭐マークのところです。
例えば⭐を下記のように変え、「i = 30」を代入してみましょう。

  i = 30
  if i % 3 == 0    
    puts "Fizz"
  elsif i % 5 == 0
    puts "Buzz"
  elsif i % 15 == 0
    puts "FizzBuzz"
  else
    puts i 
  end

 # Fizz

本来なら、30は15の倍数となるため、「FizzBuzz」と出力されますが、「Fizz」と出力されています。これは、⭐から順に処理が行われているからです。ですから、「15の倍数」「5の倍数」「3の倍数」の順に条件式をたてて、最後に「それ以外の数字」にします。

if文の次はfor文を一緒にみていきましょう!

for文とは?

くり返し処理を行う1つです。inのあとに指定したオブジェクトの要素分だけ処理をくり返し行います。

for 変数 in オブジェクト do
   くり返す処理
end

今回は、「1〜30の数字を表示する」でした!基本文法のオブジェクト部分に、あてはめてみましょう!
出力して、確かめてみましょう。期待通りの結果になりましたか?

for i in 1..30
  if i % 15 == 0
    puts "FizzBuzz"
  elsif i % 5 == 0
    puts "Buzz"
  elsif i % 3 == 0
    puts "Fizz"
  else
    puts i 
  end
end

出力結果

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz

ちゃんと出力できました
皆さんは、同じ出力結果になりましたか?
以上、解答例①のfor文でした!

解答例②

次は、eachメソッドで考えました。(オーソドックスな解答だと思います。)

eachメソッドとは?

配列や範囲オブジェクトなどで用意されているメソッドであり、オブジェクトに含まれている要素を順に取り出します。

オブジェクト.each do |変数|  #doは省略可
  くり返す処理
end

では、eachメソッドを使用して、出力してみましょう!
実際に、手を動かすのも大切ですよ。

(1..30).each do |i|
  if i % 15 == 0
    puts "FizzBuzz"
  elsif i % 5 == 0
    puts "Buzz"
  elsif i % 3 == 0
    puts "Fizz"
  else
    puts i 
  end
end

出力結果

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz

eachメソッドでも、同じ出力結果になりました。
今回は2つの解答方法を紹介いたしました。GitHubでは、他のメソッドも使用して解いているので、
気になった方は、覗いてみて下さい!

【補足】for文とeachメソッドの違い

プロを目指す人のためのRuby入門より一部引用
Rubyのプログラムでは通常、for文よりeachメソッドをよく使います。
(略)
for文の場合は、配列の要素を受け取る変数や、for文の中で作成したローカル変数がfor文の外でも使える、という違いがあります。

また、eachメソッドは、下記で示しているdo~endの中でしか、変数を使用することができません。

オブジェクト.each do |変数|
  くり返す処理
end

学習中for文をほぼ使用しなかったので、今回まとめていて、ふり返りが出来て良いアウトプットになりました!今回、変数を「indexのi」としていますが、「num,number,n」でも良いと思います。
最後まで、お付き合いして頂いてありがとうございます

参考文献: