2009年1月25日

俺はFizzBuzz問題を解ける方のプログラマなんだぜ

 プログラマの採用試験において、まず簡単なプログラムを短時間で紙に書かせてみることで能力を計り、面接の手間を省こうというアイディアがあるのだそうだ。(((( ;゚Д゚)))ガクガクブルブル

■ FizzBuzz問題 (制限時間2分)
1から100までの数をプリントするプログラムを書け。
ただし3の倍数のときは数の代わりに「Fizz」と、
5の倍数のときは「Buzz」とプリントし、
3と5両方の倍数の場合には「FizzBuzz」とプリントすること。


自分が就職面接でこの問題を出されたらどうなるか考えてみました。

面接官「この紙に書いてあるプログラムを書いてください」
俺「(゚Д゚)ハァ?」 ←間違いなく第一声はコレ。
俺「下の余白に書けばいいんですね?」
面接官「はい」
俺「・・・はいはい」 ←問題文を読んでる最中に絶対言う。

for (int i = 1; i <= 100; i++)
{
System.Console.WriteLine("{0}", i);
}

まずサラサラっと大枠を書きあげます。c⌒っ*゚∀゚)っφサラサラ
※ここではC#で書いてますが、実際に考えてるときはC言語です。

for (int i = 1; i <= 100; i++)
{
if (i % 3 == 0)
System.Console.WriteLine("Fizz");
else if (i % 5 == 0)
System.Console.WriteLine("Buzz");
else if (i % 3 == 0 && i % 5 == 0)
System.Console.WriteLine("FizzBuzz");
else
System.Console.WriteLine("{0}", i);
}

次に問題文を読みながらif文を書き足していきます。
ここまででおよそ1分でしょうか。(゚Д゚)y─┛~~

 上記のプログラムを頭の中で走らせると、"FizzBuzz"まで辿り着かずに"Fizz"が出力されることに気付くので訂正します。Σ(゚д゚lll)アブネ

for (int i = 1; i <= 100; i++)
{
if (i % 3 == 0 && i % 5 == 0)
System.Console.WriteLine("FizzBuzz");
else if (i % 3 == 0)
System.Console.WriteLine("Fizz");
else if (i % 5 == 0)
System.Console.WriteLine("Buzz");
else
System.Console.WriteLine("{0}", i);
}

 これでひとまず完成。 時間はまだ残ってるでしょうから、実行できるよう体裁を整えつつ「何か引っ掛けでもあるんじゃないか?」と疑いの目を向けてみることにします。(¬_¬)・・・

class FizzBuzz
{
public static void Main()
{
for (int i = 1; i <= 100; i++)
{
if (i % 15 == 0) // if(i % 3 == 0 && i % 5 == 0)と同義
System.Console.WriteLine("FizzBuzz");
else if (i % 3 == 0)
System.Console.WriteLine("Fizz");
else if (i % 5 == 0)
System.Console.WriteLine("Buzz");
else
System.Console.WriteLine("{0}", i);
}
}
}

できました。∩( ・ω・)∩ ばんじゃーい

 ここで「3の倍数かつ5の倍数って15の倍数ってことじゃん」と2分以内に気付くのはたぶん無理かな。 でも気付かなくても何ら問題ないね。 つかむしろ蛇足でしょう。( ゚д゚)、ペッ

問題文(仕様)に書かれている数値は「1」、「100」、「3」、「5」だけですから、「15」を持ちだすなら根拠をコメントに記載すべきだと思います。 もしそれをしないプログラマに出会ったら、そいつの履歴書に「インテリ馬鹿」とコメントしてあげてください。


■ 1行縛り(ワンライナー)

 ときにインテリ馬鹿より迷惑な存在となるのがギーク
もう貴方には誰もついていけません。( ´∀`)σ)∀`)

class FizzBuzz
{
public static void Main()
{
for (int i = 1; i <= 100; i++)
System.Console.WriteLine(
(i % 15 == 0 ? "FizzBuzz"
: i % 3 == 0 ? "Fizz"
: i % 5 == 0 ? "Buzz"
: "{0}"), i);
}
}

 基本的に「1行で書け=三項演算子を使え」なので、素直にif文を三項演算子に置き換えてやれば1行のプログラムになります。(・∀・)カンタン!!
三項演算子は「?」がTHENで「:」がELSEと覚えておくと良いでしょう。

 ところでif文のプログラムと三項演算子のプログラムを読み比べてみると、if文の方は「15の倍数なら、"FizzBuzz"を出力する」、三項演算子の方は「出力する、15の倍数なら"FizzBuzz"を」となりませんか? なんだか日本語と英語の文法の違いに似ていますよね。 俺にはif文の方が圧倒的に読みやすいです。'`,、('∀`) '`,、


■ 剰余を用いない縛り

 倍数とかn回毎にと言われたら殆どのプログラマが「%」を使うでしょう。 だから敢えて「%」を使うなという嫌な縛り。これを2分以内に解くのはシンドイですね。

class FizzBuzz
{
public static void Main()
{
int c3 = 3;
int c5 = 5;

for (int i = 1; i <= 100; i++)
{
if (i == c3 && i == c5)
{
System.Console.WriteLine("FizzBuzz");
c3 += 3;
c5 += 5;
}
else if (i == c3)
{
System.Console.WriteLine("Fizz");
c3 += 3;
}
else if (i == c5)
{
System.Console.WriteLine("Buzz");
c5 += 5;
}
else
System.Console.WriteLine("{0}", i);
}
}
}

「変数を増やさないで何とか・・・」などと考えてしまったら時間切れコースです。 誰も求めていない何処かにある美しい答えを探し求めてはいけません。


■ 分岐を用いない縛り

 分岐を無くせば処理が速くなるとか何とか。
高齢プログラマに多いですよね、頼まれなくても関数ポインタとか使いだす人。
配列の初期化が遥か彼方で行われいない限り何も言いますまい。(;^ω^)

class FizzBuzz
{
public static void Main()
{
string[] fb = { "FizzBuzz", "{0}", "{0}", "Fizz", "{0}",
"Buzz", "Fizz", "{0}", "{0}", "Fizz",
"Buzz", "{0}", "Fizz", "{0}", "{0}" };

for (int i = 1; i <= 100; i++)
System.Console.WriteLine(fb[i % 15], i);
}
}



■ 繰り返しを用いない縛り

 縛りでなくただの厨二的ヤケクソですが。(;^ω^)
FizzBuzz問題が解けずに「printf文を100個書けばいいんだろ!」となったとき、それでも正解だけど書き切れなければ恥を晒すだけです。

そこで賢くマクロを使って記述量を減らしてみました。これなら2分以内に書けるかも? あとマクロを使ってますから手早く"Fizz"を"Bizz"に変更できるなど、きちんと変更容易性も確保されていますよ(笑)

#include <stdio.h>

#define P(x) printf("%d\n", x);
#define F printf("Fizz\n");
#define B printf("Buzz\n");
#define FB printf("FizzBuzz\n");

int main(void)
{
P( 1) P( 2) F P( 4) B F P( 7) P( 8) F B P(11) F P(13) P(14) FB
P(16) P(17) F P(19) B F P(22) P(23) F B P(26) F P(28) P(29) FB
P(31) P(32) F P(34) B F P(37) P(38) F B P(41) F P(43) P(44) FB
P(46) P(47) F P(49) B F P(52) P(53) F B P(56) F P(58) P(59) FB
P(61) P(62) F P(64) B F P(67) P(68) F B P(71) F P(73) P(74) FB
P(76) P(77) F P(79) B F P(82) P(83) F B P(86) F P(88) P(89) FB
P(91) P(92) F P(94) B F P(97) P(98) F B /* 100 */

return 0;
}

0 件のコメント:

コメントを投稿