[個人用ページ] :
一言 「FizzBuzz問題」

初出: 2007/08/22 T.Shirai
更新: 2007/08/28 T.Shirai

 FizzBuzz問題というものがあるらしい.
 http://oku.edu.mie-u.ac.jp/~okumura/blog/node/1531
 http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm

 要するに,「はい,私はプログラムを書けます」というプログラマ200人のうち199人は使い物にならない,ということを言いたいらしいですね.多少の誇張はありますが,プログラミング言語を知っていることと,真っ当なプログラムを書けることとは異なるという意味で,これはとても納得できる指摘です.それをチェックする課題がFizzBuzz問題.つまり以下の課題を与えた場合に,どれくらいの短時間でプログラムを完成させられるのかをそのプログラマの能力を測る指標の一つにできるということです.その課題とは,単純なものです,

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

 試される能力を適当にまとめると...

(ラピッドプロトタイピング能力)

取り敢えず与えられた仕様に従って動くプログラムを迅速に作成できる.

(デバッグ能力)

一発で動くとは限りません.如何に速く問題を発見し,取り除くことができるのか.

(安全性)

デバッグ能力にも関わりますが,プログラムが正しく動いていることを確認する機能を組み込めるかどうか.プログラムは動けばなんらかの答えを出します.でも,それが正しいという保証はありません.

(拡張性)

与えられた課題は1から100までを値の範囲としていますが,じゃあ,値の範囲を200まで増やそう,2の倍数の時は「Hoo」とプリントしろといわれたら?



(プログラム1):一番正直なプログラム
#include <stdio.h>
void main(void)
{
    int i, flag;
    for (i = 1; i <= 100; i++) {
        flag = 0;
        if (!(i % 3)) {
            printf("Fizz");
            flag = 1;
        }
        if (!(i % 5)) {
            printf("Buzz");
            flag = 1;
        }
        if (!flag) printf("%d", i);
        printf("\n");
    }
}


(プログラム2):文字列関数を使用するとシンプルに

#include <stdio.h>
#include <string.h>

void main(void)
{
    int  i;
    char str[9];
    for (i = 1; i <= 100; i++) {
        str[0] = '\0';
        if (!(i % 3)) strcat(str, "Fizz");
        if (!(i % 5)) strcat(str, "Buzz");
        if (str[0] == '\0') printf("%d\n", i);
            else            printf("%s\n", str);
    }
}


(プログラム3): switch-case文を使ってみると

#include <stdio.h>

void main(void)
{
    int  i, flag;
    for (i = 1; i <= 100; i++) {
        flag = 0;
        if (!(i % 3)) flag += 3;
        if (!(i % 5)) flag += 5;
        switch (flag) {
          case 0 : printf("%d\n", i);    break;
          case 3 : printf("Fizz\n");     break;
          case 5 : printf("Buzz\n");     break;
          case 8 : printf("FizzBuzz\n"); break;
          default: printf("Error!\n");   break;
        }
    }
}


(プログラム4):配列を使って3の倍数,5の倍数をチェックする(段々といかがわしいコードになる)

#include <stdio.h>

#define MAX_NUMBER  (100)
void main(void)
{
    int  i;
    char flag[MAX_NUMBER];
    for (i = 0; i < MAX_NUMBER; i++)  flag[i]  = 0;
    for (i = 2; i < MAX_NUMBER; i+=3) flag[i] += 3;
    for (i = 4; i < MAX_NUMBER; i+=5) flag[i] += 5;
    for (i = 0; i < MAX_NUMBER; i++) {
        switch (flag[i]) {
          case 0 : printf("%d\n", i);    break;
          case 3 : printf("Fizz\n");     break;
          case 5 : printf("Buzz\n");     break;
          case 8 : printf("FizzBuzz\n"); break;
          default: printf("Error!\n");   break;
        }
    }
}


(プログラム5):ファイルを使用しよう.

#include <stdio.h>

#define MAX_NUMBER  (100)

void fout(int num, char *str)
{
    FILE *fp;
    char fname[16];

    sprintf(fname, "%d.txt", num);
    if ((fp = fopen(fname, "at")) != NULL) {
        fprintf(fp, " %s", str);
        fclose(fp);
    }
    return;
}

void main(void)
{
    FILE *fp;
    int  i;
    char fname[16], str[16], str1[16], str2[16];

    for (i = 3; i <= MAX_NUMBER; i+=3) fout(i, "Fizz");
    for (i = 5; i <= MAX_NUMBER; i+=5) fout(i, "Buzz");
    for (i = 1; i <= MAX_NUMBER; i++) {
        sprintf(fname, "%d.txt", i);
        if ((fp = fopen(fname, "rt")) == NULL) printf("%d\n", i);
          else {
            if (fgets(str, 15, fp) == NULL) break;
            str1[0] = str2[0] = '\0';
            sscanf(str, "%s%s", str1, str2);
            printf("%s%s\n", str1, str2);
            fclose(fp);
        }
    }
}

ただし,実行前にフォルダ内の拡張子txtのファイルを全て削除すること!


(プログラム6):フィルタープログラム

・fizzbuzz6a.c

#include <stdio.h>

#define MAX_NUMBER  (100)
void main(void)
{
    int  i;
    for (i = 1; i <= MAX_NUMBER; i++) fprintf(stdout, "%d\n", i);
}

・fizzbuzz6b.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
    char str[16], nstr[16];
    while (fgets(str, 15, stdin) != NULL) {
        *strstr(str, "\n") = '\0';
        if (sscanf(str, "%s", nstr) == 0) {
            fprintf(stdout, "Error!\n");
            break;
        } else {
            if (atoi(nstr) % 3) fprintf(stdout, "%s\n", str);
                else            fprintf(stdout, "%s Fizz\n", str);
        }
    }
}

・fizzbuzz6c.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
    char str[16], nstr[16];
    while (fgets(str, 15, stdin) != NULL) {
        *strstr(str, "\n") = '\0';
        if (sscanf(str, "%s", nstr) == 0) {
            fprintf(stdout, "Error!\n");
            break;
        } else {
            if (atoi(nstr) % 5) fprintf(stdout, "%s\n", str);
                else            fprintf(stdout, "%s Buzz\n", str);
        }
    }
}

・fizzbuzz6d.c

#include <stdio.h>

void main(void)
{
    char str[16], str1[16], str2[16], str3[16];
    while (fgets(str, 15, stdin) != NULL) {
        str1[0] = str2[0] = str3[0] = '\0';
        if (sscanf(str, "%s%s%s", str1, str2, str3) == 1) printf("%s\n", str1);
            else printf("%s%s\n", str2, str3);
    }
}

 それぞれコンパイルし,コマンドプロンプトで,fizzbuzz6a | fizzbuzz6b | fizzbuzz6c | fizzbuzz6d とパイプで繋いで実行.fizzbuzz6aが1から100の数字を発生し,fizzbuzz6bが3の倍数をチェックし,fizzbuzz6cが5の倍数をチェックし,fizzbuzz6dで最終結果を整形して出力.


(プログラム7):文字列のテンプレートを利用する.

#include <stdio.h>

#define MAX_NUMBER  (100)

void main(void)
{
    int  i;
    char str_buf[4][16] = {"Fizz", "Buzz", "FizzBuzz"};
    char flag[MAX_NUMBER];

    for (i = 1; i <= MAX_NUMBER; i++) {
        flag[i - 1] = 0;
        if (!(i % 3)) flag[i - 1] += 1;
        if (!(i % 5)) flag[i - 1] += 2;
    }
    for (i = 1; i <= MAX_NUMBER; i++) {
        if (flag[i - 1] == 0) printf("%d\n", i);
          else                printf("%s\n", str_buf[flag[i - 1] - 1]);
    }
}


(プログラム8):カウントダウンタイマーを使用する(忘れていたので8/27に追加)

#include <stdio.h>

#define MAX_NUMBER  (100)

void main(void)
{
    int i, flag = 0;
    int c3 = 3;
    int c5 = 5;
    for (i = 1; i <= MAX_NUMBER; i++, flag = 0) {
        if (--c3 <= 0) { c3 = 3; printf("Fizz"); flag = 1; }
        if (--c5 <= 0) { c5 = 5; printf("Buzz"); flag = 1; }
        if (!flag) printf("%d", i);
        printf("\n");
    }
}

(プログラム9):3の倍数は各桁の数字を足した結果が3の倍数,5の倍数は下一桁が0か5(8/28に追加)

#include <stdio.h>

#define MAX_NUMBER  (100)

int fizz3(int num)
{
    int sum = 0;
    if (num < 0) num *= -1;
    do {
        sum += num - num / 10 * 10;
        while (sum >= 3) sum -= 3;
    } while (num /= 10);
    if (sum) return 0; else {
        printf("Fizz");
        return 1;
    }
}

int buzz5(int num)
{
    if (num < 0) num *= -1;
    num -= num / 10 * 10;
    if ((num != 0) && (num != 5)) return 0; else {
        printf("Buzz");
        return 1;
    }
}

void main(void)
{
    int i;
    for (i = 1; i <= MAX_NUMBER; i++) {
        if (!(fizz3(i) + buzz5(i))) printf("%d", i);
        printf("\n");
    }
}


(プログラム10):3の倍数は各桁の数字を足した結果が3の倍数,5の倍数は下一桁が0か5の文字列バージョン(8/28に追加)

#include <stdio.h>
#include <string.h>

#define MAX_NUMBER  (100)

int fizz3(int num)
{
    char str[16], *ptr;
    int  sum = 0;
    if (num < 0) num *= -1;
    sprintf(str, "%d", num);
    for (ptr = &str[0]; *ptr != '\0'; ptr++) {
        sum += *ptr - '0';
        while (sum >= 3) sum -= 3;
    }
    if (sum) return 0; else {
        printf("Fizz");
        return 1;
    }
}

int buzz5(int num)
{
    char str[16], c;
    if (num < 0) num *= -1;
    sprintf(str, "%d", num);
    c = str[strlen(str) - 1];
    if ((c != '0') && (c != '5')) return 0; else {
        printf("Buzz");
        return 1;
    }
}

void main(void)
{
    int i;
    for (i = 1; i <= MAX_NUMBER; i++) {
        if (!(fizz3(i) + buzz5(i))) printf("%d", i);
        printf("\n");
    }
}

取り敢えずいま思い付くパターンは全て出し尽くした.他にも何か別の発想のコーディングは無いかな?

<戻る>