今日の内容
- FizzBuzz?なにそれ
- C言語とRustでFizzBuzz問題に挑戦しよう
- ループ処理
- 条件分岐処理
はじめに
前回は画面出力について学びました。今回はFizz Buzz問題に挑戦したいと思います。
Fizz Buzzとは、「1」から順に数字を発言していき、その数字が3の倍数であれば代わりに「Fizz」と、5の倍数であれば「Buzz」と、3の倍数かつ5の倍数であれば代わりに「FizzBuzz」と発言するというゲームです。
そして、このゲームをコンピュータに表示させることができるかどうかで、その人がプログラムを書けるかどうかを判断する、という問題が 『Fizz Buzz問題』 です。
初心者専用の問題に見えますが、実は縛りを追加することで上級者も悩める問題となっています。
Fizz! Buzz! FizzBuzz!!!!!!
さっそくFizz Buzz問題に挑んでみましょう。
基本的には1から順に数字を出力すればよいですね。まずはそのプログラムを書いてみます。
C言語では以下のようになります。無限に出力するわけにはいかないので、15まで表示させています。
#include <stdio.h>
int main(){
int i;
for(i=1; i<=15; i++) printf("%d ", i);
return 0;
}
/******** 出力結果 *******
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
*************************/
for文を使っています。1から任意の数字までに対応できるよう、ループ処理を行っています。ループ処理について全く知らない方は「ループ処理とは」から学んでください。
C言語ではループ処理として主にfor文、while文、do-while文があります。他に思いつくのはgotoでしょうか..。
Rustでも同じようにループ処理を用いて解きます。
fn main(){
for i in 1..16 {
print!("{} ", i);
}
}
/******** 出力結果 *******
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
*************************/
同じくfor文を使いました。ではさっそくfor文について学ぼう...と言いたいところですが、その思考をいったん放置してください。とりあえず完成させて、部分にわけて解説していきます。というわけで、完成品がこちらです。
エスケープシーケンスを利用して、1出力ごとに改行して表示しています。
/*C言語*/
#include <stdio.h>
int main(){
int i;
for(i=1; i<=15; i++){
if(i % 15 == 0) printf("FizzBuzz\n");
else if(i % 3 == 0) printf("Fizz\n");
else if(i % 5 == 0) printf("Buzz\n");
else printf("%d\n", i);
}
return 0;
}
/******** 出力結果 *******
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
*************************/
/*Rust*/
fn main(){
for i in 1..16 {
if i % 15 == 0 {println!("FizzBuzz");}
else if i % 3 == 0 {println!("Fizz");}
else if i % 5 == 0 {println!("Buzz");}
else {println!("{}", i);}
}
}
/******** 出力結果 *******
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
*************************/
それでは解説していきます。まず、main関数があります。これは別名「エントリーポイント」と呼ばれ、プログラムの一番最初に実行される場所を指します。C言語やRustなどのコンパイル型言語は通常main関数がエントリーポイントとなっているため、main関数は必須になります。ただし、言語によってmain関数の定義形式が変わります。 Rustでは関数の定義が「fn 関数名(引数){中身}」となっているため、main関数は「fn main(){}」と定義します。
次に、for文です。すでに触れていますが、for文はループ処理の一つです。他にはwhile文やloop文があります。ループ処理にいくつか種類があるのには、ループの仕方に違いがあって、それを使い分けるためです。
例えば、「n回繰り返したい」ならfor文、「この条件式が成り立つ間繰り返したい」ならwhile文、「無限に繰り返したい」ならloop文などです。
今回は「15回繰り返したい」ので、for文を使うことにします。(注:loopやwhileでもできます。)for文の文法は、「for 変数 in 最初の値..最後の値+1 {中身}」となります。例えば、変数「i」が、i=1で始まって、i<16であれば「中身」を実行し、i=i+1する、を繰り返すといった感じです。そうすると、i=i+1 =16となったとき、i<16ではないので、「中身」が実行されず、結果的に「中身」は15回繰り返された..ということになります。
次に、if-else文です。if-else文は条件分岐処理の一つです。「条件分岐処理」について全く知らない方は「条件分岐処理とは」から学んでください。Rustでは、if-elseやmatchなどの条件分岐処理が用意されています。matchはC言語でのswitchに似ています。
基本的な条件分岐はif-else文で行います。「もし、この条件が真なら、この処理を行う。もし偽なら、この処理を行う」といったようなことができます。「真」と「偽」は「正しい」、「正しくない」もとい、「true」、「false」を意味します。
プログラムを見てみると、for文の中身は4行になっていますが、この4行全てが条件分岐処理になっています。上から、
「もし変数が15で割り切れるなら、"FizzBuzz"と表示する。」
「でなければ、もし変数が3で割り切れるなら、"Fizz"と表示する。」
「でなければ、もし変数が5で割り切れるなら、"Buzz"と表示する。」
「でなければ、変数を表示する。」
という意味になっています。ここでの「変数」は、for文の「変数」と同じものです。つまり、for文で変数「i」が1,2,3,4,..と増加するとき、もし変数「i」が15で割り切れるなら、"FizzBuzz"と表示する。といった感じになります。割り切れるかは剰余演算(%)を用いて計算します。if-else文の文法は、「if 条件式1 {中身}」、「else if 条件式2 {中身}」、「else {中身}」となります。順番に、「もし~なら」、「でなければ、もし~なら」、「そのどれでもないなら」となります。「else」で始まるものは、直前に「if 条件式1 {中身}」がなくてはなりません。
これで解説を終わります。
おわりに
おつかれさまでした。今回は、100DaysOfCode 三日目として、Fizz Buzz問題に挑戦してみました。
明日はfor文についてより詳しく学んでいきます。
ご精読、ありがとうございました。
おまけ
筆者が頑張って一行縛りでfizzbuzz問題に挑戦してみました。とは言っても、三項演算子がなくてブルブルしながら書いた粗悪品です...。あと!(i%15)とかもエラー出て感動しました。
fn main(){
for i in 1..16{println!("{v}",v= if i%15==0 { "FizzBuzz".to_string() } else if i%3==0 { "Fizz".to_string()} else if i%5==0 { "Buzz".to_string()}else { i.to_string()});}
}
/******** 出力結果 *******
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
*************************/