本稿は、プログラミング未経験で新人研修でプログラミングをやらされている皆様へ(2)の続きです。
条件分岐して処理内容を分ける
いろいろ計算できるのは分かったけどさぁ、もう少しエンタメ性がないと勉強していて面白くないよ。このように皆様はお考えだと思いますので、FizzBuzzという、英語圏のゲームで、なおかつ、プログラミングができるかどうかの判定に使われることが多いお題をやってみましょう。
FizzBuzzとは?
プレイヤーが輪になって数字を1から順に数えていくゲームで、ただし、3の倍数のときはFizz、5の倍数のときはBuzz、そして3と5の倍数のときはFizzBuzzと言わなければならないというゲームです。1、2、Fizz、4、Buzz、6……のように順に言わなければならないわけで、これがやってみると結構難しい。でも、プログラムを組めば、絶対に正解できます。
……プログラムに間違いがなければ、だけどな。
とりあえず、1〜100まで数えてみる
前章で学んだループを使用すれば、1〜100まで表示するプログラムを作るのは簡単です。こんな感じ。
class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 100; ++i) {
System.out.println(i);
}
}
}
「1から」なので、初期値を1にするためにint i = 1;
に、「100まで」なので、ループの条件が100以下になるようにi <= 100;
にしました。これで1〜100までの数字が表示されます。
少し書いたら実行するのが、プログラミングの極意
さて、プログラミング未経験者の誤解として、「プログラミングできる人はいきなり正しいプログラムを書ける」というのがあります。これは完全に間違いで、どんなすごいプログラマーでも余裕で間違えます。プログラミングに慣れていても文法間違えはなくなりませんし、先のプログラムの例で言えば0から始めたり99でループが終わってしまったりします。
ではどうしているかというと、プログラミングできる人は、こまめに実行して間違いがないことを確認します。FizzBuzzのプログラムを作りなさいと言われた場合、本稿でやっているようにとりあえず1〜100を表示するだけ、FizzもBuzzもFizzBuzzもやらない単純なプログラムを作って実行して間違いがないことを確認して、その後に、FizzやBuzzやFizzBuzzの処理を書いていきます。このようにすれば、必ず間違いをおかす我々人間でも、確実にプログラムを作成することができるんですよ。
この逆をやるのは、つまりいきなりプログラム全体を書くのは、絶対にやっては駄目。コンピューターは間違いに不寛容で、セミコロンを忘れただけでも駄目ですし、変数名の大文字と小文字を間違えたら異なる変数と思い込んでそんな変数は知らないと文句を言ってきます。一つでも間違いがあるとコンパイルができなくて、いっぱいプログラムを書いたらいっぱいミスをするので、そのいっぱいのミスを全部修正しないとコンパイルしてプログラムを動かすことができません。
文法的に正しく修正できたのでコンパイルできてプログラムを動かせたとしても、コンピューターはプログラムに書いた通りにしか動作しないので、お題の通りに動くかは分かりません。先のプログラムでint i = 0;
と書いたら、もう絶対に0から始めちゃうわけ。このような間違いを全て修正しないと正しく動作しないのですけど、いっぱいプログラムを書いてしまうとどこが間違いなのかを探すのはとても大変になります。大変な思いはしたくないので、だから、少しプログラムを書いて実行して、間違いを探す範囲をその少しのプログラムという小さな範囲にするというわけ。
プログラミング初心者のうちは、一行書いたらコンパイルして文法ミスがないことを確認する、二行書いたらコンパイルして実行して処理内容に間違いがないことを確認する、くらいが丁度良いと思いますよ。
条件分岐を使ってみる
閑話休題。1〜100まで数え上げるのができましたので、次は、3の倍数のときは数字ではなくてFizzと表示する処理を追加してみましょう。〇〇ならば△△するという処理は、if
文で実現します。こんな感じ。
class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 100; ++i) {
if (i % 3 == 0) { // 3の倍数なら
System.out.println("Fizz");
} else { // そうでなければ
System.out.println(i);
}
}
}
}
if
の後ろの括弧の中の条件が満たされたら中括弧の中を、そうでなければelse
の後の中括弧の中が実行されるというわけ。%
は、割り算した余りを計算するという意味になります。3で割った余りが0なら、3の倍数ですよね? その場合はFizzを表示して、そうでなければ数字をそのまま表示するというわけ。このプログラムをう動かしてみると、3の変わりにFizzが表示されることが分かります。
で、このまま調子にのって、5の倍数のときにBuzz、3と5の倍数のときにFizzBuzzと表示するif
文を追加してみました。結果はこんな感じになったのですが、気をつけてください、このプログラムは正しく動作しません。
class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 100; ++i) {
if (i % 3 == 0) { // 3の倍数なら
System.out.println("Fizz");
} else if (i % 5 == 0) { // 5の倍数なら
System.out.println("Buzz");
} else if (i % 3 == 0 && i % 5 == 0) { // 3の倍数、かつ、5の倍数なら
System.out.println("FizzBuzz");
} else { // そうでなければ
System.out.println(i);
}
}
}
}
まずは文法の話をしておきますと、if (条件)
が満たされない場合向けにさらに条件分岐したい時は、else if
と書きます。あと、複数の条件を「かつ(AND)」でつなげたい場合は、&&
と書きます。
で、上のプログラムでは3の倍数のときと5の倍数のときと3と5の倍数のときの条件分岐を書いていて、3の倍数ではFizz、5の倍数のときはBuzzと表示されるのですけど、3と5の倍数である15のときにFizzBuzzと表示されずにFizzと表示されてしまいます……。
これはなぜかというと、プログラムは上から順番に実行されるためです。i
が15の場合でループの中括弧の中を上から見ていくと、15 % 3 == 0
なので最初のif
文の条件が満たされて、System.out.println("Fizz");
が実行されてFizzが表示されてしまったというわけ。else if (i % 3 == 0 && i % 5 == 0)
までやってこないので、FizzBuzzが表示されることはありません。
じゃあどうすればよいかというと、3と5の倍数の判定を先に持ってくればよいわけ。こんな感じです。
class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 100; ++i) {
if (i % 3 == 0 && i % 5 == 0) { // 3の倍数、かつ、5の倍数なら
System.out.println("FizzBuzz");
} else if (i % 3 == 0) { // 3の倍数なら
System.out.println("Fizz");
} else if (i % 5 == 0) { // 5の倍数なら
System.out.println("Buzz");
} else { // そうでなければ
System.out.println(i);
}
}
}
}
これで、15や30でFizzBuzzが表示されるようになりました! このプログラムを改造すれば、3の倍数と3がつく数(i % 3 == 0 || i % 10 == 3 || i / 10 == 3
)で阿呆になる「世界のナベアツ」を作れますのでぜひやってみてください(30〜39の阿呆連発がなかなか面白いです)。お疲れさまでした。