【Java】プログラミング初心者が、Fizz Buzz問題に挑戦してみた。

はじめに

こんにちは。ささのぼうです。今回はFizz Buzz問題に挑戦してみて、何とか解くことが出来たので、過程等をまとめてみます。

私のプログラミング略歴

  • Fizz Buzz問題 挑戦前日に"スッキリわかるJava入門"読了 

"スッキリわかるJava入門"から初めてプログラミングに触れて、読了には1週間ほどかかったので、私のプログラミング略歴は約1週間とします。

前提条件

Fizz Buzz問題の概要を見ていると、for文とif文だけで実装できそうでしたので、以下のルールを定めました。

  • ネット検索原則禁止 (書籍も禁止)
  • IDEの使用はok

    挑戦

    仕様の確認

    まず、Fizz Buzz問題の確認です。

  • 「1から100までの数字を画面に表示する」
  • 「3の倍数のときは数字の代わりにFizzと表示する」
  • 「5の倍数のときは数字の代わりにBuzzと表示する」
  • 「15の倍数のときは数字の代わりにFizzBuzzと表示する」

    「1から100までの数字を画面に表示する」

    for文を活用したら解決できそうです。

public class Main{
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            System.out.println(i);
        }
    }
}

「..の倍数のとき..と表示する」

if-else if文を使用して、それぞれのブロックで"Fizz"、"Buzz"、"FizzBuzz"を出力するイメージが出来ました。 3や5の倍数の場合からif文を始めると、else-if文で15の倍数が取れてこないので、15の倍数の場合からif文を開始します。 問題はどのように倍数を表現するかでした。 まず直感で、 "3の倍数"、"5の倍数"、"15の倍数"の値を格納する変数を作れば見通しが良くなると考えました。

public class Main{
    public static void main(String[] args) {
        int multipleOf3 = 3;
        int multipleOf5 = 5;
        int multipleOf15 = 15;
        
        for (int i = 1; i <= 100; i++) {
            /*「..の倍数のとき..と表示する」
              「期待する倍数がなければiを返す」*/
        }
    }
}

「for文スコープのロジック」

  • "もし15の倍数なら"FizzBuzz"と表示 & その後15を足して変数に格納 → そうでなく3の倍数なら"Fizz"と表示 & その後3を足して変数に格納 → そうでなく5の倍数なら"Buzz"を表示 & その後5を足して変数に格納 → どれでもなければ"変数i"を表示

if-else if文に落とし込みやすくするため、日本語に変換してみました。これを実装してみます。

public class Main {
    public static void main(String[] args) {
        int multipleOf3 = 3;
        int multipleOf5 = 5;
        int multipleOf15 = 15;
        
        for (int i = 1; i <= 100; i++) {
            if (i == multipleOf15) {
                System.out.println("Fizz Buzz");
                multipleOf15 += 15;        
            }
            else if (i == multipleOf3) {
                System.out.println("Fizz");
                multipleOf3 += 3;
            }
            else if (i == multipleOf5) {
                System.out.println("Buzz");
                multipleOf5 += 5;
            }
            else {
                System.out.println(i);
            }
        }
    }
}

つまづき

上記のソースコードで、FizzBuzz問題の要件を満たしたと考えていました。軽く見直して、実行。

  • 結果 ↓
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz

15まで正常に表示されています。 16以降はどうでしょうか。

16
17
18
19
20
21
22
23
24
25
26
27
28
29
Fizz Buzz

15以降で"Fizz"、"Buzz"が表示されていません、、しかし、"Fizz Buzz"は正しく表示されています。

最後の100まで確認したところ、15以降では"Fizz Buzz"以外正しく表示されていないことが分かりました。

原因調査

それでは、正しく表示されない原因を探っていきます。

"Fizz Buzz"を表示させている以下のブロックがあやしいです。

if (i == multipleOf15) {
                System.out.println("Fizz Buzz");
                multipleOf15 += 15;
            }

おそらくこのブロックで何か問題があって、else if に上手く処理が流れていないのではと仮定しました。

しばらく頭で考えてみて分からなかったので、プログラムの流れをトレースして変数の中身を確認してみます。

i = 1                   ..    i = 12
multipleOf3 = 3         ..    multipleOf3  = 15
multipleOf5 = 5         ..    multipleOf5  = 15
multipleOf15 = 15       ..    multipleOf15  = 15

なるほど、倍数の変数の値が全て15になる瞬間があったのですね。落ち着いて考えると当たり前ですが、盲点でした。

  • 結論

multipleOf15 = 15 の際にifブロックを抜けてしまうため、else if ブロックで値を変更している変数multipleOf3 、multipleOf5はずっと15の値のまま放置される、ということが問題でした。

デバッグ

multipleOf15 = 15 の際にifブロックを抜けてしまうので、その後のelse if ブロックが評価されない、、

対策として、multipleOf15 = 15 の際に評価されるifブロックに変数multipleOf3 、multipleOf5の値変更ロジックを追加してみました。

public class Main {
    public static void main(String[] args) {
        int multipleOf3 = 3;
        int multipleOf5 = 5;
        int multipleOf15 = 15;
        
        
        for (int i = 1; i <= 100; i++) {
            if (i == multipleOf15) {
                System.out.println("Fizz Buzz");
                multipleOf15 += 15;
                multipleOf3 += 3;
                multipleOf5 += 5;
            }
            else if (i == multipleOf3) {
                System.out.println("Fizz");
                multipleOf3 += 3;
            }
            else if (i == multipleOf5) {
                System.out.println("Buzz");
                multipleOf5 += 5;
            }
            else {
                System.out.println(i);
            }
        }
    }
}

実行してみると、正しく表示されました!

模範回答を調べてみる

封印していたchatgptさんに質問してみて返ってきたコードです (動作確認済み & ネットでも検索済み)。

public class Main {
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            if (i % 3 == 0 && i % 5 == 0) {
                System.out.println("Fizz Buzz");
            } else if (i % 3 == 0) {
                System.out.println("Fizz");
            } else if (i % 5 == 0) {
                System.out.println("Buzz");
            } else {
                System.out.println(i);
            }
        }
    }
}

なるほど、こう書けば変数宣言も要らないし、スマートにまとめることが出来るんですね。倍数というキーワードで剰余がパッと浮かぶようにしたいです。勉強になりました。

他にも三項演算子やStream APIを用いた方法等などがあるようです。またキャッチアップしたら追記してみます。

おわりに

アルゴリズム力の無さを痛感したので、毎日少しづつ伸ばしていきたいです。基本情報の科目Bを少しづつ解いて慣れようと思います。ここまで読んでくださり、ありがとうございました。

P.S.スマホで確認するとコード等が読みづらい、、レスポンシブデザインにチェック入れてみましたが、うまく対応できていないので後日何か対策を考えます。