【FizzBuzzで遊ぼう】PythonからC言語まで|定番問題をコードパズルにしてみた | UNIX Cafe

* 当サイトでは、コンテンツの一部に広告を掲載しています。

System Note $ cat /proc/ai-disclosure

本記事の構成および論理分析にはAI(人工知能)を使用しています。情報の正確性は、システム管理者(UNIXユーザー)による手動検証済みです。

【FizzBuzzで遊ぼう】PythonからC言語まで|定番問題をコードパズルにしてみた | UNIX Cafe

プログラミングを学んだことがある人なら、誰もが一度は耳にする定番の「FizzBuzz(フィズバズ)」。 「3の倍数でFizz、5の倍数でBuzz、15の倍数でFizzBuzzと出力する」という、一見すると非常にシンプルなミニゲームです。

私の場合は2000年頃にDTPの現場からWebの世界に入りましたので、本格的にプログラミングの学習をしたわけでもないのですが、たまたま見かけたFizzBuzzの話題をきっかけに、GeminiにFizzBuzzってなに?と質問して教えてもらっていくうちに、面白いコードに出会いました。今回は、そのパズルのような解法を紹介します。

目次

FizzBuzzってなに?

本題に入る前に、少しだけFizzBuzzについて調べたことを紹介します。

ゲームとしてのルーツ:19世紀前半の数え遊び

FizzBuzzそのものとまったく同じ形ではありませんが、19世紀前半には、特定の数字や倍数のときだけ別の言葉を言う数え遊びがすでにありました。

たとえば、1832年頃の『The Little Girl’s Own Book』には、7を含む数や7の倍数のときに「Buz」と言う遊びが掲載されています。現在のFizzBuzzとはルールが違いますが、「数を順番に数えながら、条件に合う数字だけ別の言葉に置き換える」という考え方はよく似ています。

  • 古い例:1830年代頃の子供向けの数え遊び
  • 当時の名前:「Buz」など
  • 現在のFizzBuzzとの関係:直接同じルールではなく、原型に近い数え遊び

その後、19世紀後半にも「Fiz」「Buz」「Buzz」「Fuzz」など、似た形式の数え遊びがいくつか見られます。現在のプログラミング問題としてのFizzBuzzは、こうした古い数え遊びの流れを受け継いだものと考えると分かりやすいです。

プログラミング問題としての発祥:2007年

こうした数え遊びの考え方を、「プログラマの採用テストに使えるぞ!」という形でシステムの世界に広めた人物がいます。

  • 時期: 2007年1月24日 + 2007年2月26日・27日
  • 作者: イムラン・ガユール(Imran Ghory)というエンジニアが、採用テスト用の課題として紹介しました。
  • 紹介・拡散: 著名なブロガーのジェフ・アトウッド(Jeff Atwood)がCoding Horrorで取り上げ、広く知られるきっかけになりました。

イムランが自身のブログ(Imran on Tech)で「開発者を見つけるためにFizzBuzzを使っている」という記事を書いたことがきっかけで、 それを、プログラミング界隈で超有名なブログ『Coding Horror』を運営していたジェフ・アトウッドが「Why Can’t Programmers… Program?」という衝撃的なタイトルのエッセイで紹介しました。

26 Feb 2007 — 3 min read — こちらは、Jeff AtwoodがCoding HorrorでFizzBuzzを紹介した記事です。記事の冒頭では、Reginald Braithwaiteの指摘を読んで驚いた、という流れから話が始まります。

27 Feb 2007 — 2 min read — こちらが続編の記事です。FizzBuzzをLed ZeppelinのStairway to Heavenに例えています。

FizzBuzzの基本ルール

1から順番に数を数え上げていく途中で、特定の条件のときに数字の代わりに指定された言葉を発する(出力する)というルールです。

  • 3の倍数 のときは、数字の代わりに “Fizz” と言う。
  • 5の倍数 のときは、数字の代わりに “Buzz” と言う。
  • 3と5の両方の倍数(つまり15の倍数) のときは、数字の代わりに “FizzBuzz” と言う。
  • それ以外の数字は、そのまま数字を言う。

1から15までの出力例

実際に並べてみると、こんな感じの流れになります。

出力理由
11通常の数字
22通常の数字
3Fizz3の倍数
44通常の数字
5Buzz5の倍数
6Fizz3の倍数
1414通常の数字
15FizzBuzz3と5の公倍数(15の倍数)

その1:まずは普通に書いてみるFizzBuzz(Python)

まずは一番お行儀が良く、読みやすいスタンダードなコードをPythonで見てみましょう。

viなどのエディタを使って、FizzBuzz.py という名前でファイルを作成します。

for i in range(1, 16):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

ファイルを保存して実行します。

python3 FizzBuzz.py

プログラムを実行すると、結果はこうなります。

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

💡 このコードのパズル要素

このコードの肝は条件の順番です。プログラムは上から順番に条件を評価していくため、最も条件が厳しく範囲の狭い「15の倍数」を最初に判定します。もし最初に「3の倍数」を判定してしまうと、数字の「15」が来た時に「3で割り切れるからFizzだ!」と判定され、その下の「15の条件」まで辿り着かなくなってしまうのです。

その2:文字列をつなげて遊ぶFizzBuzz(Python)

if - elif の塊がちょっと不格好だな。と感じたら、文字列を結合していくこんなアプローチもあります。

FizzBuzz_short.py という名前でファイルを作成します。

for i in range(1, 16):
    result = ""
    if i % 3 == 0: result += "Fizz"
    if i % 5 == 0: result += "Buzz"
    print(result or i)

ファイルを保存して実行します。

python3 FizzBuzz_short.py

プログラムを実行すると、結果はこうなります。

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

💡 このコードのパズル要素

15のときは、Fizz と Buzz が順番に文字結合されて自動的に FizzBuzz になります。最後の print(result or i) は、Pythonの「空文字 “” は偽(False)とみなされる」という性質を利用し、3でも5でもない時は数字をそのまま出すという、ちょっとスマートなテクニックです。

その3:C言語で書いてみるFizzBuzz

つづに、一番オーソドックスで、読みやすいスタンダードなコードをC言語で見てみましょう。

viなどのエディタを使って、FizzBuzz_basic.c という名前でファイルを作成します。

#include <stdio.h>

int main(void) {
    int max_num = 15;

    for (int i = 1; i <= max_num; i++) {
        // 1. 最も条件の厳しい「15の倍数」を最初に判定
        if (i % 15 == 0) {
            printf("FizzBuzz\n");
        }
        // 2. 次に「3の倍数」を判定
        else if (i % 3 == 0) {
            printf("Fizz\n");
        }
        // 3. その次に「5の倍数」を判定
        else if (i % 5 == 0) {
            printf("Buzz\n");
        }
        // 4. どれにも当てはまらない場合は数字をそのまま出力
        else {
            printf("%d\n", i);
        }
    }

    return 0;
}

ファイルを保存してコンパイルします。

gcc FizzBuzz_basic.c -o FizzBuzz_basic

コンパイルしたファイルを実行します。

./FizzBuzz_basic

プログラムを実行すると、結果はこうなります。

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

💡 このコードのパズル要素

このコードの肝も第1問と同じで条件の順番です。プログラムは上から順番に条件を評価していくため、最も条件が厳しい「15の倍数」を最初に判定するのが鉄則です。もし先に「3の倍数」を判定すると、15が来たときに「3の条件」に吸い込まれ、下の15の処理まで辿り着かなくなります。

その4:printf一発で遊ぶFizzBuzz(C言語)

ここからが本題です。C言語の「三項演算子(?:)」をこれでもかとネスト(入れ子)にし、printf の中にすべてを詰め込んだワンライナーがこちらです。

FizzBuzz.c という名前でファイルを作成します。

#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 15; i++) {
        printf(i % 15 == 0 ? "FizzBuzz\n" :
               i % 3  == 0 ? "Fizz\n" :
               i % 5  == 0 ? "Buzz\n" : "%d\n", i);
    }
    return 0;
}

ファイルを保存してコンパイルします。

gcc FizzBuzz.c -o FizzBuzz

コンパイルしたファイルを実行します。

./FizzBuzz

プログラムを実行すると、結果はこうなります。

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

💡 悪魔的ハックの裏側

このコード、実は printf の第一引数(書式文字列)を三項演算子で丸ごと切り替えているんです。

printf( 【三項演算子で選ばれた文字列】 , i );

15、3、5の倍数のときは、それぞれ "FizzBuzz\n" などの文字が選ばれます。C言語の printf は、フォーマット指定子(%dなど)がない文字列を渡された場合、後ろにそっと添えられている引数 , i を完全に無視して文字だけを出力する仕様になっています。

そして、どれにも当てはまらない数字のときだけ、最後の砦である "%d\n" が選ばれ、後ろの i がカチッと嵌まって数字が出力される。

C言語の「引数が余分にあってもエラーにしない」という大雑把(?)で懐の深い仕様を逆手に取った、1行パズルです。

実際にmacOSのターミナルで叩いてみた

手元にある、2001年9月30日初版の『やさしいC』の時代(C89規格)だと、変数は必ず関数の「一番最初」で宣言しなければなりませんでした。しかし、現代のC言語(C99以降)なら、for (int i = 1; ...) のようにその場で宣言する書き方が通ります。

実際に手元の環境(macOSのzsh)で gcc を使ってコンパイルし、実行してみた結果がこちらです。

works_c % gcc FizzBuzz.c -o FizzBuzz
works_c % ./FizzBuzz                 
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

エラーもなく、小気味よくターミナルに結果が流れた瞬間は最気持ちが良いですね。

まとめ:FizzBuzzは小さなコードパズルになる

同じ結果を画面に出すだけでも、言語の特性やアイデア、そしてちょっとした好奇心で、コードの景色はこれだけガラリと変わります。

プログラミングって、ただの堅苦しいシステム構築の手段ではなく、ルールの中でどれだけ楽しく遊べるかという「最高のパズル」なんだと、改めて実感させられました。

みなさんも、手元の古い技術書をめくりながら、現代のターミナルでちょっとした「コードの悪戯」を楽しんでみてはいかがでしょうか?

用途ごとに選ぶ Pythonのおすすめ本

用途ごとに選ぶ C言語のおすすめ本

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

目次