キャリア20年超。ずっとプログラマで生き延びている女のコラム。

FizzBuzzを解いてみた

»

 小飼弾氏の記事『転職活動する暇があったらブログを書け』で

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

という問題を見て、「これが書ければプログラマとして認めてもらえるのか。ハードル低っ」と思いました(ハードル下げたくて下げているわけじゃないでしょうが)。

 まあ、その時はそう思っただけだったんですけど、昨日の夜になって、試験官に「確かに正解だけどさあ」と言わせるようなものを書いてみたらどうだろう、とか思いついてしまいました。

 思いついたら、なんかもうサンプル品を書かずにはいられません(苦笑)。

 そんなわけで、日曜の午後をつぶして、「FizzBuzzをムダに難しく書いてみよう」というお題でコードをいくつか書いてみました。

 長くしようと思えばいくらでも長くできるので、試験問題ということを考慮して「5分以内でタイプできるくらいの長さ」という制約をつけて考えてみたんですけど、これがなかなか難しいんです。

 ムダに再帰を使ってみたり、ムダに配列を使ってみたり、ビット操作で何かやれないかと考えてみたりしたんですけど、なんかもっと奇抜なやり方がありそうな気がしてしかたありません。

 シンプルにしようとすれば、ある程度ルートは限られてきますけど、ムダに複雑にしようと思うと、選べるルートが増えすぎて迷うんですよ(←だったらやらなければいいのに)。

 もっとも半日でこのテーマに飽きてしまったので(←仕事がからまないと集中力が続かない)、これ以上、つっこむつもりはないんですけど。

 C/C++ っぽい解決方法を考えた結果として、ムダにポインタやメモリ操作標準関数を使って書いてみたコードを、サンプルとして載せてみます。こういうとこでコードを公開するってかなりリスキー(笑)ですが、ほんのお遊びということで細かいところには目をつぶってやってくださいませ。

 言語はANSI C/C++です。宣言等の書かなくてもわかる部分は省略してあります。あと、わざとわかりにくくするためコメントを書いていませんので、興味がおありでしたら自力で解読してください(←いやがらせ?)。

 ここ3年間というもの、Visual BASIC と SQL を使いこなすことに注力してきたため、C/C++ がものすごくヘタになってて軽~くショックでした。

int main(int argc, char* argv[])
{
  char cBuffer[65535], cTemp[10];
  int aryFizz[100], aryBuzz[100];
  int nFizzPos = -1, nBuzzPos = -1;
  char *pFizz = "Fizz", *pBuzz = "Buzz";

  memset(cBuffer, '\0', sizeof(cBuffer));

  for (int nLoop = 1; nLoop <= 100; nLoop++) {
    if ((nLoop % 3) == 0) {
      aryFizz[++nFizzPos] = (int)strlen(cBuffer);
    }
    if ((nLoop % 5) == 0) {
      aryBuzz[++nBuzzPos] = (int)strlen(cBuffer);
    }
    sprintf(cTemp, "%d\n", nLoop);
    strcat(cBuffer, cTemp);
  }

  while (true) {
    char *pTop;
    bool bFizzFlag = false, bBuzzFlag = false;
    if ((nFizzPos >= 0) && (nBuzzPos >= 0)
        && (aryFizz[nFizzPos] == aryBuzz[nBuzzPos])) {
      pTop = &cBuffer[aryFizz[nFizzPos--]];
      nBuzzPos--;
      bFizzFlag = true;
      bBuzzFlag = true;
    } else if (((nFizzPos >= 0) && (nBuzzPos < 0))
        || (aryFizz[nFizzPos] > aryBuzz[nBuzzPos])) {
      pTop = &cBuffer[aryFizz[nFizzPos--]];
      bFizzFlag = true;
    } else if (((nFizzPos < 0) && (nBuzzPos >= 0))
        || (aryFizz[nFizzPos] < aryBuzz[nBuzzPos])) {
      pTop = &cBuffer[aryBuzz[nBuzzPos--]];
      bBuzzFlag = true;
    } else {
      break;
    }

    char *pTail = (char*)memchr(pTop, '\n',
        (int)strlen(cBuffer) - (int)strlen(pTop));
    if (!pTail) {
      break;
    }
    memmove(pTop, pTail, strlen(pTail) + 1);

    if (bBuzzFlag == true) {
      memmove(pTop + (int)strlen(pBuzz), pTop, (int)strlen(pTop));
      memmove(pTop, pBuzz, (int)strlen(pBuzz));
    }
    if (bFizzFlag == true) {
      memmove(pTop + (int)strlen(pFizz), pTop, (int)strlen(pTop));
      memmove(pTop, pFizz, (int)strlen(pFizz));
    }
  }

  printf("%s", cBuffer);

  return 0;
}


 これは試験官に対するイヤがらせとしか思えません。こういうコードを書く人を会社は雇ってくれるんでしょうか? ていうか、「タイプのみでも5分以内でできるのか?」と言われそうです(ものすごく速い人なら……多分)。

 普段は、どれだけシンプルにできるか、ということに頭を痛めているんですが、どれだけ複雑にできるか、というのもやってみるとおもしろいです。まあ、くだらない遊びです。くだらないからこそ楽しいんですけどね。

Comment(89)

コメント

インドリ

こんばんは♪
私も遊んでみました♪
static void Main ( string [ ] args )
{
FizzBuzz ( 0, 101 );
}

static void FizzBuzz ( int count, int max )
{
if ( count == max ) return;
if ( count == 0 ) {
Console.WriteLine ( count.ToString ( ) );
FizzBuzz ( ( count + 1 ), max );
}
int flag = 1;
if ( ( flag = ( count % 3 ) ) == 0 ) Console.Write ( "Fizz " );
int flag1 = 1;
if ( ( flag1 = ( count % 5 ) ) == 0 ) Console.Write ( "Buzz" );
if ( flag != 0 && flag1 != 0 ) Console.WriteLine ( count.ToString ( ) );
else Console.Write ( "\n" );
FizzBuzz ( ( count + 1 ), max );
}

インドリ

おっとごめん。
return;
が抜けていた(笑)

if ( count == 0 ) {
Console.WriteLine ( count.ToString ( ) );
FizzBuzz ( ( count + 1 ), max );
return;
}

ひでみさん、おはようございます。

風邪ひいてぼーっとしているので追いきれない。もう一回寝ます。

インドリさん、パッと見た感じ、0から書いちゃうような気がしますが……。

インドリ

>インドリさん、パッと見た感じ、0から書いちゃうような気がしますが……。

ええ。C#で関数型言語チックにしたかったので知ってて0の扱いを付け加えました。
1から100までとは言っても、拡張性がなければ個人的には嫌です。
言われたとおりにしか出来ない人は開発者として如何なものかと思います。
あと、本当は関数呼び出しが巻き戻るので、returnは要らない筈なのですが、
勘違いされるかもしれないから、保守性のために必要かもしれません。
最後に、インデントが深くなるから省略しましたが、
この関数二つは勿論クラス定義内でしないとコンパイルエラーです。
Programクラス内にでも定義してお試しください。

追伸
より関数言語チックにしたい場合は、ラムダ式を使って関数を引き渡し、
高階関数にするとよいでしょう。

guest

インラインアセンブラとかでしょ


// ただアセンブラで書くんなら、ものすごく順当な課題になることに今気づいた


…MIPSとかで

インドリ

ちょっと分かり難いかもしれないので追記します。
「言われたとおりにしか出来ない人」云々は常に例外を考える事を指しています。
これは遊びだから構わないのかもしれないのですが、現場では範囲チェックが欠かせないので「予想外の値」が渡された場合も考えました。
エンドユーザーが0を指定しないとは限りません。
いえ、必ず誰かが0を指定するでしょう。
その時ちゃんと対応していないと、FizzBuzzと表示されます。
0を何で割っても0なのですからこれは間違いです。
ということで、例外をスローするのはやりすぎだと思って0を表示する事にしました。

起きた。
仕事行く前に少し。

ゼロはゼロ以外のすべての実数の倍数ですから、ゼロのときはFizzBuzzと出力すればよい。

インドリ

数学的に0は例外扱いする場合が多いと思うのですが、FizzBuzzの問題は例外扱いしなくていいのですか?

あ~り~

>インドリさん
0書いちゃうわけですね?
>>拡張性がなければ
これはわかります。しかし、仕様外のものを付け足すのはいかがかと。
何も表示しないor範囲外ということを教えるのが現時点での正解では?
『1~100まで』ですから。
仕様(要求事項)にないもの付け足して、それがいらないものだったら?
とかちょっと考えるだけで色々と問題が出てきます。
まぁ、FizzBuzzですからいいですけど・・・

>ひでみさん
C系の記憶が完全に無くなった私には大変難しいプログラムでした・・・
sprintf・・・これすら強敵でした・・・
しかし、シンプルに綺麗にスマートにするより難しくするほうが
いろんなルートができていいですね。
勉強できそうです。・・・新人にやらせようかな。

余談:
あぁ、ここのコメント見てたら思いました。。。
10:30に起きちゃうくらいの重役出勤したいな~(笑)

xeren

逆転の発想は面白いですね。こういう遊びは好きな人多そう。

でも9割方忘れたアセンブラでは全然書けませんでした。勉強しなおそうかな…

>インドリさん
(1,101)はご愛嬌として、どっちかっていうとcount > max時が問題…

guest2

100で終わるために
if ( count == max ) return;
として101を引数で渡すって・・・。

if ( count == 0 ) {
ゼロは(余計に)考慮するのにマイナスは・・・

int flag = 1;
int flag1 = 1;
・・・

センス良く難しくしたというより、
新人の気持ちになってやって見たって感じが・・・。

こんにちは

> そんなわけで、日曜の午後をつぶして、「FizzBuzzをムダに難しく書いてみよう」という
> お題でコードをいくつか書いてみました。

OK
邪悪なコードこんなのを昔に思いつきましたよ

[(filter( lambda obj:(type( obj ) != int), fragment )[-1] if filter( lambda obj:(type( obj ) != int), fragment ) else ([[reduce( partial_function, div_rep ) for div_rep in ((3, "Fizz"), (5, "Buzz"), (15, "FizzBuzz"))] for partial_function in [__import__("functools").partial( (lambda integer, divisor, replace: ((integer % divisor == 0) and replace) or integer), integer ) for integer in range( 1, 101 )]].index( fragment ) + 1)) for fragment in [[reduce( partial_function, div_rep ) for div_rep in ((3, "Fizz"), (5, "Buzz"), (15, "FizzBuzz"))] for partial_function in [__import__("functools").partial( (lambda integer, divisor, replace: ((integer % divisor == 0) and replace) or integer), integer ) for integer in range( 1, 101 )]]]

Python2.5 です。

CMP

皆さんのコードを見てふと思ったのですが、
関数を定義(設計)するときってどっちを重要視します?
A.その関数で処理を完結する
B.その関数に実機能のみを実装する
わかりにくいと思うので例を挙げれば、Aはインドリさんが記述したFizzBizz関数。
Bは引数にループカウンタを設定することで戻り値として出力する文字列を返すタイプ。「printf("%s\n",FizzBiz(iLoop));」みたいな。

私は小飼弾氏の記事を読んで、パッと頭に浮かんだのはBの方なんですよね。
夢占いじゃないけど、「Aで実装するタイプは~」「Bで実装するタイプは~」って
感じで誰か分析してもらえませんか?w

King

上手い事が思いつきません・・・。

[C#]
System.Linq.Enumerable.Range(1, 100).ToList().ForEach((a) => Console.WriteLine((a % 15 == 0 ? "FizzBuzz" : a % 3 == 0 ? "Fizz" : a % 5 == 0 ? "Buzz" : a.ToString())));

インドリ

確かに
if ( count == max ) return;
これは問題ですね(笑)
素直にcountとmaxを指定するとは限りません。
if ( count >= max ) return;
もしくはif ( count > max ) return;
ですね。
いや、count > max な場合は例外を投げるほうがいいですね。
そういえば、この問題マイナス値の場合はどうなんだろう?
一応正方向に伸びると考えたのですが・・・
もしかして、マイナス値の場合は負の方向に数えるとか?
この問題を掘り下げるのは面白そうです。
0の扱いも気になるしね。


>関数を定義(設計)するときってどっちを重要視します?
実は私、ひねくれ者なのでAB以外にも(冗談で)オブジェクト指向バージョンもちょっと考えました(笑)
「コンソール画面に出力するとは限らない!」なんてね。
他にも増加率を変化してもOKなように対応しなさいとか・・・
この問題付加条件をつけたら楽しそうですね。
まじめに答えるとBがいいと思います。
関数の機能を単一化しておかないとテスト効率も悪いし柔軟性もありません。
小さいことはいいことです。

ひでみ

こんばんわです。ひでみです。
たった1日でコメント数がえらいことになっててビックリしました。


インドリさん。

いちはやくお遊びにおつきあいくださりありがとうございます。
私としては、拡張性なんてなにもなくて FizzBuzz 以外には何も使えない、というのがこの場合おもしろいんじゃないかと思ってます。
めざすは「ムダ」ですから(笑)。
でも、どうしても拡張性を考えてしまうんですよねえ(←身に染み付いてる)。

0 以下の扱いに関しては、余りの演算子の答えに従えばいい、と単純に考えていました。


生島勘富さん。からだのおかげんはいかがですか?
具合悪い時にわざとこんがらがせたコードをほぐしてると、熱があがりそうな気がしますが。


guestさん。

すみません。アセンブラの話はまったくわかりません……。


あ~り~さん。

> sprintf・・・これすら強敵でした・・・

最初、cout を使っていて、これでは C は通らないと気づいてあわてて printf にしました。その流れで sprintf を思い出したんですが、少ししてから itoa とかいう関数もあったなあ、ということを思い出しました。
こんな基本的なことを忘れてるなんて……。

> 勉強できそうです。・・・新人にやらせようかな。

新人さんにやらせたら、それぞれの能力や個性がものすごくはっきり出そうな気がします。


xerenさん。

> 逆転の発想は面白いですね。こういう遊びは好きな人多そう。

所詮、私の考えることですから、どこかで誰かがすでにやってそうな気がしたんですが、まいっか、とか思って公開しちゃいました。(笑)


Fomalhautさん。

Python は昔やったはずなのにさっぱり思い出せません。
解読できない~。くやしい~。


CMPさん。

> 関数を定義(設計)するときってどっちを重要視します?
> A.その関数で処理を完結する
> B.その関数に実機能のみを実装する

私はどちらかというと「A」のような気がします。
まとまっていて欲しいのかな?


Kingさん。

複雑というよりはコンパクトになってる感じがします。
こういうコードを読みなれてるせいですかねえ。
私の先輩にはこの手のコードを書く方がたくさんいらっしゃいました(苦笑)。


ひいらぎさん。

おもしろい記事を教えてくださってありがとうございました。
ていうか、普通は再帰とかデザインパターンとかで解決しようと考えるのが普通なんでしょうか。
これを文字列操作問題にすりかえちゃった私は一体……。

ヴァン

Kingさんのコードにちょっと「にやっ」とした。

アセンブラなら出力はどうしようとちょっと悩んだ。

インドリさんの
>FizzBuzz ( 0, 101 );
に腹抱えて...

ひでみさん、こんにちは。

残念なことにこういうプログラムを読むのが非常に苦手です。

たぶん、キレる方の試験官です(^^;

個人的に

  FizzBuzz ( 1, 100 );

で正しく出力され、

  FizzBuzz ( 0, 101 ); // 0は"FizzBuzz"、101まで出力

  FizzBuzz ( -100, 100 ); // -100で "Buzz" -90で"FizzBuzz"

  FizzBuzz ( 100, -100 ); // エラー

となる、関数 FizzBuzz を(再帰だろうがなんだろうが)書いてくる人が一番評価が高い。
101と入れさせるのは、直感的でないので大嫌いです。

1.仕様を満たす。
2.直感的で読み易い。
3.拡張性を保っている。

の順で評価するかな……。

あくまで、個人的にです。

ポチたま

こんにちは。

> ハードル低っ
あえてそう書かれているのかと思いますが、その低いハードルが書けない人がいるということが問題なんですよね。
プログラマを名乗っていながら、FizzBuzzすら解けない人もいる、ということで。

インドリさん。

> ええ。C#で関数型言語チックにしたかったので知ってて0の扱いを付け加えました。
> 1から100までとは言っても、拡張性がなければ個人的には嫌です。
あ~り~さんも書かれていますけど、0は必要なんでしょうか。間違えて0から数えるコードを書いてしまったことに対して「拡張性」という言い訳をしているように見えますけど、違いますか?
拡張性を考えるのは良いことだと思いますし、その点でインドリさんは正しいのかもしれないですけど、それは「将来に向けて拡張しようとしたときのことを考えて」だと思うんです。現時点では「1~100」と明記されているものを、仕様にない0を勝手に追加しちゃうのは、拡張性と言うより「仕様を理解できていない」にあたる気がしますよ。

生島勘富さん。

面白い考え方ですね。自分であれば、1~100以外(例えば0や101等)が入力された場合は例外を吐くようにすると思います。
これが「与えた数」と書かれていたらまた変わったかもしれませんけど。

> 1.仕様を満たす。
> 2.直感的で読み易い。
> 3.拡張性を保っている。
この順は自分も同じですね。
100を求めるために101を指定させるっていうのは、手段のために目的を選んでないというか、本末転倒というか。

ひでみ

こんばんわです。ひでみです。


生島勘富さん。

> 残念なことにこういうプログラムを読むのが非常に苦手です。
> たぶん、キレる方の試験官です(^^;

試験官に「うが~!」って言わせようと思って書いてますので、その点では成功作になっているようです(笑)。
私も入社試験でこれを書くほどチャレンジャーではありません。

> 1.仕様を満たす。
> 2.直感的で読み易い。
> 3.拡張性を保っている。
> の順で評価するかな……。

私的には「その発想はなかった」というのがポイント高いです。
ところで、うちの見習いSE(と社長が呼んでいる)はFizzBuzzをSQLで解いてきました。
その発想はなかった……。


ポチたまさん。

> プログラマを名乗っていながら、FizzBuzzすら解けない人もいる、ということで。

だったらそういう人は何と名乗ればいいのか、と考えてみたんですが、妙案が浮かびません。
「見習い」とか「丁稚」とか? 「未経験」が正確な気がしますが。
解けないけど「プログラマ」を名乗って就職活動をしている方は、「これからがんばって勉強すればなんとかなる」と思っているのか、「採用されちゃえばこっちのもん」と思っているのか……。

Soda

>インドリさん
>0を何で割っても0なのですからこれは間違いです。

えーと、0を割れない数字がありますよ。
0÷0=0だと勘違いしている人って結構いますね(^^;

この場合、0÷3=0、0÷5=0と割り切れてます。
また、3×0=0、5×0=0と整数倍になってますよねぇ。
だから、0は3の倍数ですし、5の倍数でもあります。

0を特別に感じているのだと思いますが、倍数に関しては上記の通りです。
例外扱いする必要はないですよーと皆さんが言ってるわけです、ハイ。

>生島勘富さん
> FizzBuzz ( 100, -100 ); // エラー

FizzBuzz ( 開始, 終了 );
って考えるなら、100から始まって-100で終わるように減ってくのもありかなと。
引数で判定できるし、矛盾は無さそう・・・増加イメージが強いと直感的ではないかもしれませんが(^^;
再帰だと数値が大きくなると、スタックオーバーフローの可能性があがるのが怖いですね。

>ひでみさん
>だったらそういう人は何と名乗ればいいのか、と考えてみたんですが、妙案が浮かびません。

自称なら、やっぱりプログラマになるんじゃないですかね?
もちろん、周りの評価は別ですがw
アマグラマなんて言葉も使われたりしますがーいまどきのアマチュアはプロよりもレベル高かったりするからなぁ(^^;
まぁ、「自称プログラマ」と「自称」を強調して呼んであげればいいのではないかとw
もちろん、自慢げにしている人限定ですが(^^;

向上心がある人なら応援したいとこかなー最初は誰でもヘッポコさんなわけだしね。
といっても、そんな奴が「プログラマ」を名乗るなーって気持ちもわかるんだよねぇw
私の勤めてる会社では「アシスタントプログラマ」って肩書きが用意されてましたよ。

記事の話にもどってームダに難しくすると考えると・・・

1、倍数の判定方法を変える
 5の倍数は下1桁が0なのか5なのかを判定する。
 3の倍数は、各位の和を求め、それが1桁になるまで繰り返し、0、3、6、9になるか判定する。

2、ループをマルチスレッドで処理する
 一部でこれからの時代は並列処理だーという熱狂的な意見もあるのでw
 並列処理させることで、マルチコアなCPU搭載機での速度アップという大義名分を得られます。
 ・・・が余程大きな範囲じゃない限り速度アップしないという意味の無さも加算されます。
 結果を表示する時は、順番に並べないといけないので、結果をバッファに保存する必要があります。
 つまり、メモリもムダに使えますw

コードにするとそれなりに肥大すると思いますがーこんな感じですかね。

インドリ

全然意味わかっていない人が見受けられますね(笑)
私が表したのは「仕様に対して探りを入れられるか」と言う事です。
一語一句エンドユーザーの言葉どおりにシステムは作れるほど単純じゃありません。
仕様に不明確なところがあれば予め聞いておかないとならないのです。
この例ですと、ひとまず「0の取り扱い」、「限界値」の2つは聞いておかないとなりません。
※これは遊びだからいいのですが、後は「処理の存在理由」も聞くとよい。
こういった処に疑問を持つ/持たないが資質を表すと思います。
言葉通りに実装していては顧客満足度は高められません。
わかると思ったけどなー。
そこを楽しむために書いたのにな・・・
プログラミング遊びは仕様までしゃぶらないとね♪

King

実際に仕事でこういうものを作る場合、開始と終了の値やその他の条件は設定ファイルに持たせ、例外処理や拡張性を持たせたものになる事になると思います。
例外処理とか拡張性を考えていくと
・指定された値が数値なのか
・開始終了の大小関係あっているか、
・開始終了に指定できる数値の条件
・etc
ときりがありません。
そんなものをこの記事の答えとして考えるといくらでも難しくできます。

この記事の問題の場合、
0が「指定される」とか101以上が「指定される」という、「指定される事がある」という事自体が拡張性に当たっていると個人的には思います。
つまり「1と100が必ず指定される」前提がそこに含まれていると思います。
拡張性を全く除外した状態で、いかにコードを難しくするかという事がこの記事でおっしゃっている事だと。
(私には出来ませんでしたが・・・)

「1~100を出力するプログラムを作成せよ」
とだけ言ってるのに、受け取った実行ファイル実行したら
「例外:1~100の数値をしてください。」
とか出たら私なら「はぁ?」って思います。
0~100が出たら黙って頭を抱えます。

King

すみません、上記書き込みの記述間違いです。

> 「例外:1~100の数値をしてください。」

> 「例外:1~100の数値を指定してください。」

> 0~100が出たら黙って頭を抱えます。

> 0~100が出て理由を聞いて「僕は言われた通りにしか出来ない人じゃないんで」って言われたら、黙って頭を抱えます。

Soda

>インドリさん
>この例ですと、ひとまず「0の取り扱い」、「限界値」の2つは聞いておかないとなりません。

えーこの例だと、範囲の入力を要求されていないので不要ですよ?
今回の場合、顧客はひでみさんですよね。
顧客が拡張性は不要だと明言しているのに拡張性を語るのは、プログラマのエゴでしょう。
顧客の仕様に対し+αを考えるよりも先に、顧客が求めていることを把握することのほうが重要です。

で、まだ0のこと解らないんですね(^^;
あまり連呼すると、数学がわからないバカな人に見えますから注意したほうがいいですよ?
少なくとも3人に指摘されてるんですから・・・
ただでさえ、この記事の趣旨をわかってないように見えるのに・・・

>そこを楽しむために書いたのにな・・・

インドリさん自身が楽しんでるだけで、顧客は満足していないことに注意したほうがいいですね。
おそらく、多くの方が「仕様を勝手に変えて自己満足している」と見ていると思います。
さらには、その仕様変更が中途半端でバグ付きなんだから性質が悪い(^^;

あと、今回のインドリさんの手法は、記事内でひでみさんが触れています。
そして、それではつまらないの採用しなかったものです。
まぁ、ひでみさんが直接それを言ってしまうとアレなんで言わなかっただけなんですが・・・
過去に何度も言われていると思いますが、よく確認してからコメントすることを薦めます。

遊びにもルールがあるってことを認識して参加されるほうが、本当の意味で楽しめると思いますよ。

PS.
CodeZineであんなことがあったばかりなのに・・・
もう少し人の話を真剣に聞かないと、技術よりも重要な信用を失いますよ?

knowledge

頼むからもうちょっと手加減してください。> インドリさん
手が震えてキーボードが打てない...

DD

ここはインドリさんの無知発表会でも言いわけ発表会でもないですよ。落ち着いてください。
  ○自分が何を伝えたいのか
  ○伝えたい内容に間違いがないか
  ○後からいい訳付け加えなくても相手に伝わる文章になっているか
くらいは確認してから投稿ボタンを押してください。本当にお願いします。

CMP

話をぶった切りますが、Sodaさんの書き込みを見て昔言われたことを思い出しました。

「プログラマのプロは、プロフェッショナルとプロと同じだ。自己満足で作ってるうちはアマチュアといっしょ。まあ普通のユーザよりはできるから差し詰めパワーユーザといったところか。」

これは、私があるアプリケーションを作成し、納品検査中に仕様と異なる動作をする不具合が見つかったときに言われた一言でした。
この一言を言ってくれた先輩は、基本的に怒るということをしない人でしたが、プロとしての心構えや行動を見失ったり、忘れたときは怒鳴りつける人でした。
プログラミング(言語やアルゴリズムなど)は独学だけど、プログラマとしてはその先輩が私にとって先生というか師匠だと思ってます。(飲み会で本人そういったら潰れるまで酒飲まされましたが。そのときは言うんじゃなかったって後悔してたり(--;)

いつか、自分の部下に「CMPさんがプログラマとしての師匠です!」って言われてみたいなぁ~。100%無理だけど(大汗)。

ポチたま

さとみさん。

> だったらそういう人は何と名乗ればいいのか、と考えてみたんですが、妙案が浮かびません。
> 「見習い」とか「丁稚」とか? 「未経験」が正確な気がしますが。
見習いや丁稚だと、これから成長しますよーって感じがしますよね。
でも既に「プログラマ」を名乗ってる人は、もう成長する気がないのかな?と。
なので「似非プログラマ」あるいは「似非グラマ」とか呼んであげた方がいいかも。
Sodaさんが書かれていた「自称プログラマ」もアリかな?

インドリさん。

> プログラミング遊びは仕様までしゃぶらないとね♪
遊び、ですか・・・。
プロフェッショナルであれば、仕様をしゃぶるといったことはしないと思いますよ。
ましてや「探りを入れる」のは、プロとしての仕事ではないですね。
今回のコードは仕事ではないですけど、これをどう解くかが「プログラマ」と「似非グラマ」を分けるんじゃないですかね?
インドリさんが書くべきは「全然意味わかってない」と読む側に責任転嫁するんではなく「サーセンw間違えちった!」と自分の非を素直に認めることだと思うんですけど、違います?

Kingさん。

確かに「指定」という概念はインドリさんが書かれたコードで初めて出てきていますね。
元の仕様には全然出てきていないです。例外処理など、自分も一緒になって勝手な拡張をしてしまっていたと思います。

Sodaさん。

> CodeZineであんなことがあったばかりなのに・・・
> もう少し人の話を真剣に聞かないと、技術よりも重要な信用を失いますよ?
CodeZineって、あのCodeZineですか?
何かあったのかはわからないですけど、でもこの調子だと信用を得られない気がしますね。

山田太三郎

面白そうなエントリだったので。
遅ればせですが私も邪悪なコードをw
ちなみに関数、変数名はわざとです。

public class Main {

public static int BITS = 31;
public static int MAX = 100;
public static void main(String[] args) {
func(func5(MAX,1));
}

private static int func(int a) {
fizzbuzz(func4(MAX,a,BITS));
if(a==0) return a;
return func(func4(a,1,BITS));
}

private static void fizzbuzz(int a) {
if (func2(a,15)==0) System.out.println("FizzBuzz");
else if(func2(a,5)==0) System.out.println("Buzz");
else if(func2(a,3)==0) System.out.println("Fizz");
else System.out.println(Integer.toString(a));
}

private static int func2(int a,int b) {
if (a 0) {
if ((a & 1 0) return a^n;
return func5((a^n),n<<1);
}
}
JavaといいつつほとんどCですね。
手近にCのコンパイラが無かっただけですw

山田太三郎

コードがちゃんと反映されない・・・orz

確認せずに投稿してしまいすみませんでした。

山田太三郎

private static int func2(int a, int b) {
if (a < b) {
return a;
}
return func2(func4(a, func3(a, b), BITS), b);
}

private static int func3(int a, int b) {
if (a < (b << 1)) {
return b;
}
return func3(a, b << 1);
}

山田太三郎

private static int func4(int a, int b, int n) {
if (b == 0 || n < 0) {
return a;
}
if ((a & 1 << n) == 0) {
a = func5(a, ((1 << n) << 1));
}
a = a ^ 1 << n;
b = b ^ 1 << n;
}
return func4(a, b, func5(n, 1));
}

山田太三郎

private static int func5(int a, int n) {
if (n == 0) {
return a;
}
if ((a & n) > 0) {
return a ^ n;
}
return func5((a ^ n), n << 1);
}
エラー避けるために細切れですみません・・・

なんか荒らしてしまってすみません。

いろんな考え方があると思うけれど、複雑に書こうと、シンプルに書こうと、仕様どおり動くのがまず最低限の基準です。拡張するにも仕様どおり動いてナンボなんですよね。

アピールするなら、
Main と FizzBuzz などに分けるのは良いと思います。
ただし、Main は、あくまで、1, 100 の引数で FizzBuzz を利用しする。
そして、FizzBuzz は他の引数でも使えるようになっていることが拡張性でしょう。

FizzBuzz で引数をチェックするのではなく、Main など上位で仕様を満たすためのチェックを入れることと、FizzBuzz に拡張性(複雑にするのも)を分けているのを、私は個人的に評価します。

分割しないときは、オーバーロードして引数なしのとき 1, 100 の引数になるように私は作るかな。そういうのを評価します。(同じ手間でできますからね)

インドリさんのは、仕様を満たしていないところで、何をアピールしたかったのか分からないところで微妙です。

ひでみさんのは、私が試験官ならまず読まないけれど、「こんな馬鹿みたいな問題出してナメてるのか!」って思いが出てて、高い評価をつけますね。

入社試験の話を書いているので……。

失礼しました。

ひでみ

こんばんわです。ひでみです。

Sodaさん。

> 2、ループをマルチスレッドで処理する

この発想はなかったです。すばらしくムダな感じがステキです。
そんなわけでためしに書いてみたら、マルチスレッドの学習用プログラムみたいになってしまった……。
今度は Visual Basic 2005 です。


Dim glbBuffer(100) As String
Dim objSync As Object = New Object

Sub Main()
Dim nLoop As Integer
Dim aryThread(100) As System.Threading.Thread
For nLoop = 1 To 100
If ((nLoop Mod 3) = 0) And ((nLoop Mod 5) = 0) Then
glbBuffer(nLoop - 1) = "FizzBuzz"
ElseIf (nLoop Mod 3) = 0 Then
glbBuffer(nLoop - 1) = "Fizz"
ElseIf (nLoop Mod 5) = 0 Then
glbBuffer(nLoop - 1) = "Buzz"
Else
glbBuffer(nLoop - 1) = nLoop.ToString()
End If
aryThread(nLoop - 1) = New System.Threading.Thread( _
New System.Threading.ThreadStart(AddressOf outputConsole))
Next
For nLoop = 0 To 99
aryThread(nLoop).Start()
Next
End Sub

Private Sub outputConsole()
SyncLock objSync
For nLoop As Integer = 0 To 99
If glbBuffer(nLoop) <> "" Then
Console.WriteLine(glbBuffer(nLoop))
glbBuffer(nLoop) = ""
End If
Next
End SyncLock
End Sub

ひでみ

こんばんわです。ひでみです。
連投失礼いたします(笑)。コードと一緒だと読みにくいので分割しました。

コードの批評はOK、個人的中傷はNGです。そこらへんの区別について考えたうえでの投稿をお願いします。


Kingさん。

> 拡張性を全く除外した状態で、いかにコードを難しくするかという事が
> この記事でおっしゃっている事だと。

この記事の趣旨を正確にご理解いただけるようでうれしいです。


CMPさん。

> いつか、自分の部下に「CMPさんがプログラマとしての師匠です!」って言われてみたいなぁ~。

そう言ってくれる後輩は私にはいるんだろうか……。きっと誰かが影で言ってくれてる(←と思っておけ、と自分に言い聞かせてみる)。


ポチたまさん。

> 見習いや丁稚だと、これから成長しますよーって感じがしますよね。
> でも既に「プログラマ」を名乗ってる人は、もう成長する気がないのかな?と。

確かに「丁稚」だと「将来、自分の店をもつんだ」的な前向きイメージがありますね。
「似非プログラマ」は職を得るために必死なんだ、という考えもできますが、だったら別方向にがんばろうよ、という気がしてしかたありません。
そのためにきちんとしたプログラマが職を得られない、という可能性を考えるとことさらに。

ところで「さとみさん」てどなたですか?(爆笑)


山田太三郎さん。

コードが邪悪すぎて、私の脳が解析するのを拒否しました(苦笑)。


生島勘富さん。

> ひでみさんのは、私が試験官ならまず読まないけれど、「こんな馬鹿みたいな
> 問題出してナメてるのか!」って思いが出てて、高い評価をつけますね。

それはありがとうございます。
コードを通じて自分のアピールポイントが出せていればOKということですか。

ひでみ

こんばんわです。ひでみです。
さらに連続ですみませんです。
さきほどのコードを読み直してみたら Exit For が抜けてました(キモなのにっ!!)。

Private Sub outputConsole()
SyncLock objSync
For nLoop As Integer = 0 To 99
If glbBuffer(nLoop) <> "" Then
Console.WriteLine(glbBuffer(nLoop))
glbBuffer(nLoop) = ""
Exit For
End If
Next
End SyncLock
End Sub

インドリ

>インドリさんのは、仕様を満たしていないところで、何をアピールしたかったのか分からないところで微妙です。

試験ではこんな事言いませんよ(笑)
最初に明言しましたが、遊びですよ、遊び。
このコードを読んだら、先ほど言ったように「何故0と101を指定する」と聞いてくる人がいると見越して書いたのです。
生島さんがすごく速かったのでさすがに気づくのが早いと思いました。
もし本当に試験であるならば「エラーチェックはどうするのですか?」とか、
「0の扱いはどうしたらいいのですか?」と聞きます。
何故0が特別なのかと言いますと、数学的理由(0は無であり割れないという学者もいる)のほかにも「デフォルト値」と「意識外」だからです。
デフォルト値を渡すという事は「値の設定を忘れている」のか「本気で渡している」のかのどちらかです。
ですから親切な関数設計ではデフォルト値をどうするのかを考えなくてはなりません。
また、エンドユーザーの意識外の場合もあります。
その時は例外を投げなくてはなりません。
そういった事を問題文を読むのと同時に考えて(会話と同時に実装が思い浮かびますので)、1・2分で実装しました。
ちなみに、他にも色々なコードが思いついたのですが(SQL式、オブジェクト指向式、イベント駆動式、ループ式、文字列を返す形)、他の人の迷惑になるかもしれないので投稿をやめました。

問題文にある「まで」とは「以下」なのか「未満」なのか迷いませんか?
そういった細かい点に気づくかどうかも大事だと思います。
これに気づくてくる人がいませんでしたね・・・
気づくように0と101にしたのに・・・

私が試験管ならば・・・
・聞きたい事がありますか?と尋ねて仕様を確認してくる人は高評価
・ひでみさんのように複雑なものを書いてきても高評価(問題が簡単すぎるという意思表示と取る)
・再帰関数を末尾再帰で実装する。
・文字列関数にしてテストがやりやすいようにしてくる。
・テストコードまで書いてくる
・オブジェクト指向でしっかりとオブジェクト設計して書いてくる
・Prolog(他言語でもOK)で論述的に書いてくる
・アセンブラで書いてくる
などが高評価だと考えております。


それにしても、FizzBuzzを解けない人がいるとは・・・
たぶん難しく考えすぎているのか緊張しているのだと思います。
ですから私が試験管である場合は、テストコードとセットで課題にして、
仕様を曖昧に書き「聞きたい事があればメールするように」と書き添えます。
そして、プログラムはもちろんのこと「思考過程」を書くように求め、
如何にこの問題で考えるかという点を採点します。
こうすれば、設計力・思考力・プログラミング力・ドキュメント力・仕様を読み取る力・テスト力などが、緊張したなどの負の影響を取り除いて素の力を測定できます。
こうすれば、丸暗記にも対応できます。
それに、このような試験を出しても丸暗記している可能性がありますし、本来はすごい力を持っているのに実力を発揮していない人がいるかもしれませんからね。

インドリ

間違ったw

誤:試験ではこんな事言いませんよ(笑)
正:試験ではこんなの書きませんよ(笑)
※黙って書かないという意味です

Soda

>ひでみさん
採用ありがとうございますw
この手のネタはどこでも定期的に発生しますよねぇ。
でもって、皆がわれこそはーと少し熱くなる感じもw
中には、そんな書式でーとか、そんな方法がーみたいな発見があって楽しいです。

最近、某所では1~10の合計をループを使わずに書くってのが流行ってました。
公式使えば簡単にできることですが、暗黙のルールで誰も使わないw
こーアレです、ムダに対する美学が存在しているのですわw
この手のものは、一見役に立つように見えて、やっぱり使えないのがポイント高めですかねw

>インドリさん

残念ですね、まだ0のことがわからないのですね。
「0で割る」と「0を割る」をごっちゃにしているのかなぁ(^^;
今回は「0を割る」ことになるので、数学的に明確な答えが存在しています。

また、「デフォルト値」も一般的な使われ方とは異なることを連想しているように見えます。
今回どこにも登場していませんし・・・0とどうからむのか、理解できる人は少ないでしょう。
生島勘富さんのコメントに絡めているとしても・・・始めのコードにはないですし・・・

>問題文にある「まで」とは「以下」なのか「未満」なのか迷いませんか?

迷いませんよ?
「○○まで」と書かれている場合、○○を含みます。
多くの方は常識として認識しているので、気づくもなにも問題にすらならないのです。

>・聞きたい事がありますか?と尋ねて仕様を確認してくる人は高評価
私なら逆ですね、仕様にあきらかな不備があるならともかく、この程度で確認するような人はいらない。

>・ひでみさんのように複雑なものを書いてきても高評価(問題が簡単すぎるという意思表示と取る)
これも逆、答えを2つ書いているならともかく、簡単な方法が思いつかなかったと判断しますね。

>・文字列関数にしてテストがやりやすいようにしてくる。
>・オブジェクト指向でしっかりとオブジェクト設計して書いてくる
>・アセンブラで書いてくる
同じ理由で無意味だと思います。

>・テストコードまで書いてくる
余分なコードも不要ですね。

>・Prolog(他言語でもOK)で論述的に書いてくる
多くの場合、言語を指定されると思いますよ。
なんのための試験なのかってことですが(^^;

まぁ、試験官(管じゃないですよー)によってなにを評価するかは色々ですね。

あと・・・
>気づくように0と101にしたのに・・・
このコメントを見ている人、書いている人を試すようなことはおやめになったほうがいいですよ?
私は、かなり失礼なことをしているのだなと思いましたが・・・

後からつけたしで言うことは簡単です。
ただし、それを行うたびに「信用」を失っていくということを理解されたほうが良いと思います。

King

VS開いてややこしいFizzBuzzとは・・・て考えてた時に、Sodaさんのマルチスレッドを使うってアイデアに「ああ、やられた」と思いました。
何か他に違う視点がないか考えてみましたがなかなか思いつきません。
・"FizzBuzz"文字列100個の配列から始める
・"1"~"100"配列、"Fizz"100個配列、"Buzz"100個配列、"FizzBuzz"100個配列をマージする方向で
・ベタで"1","2","Fizz","4","Buzz"・・・とプリント
・"1.txt"~"100.txt"まで一時フォルダに作って内容を"FizzBuzz"条件に沿って編集してソートして読み込んで・・・
全く画期的にならない・・・。

> このコードを読んだら、先ほど言ったように「何故0と101を指定する」と聞いてくる人がいると見越して書いたのです。

こういうコメントは見たくなかったですね。

ポチたま

ひでみさん。

> ところで「さとみさん」てどなたですか?(爆笑)
うわあっ!ごめんなさい。お名前間違えてしまいました。
指が勝手に動いた…とは言え、固有名詞(しかもブログ主様の名前)を間違えてしまうなんて、なんという失態。お許しください。
先輩に「誤字脱字は失礼に当たるけれど、その中でも固有名詞を間違えることは一番失礼なことなんだ」と言われたのを思い出しました。気をつけていたつもりですが、全然駄目でしたね。

インドリさん。

> 試験ではこんな事言いませんよ(笑)
> 最初に明言しましたが、遊びですよ、遊び。
インドリさんは遊びかもしれませんが、後から後からそういう事を書くのは「言い訳」じゃありませんかって書きましたよね。
遊びだったとしても「最初に遊びと書かなかったのは過失ですね。ごめんなさい」とか言えないんですか?
それはそれとして、いくら遊びでもこんな稚拙なコードはどうかと思います。「難しくする」というひでみさんの課題はクリアできている(ように見える?)かもしれないですけど、それ以外の基本的な部分でポカしまくってるじゃないですか。
それともなんですか、試験だったら FizzBuzz ( 1, 100 ); と書くとでも?それはそれで我々を馬鹿にしすぎてるんじゃないですかね。

Sodaさん。

> このコメントを見ている人、書いている人を試すようなことはおやめになったほうがいいですよ?
> 私は、かなり失礼なことをしているのだなと思いましたが・・・

> 後からつけたしで言うことは簡単です。
> ただし、それを行うたびに「信用」を失っていくということを理解されたほうが良いと思います。
既に同じ意見が出ていたのですね。
確かにインドリさんは失礼なことをしていると思いますし、信用を失っていると思います。Sodaさんはインドリさんの事をよくご存じのようですが、これまでもこのような感じだったのですか?

King

連投&趣旨違いで申し訳ありません。
どうしても引っかかってしまうので。

> このコードを読んだら、先ほど言ったように「何故0と101を指定する」と聞いてくる人がいると見越して書いたのです。

百歩譲ってこんな事言われてみなさんが
「あ!そうだったのか!やられたな~!」
なんて思うとして(思わないはずですが)、
だからなんなのですか?

「指摘が多かった!良かった!この業界の未来も安心だな!」
と思うのですか?
他人の記事を潰してまで?
何様ですか?

CMP

ここは「以下に簡単な問題を複雑に回答するか」という壮大かつ大胆な試みを
みんなで楽しむところだ。
コメントを書いた後、投稿ボタンを押す前に一度深呼吸し、書いた内容を再度確認してから投稿ボタンをクリックしよう。

さあ、もう一捻りして新たなコードを出そう!
え、私?私はそこまで柔軟な思考ができないのでやめておきます・・・m(- -)m。

CMP

ぎゃあぁぁぁ
「以下に~」
でなく
「如何に~」
です。
連投&誤文すみませんでした(大汗)

Soda

>ポチたまさん
うーん、本記事と直接関係ないので・・・
ご本人のブログ
http://indori.blog32.fc2.com/
を参照してもらったほうが(^^;
CodeZineに関してはー私信だったと思っていただければいいかなと(^^;
それでも気になるなら、本人のブログからリンクが張られているので、そこのコメントをみてください。

ネット上で、「あの人は○○な人だー」と言っても、本当にそうかどうかは判断できないわけで(^^;
見ている人それぞれが、普段の発言から、どういう人なのかを感じるしかないです。
おそらく、その1つ1つの発言の積み重ねで、その人の信頼度などが個々に決まるんだろうと。

まぁ、自分で「○○ができる!」「○○したことがある!」といくら言っても、それだけじゃ信頼されないのと同じですね。
有言実行ってやつですかね、記事を書いてる人は特に求められると思います。
立派なことを言っていても、矛盾していたら信用されないわけで(^^;

・・・あっ、また長くなってしまった(^^;;;;

PS.
インドリさんは始めに
>私も遊んでみました♪
と書かれているので、遊びだったのは始めからわかりますよー。
まぁ、遊びのルールを守っていたかどうかは別の話ですが(^^;

PS.2
マルチスレッドの上を目指すと次は分散コンピューティングですかねw

セロ

>CMPさん
CMPさんのコメント以降はそうしましょうととれば、以下でもあながち間違いではない罠。

SELECT CASEで百個に分岐でどうでしょう。

ビガー

ビガーです。こんばんは。

書きたくなったので遅くなりましたが、オブジェクティブにある意味複雑に書いてみました。
MAX2500くらいでスタックオーバーフローになるゴミです。stateのnewもなってない。
単純計算には、まったく向かないですね。

どうでもいいけど、コメント欄でのインデントの完全なつけ方わからず(空白ベタ書きでも途中で無効になったり、HTMLのエスケープも効かないし)、皆さんの無念を感じました。

public class FizzBuzz {

public static void main(String[] args) {
new FizzBuzz().run();
}

public void run() {
new ThreeAndFiveFizzBuzzVisitor().visit(new ThreeAndFiveFizzBuzzStrategy());
}

abstract class FizzBuzzVisitor {
protected int visitCount = 0;
protected static final int VISIT_COUNT_MAX = 100;
protected abstract void visit(FizzBuzzStrategy strategy);
public int getVisitCount() { return visitCount; }
}
class ThreeAndFiveFizzBuzzVisitor extends FizzBuzzVisitor {
@Override
protected void visit(FizzBuzzStrategy strategy) {
if( strategy == null ) throw new IllegalArgumentException("strategy is null");
if( visitCount++ >= VISIT_COUNT_MAX ) return;
strategy.print(this);
}
}

interface FizzBuzzStrategy {
FizzBuzzState judge(FizzBuzzVisitor visitor);
void print(FizzBuzzVisitor visitor);
}
class ThreeAndFiveFizzBuzzStrategy implements FizzBuzzStrategy {
private java.io.PrintStream output = System.out;
public void print(FizzBuzzVisitor visitor) {
if( visitor == null ) throw new IllegalArgumentException("visitor is null");
FizzBuzzState state = judge(visitor);
if( state == null ) { output.println(visitor.getVisitCount()); }
else { output.println(state.getStateName()); }
visitor.visit(this);
}
public FizzBuzzState judge(FizzBuzzVisitor visitor) {
int count = visitor.getVisitCount();
if( count % 3 == 0 && count % 5 == 0 ) { return new ThreeAndFiveFizzBuzzState(); }
else if( count % 3 == 0 ) { return new ThreeFizzBuzzState(); }
else if( count % 5 == 0 ) { return new FiveFizzBuzzState(); }
return null;
}
}

interface FizzBuzzState {
String getStateName();
}
class ThreeFizzBuzzState implements FizzBuzzState{
public String getStateName() { return "Fizz"; }
}
class FiveFizzBuzzState implements FizzBuzzState{
public String getStateName() { return "Buzz"; }
}
class ThreeAndFiveFizzBuzzState implements FizzBuzzState{
public String getStateName() { return "FizzBuzz"; }
}
}

ひでみ

こんばんわです。ひでみです。


インドリさん。

> それにしても、FizzBuzzを解けない人がいるとは・・・
> たぶん難しく考えすぎているのか緊張しているのだと思います。

私もそう思いたいところですが、どんだけ教えてもこの手の問題に悩む人ってのがいるんですよね。
その人がどうして理解できないのかが理解できなくて、どうすればいいのか途方に暮れちゃいます。
緊張して余りの演算子を思い出せないとか、言語がごっちゃになっちゃったとかいうのはあり得ますが(私もやりそう)、ロジックそのものがでてこない、というのは「プログラマ」を名乗るのならあり得ないと思います。


Sodaさん。

> 採用ありがとうございますw

こちらこそ、おもしろいネタをありがとうございました。
もうちょっと考えればもっとひねれそうな気がするんですが、あんな形で Lock をかけたらマルチスレッドなんてまるっきり無意味、という学習用教材みたいになっちゃいました。
おまけに実は Exit For が抜けてても結果は同じだしっ(それでも入れておきたい)。


Kingさん。

> "1.txt"~"100.txt"まで一時フォルダに作って内容を"FizzBuzz"条件に
> 沿って編集してソートして読み込んで・・・

わざわざファイルをつくるという発想は思いつきませんでした。
ムダ度でいえばかなりなもんですよね。


ポチたまさん。

> うわあっ!ごめんなさい。お名前間違えてしまいました。

いや、おもしろかったからいいんですけど。


CMPさん。

> え、私?私はそこまで柔軟な思考ができないのでやめておきます・・・m(- -)m。

ながめているだけでもお楽しみいただけているのなら幸いです。


セロさん。

> SELECT CASEで百個に分岐でどうでしょう。

書く手間を考えると、これのソースファイルを出力するコードを書きたくなりますね。
それはそれでムダな感じでよいですけど(笑)。


ビガーさん。

めちゃくちゃしっかりしたコードをありがとうございます。
これはまた継承嫌いの人を怒らせそうなコードですね。
関係ないですけど、昔、interface の使い方がさっぱり理解できなかったことを思い出しました。

> どうでもいいけど、コメント欄でのインデントの完全なつけ方わからず
> (空白ベタ書きでも途中で無効になったり、HTMLのエスケープも効かないし)、
> 皆さんの無念を感じました。

私もちょっとだけ悩んですぐにあきらめました。
ここのコメント欄がコードを書き込むことを想定していないだけなんでしょうけど。

ちなみに、エスケープしてると修正のとき大変なので、私は本文でも、コメント欄でも、全角ブランクでインデントしています。

適当なエディタで書いて、貼り付ける前にタブを全角2文字ぐらいに変換してもらえると、読み易くて助かります。

ビガー

ビガーです。

生島さん、なるほど全角空白でうまくいくんですね。抜けていました。
ゴミの上塗り(こんな言葉ある?)で恐縮ですが、strategyがひどかったのでついでに直しました。コメント欄を汚してすみません。

public class FizzBuzz {
 
 public static void main(String[] args) {
  new FizzBuzz().run();
 }
 
 public void run() {
  new ThreeAndFiveFizzBuzzVisitor().visit(new ThreeAndFiveFizzBuzzStrategy());
 }
 
 /**
  * ループカウンタを訪問者に見立て、巡回基準に則って巡回することだけを目的としている。
  */
 abstract class FizzBuzzVisitor {
  protected int visitCount = 0;
  protected static final int VISIT_COUNT_MAX = 100;
  abstract void visit(FizzBuzzStrategy strategy);
  public int getVisitCount() { return visitCount; }
 }
 class ThreeAndFiveFizzBuzzVisitor extends FizzBuzzVisitor {
  @Override
  public void visit(FizzBuzzStrategy strategy) {
   if( strategy == null ) throw new IllegalArgumentException("strategy is null");
   if( visitCount++ >= VISIT_COUNT_MAX ) return;
   strategy.print(this);
  }
 }

 /**
  * 訪問者が訪れてきたときにするべきこと(戦略)を定義する。
  */
 abstract class FizzBuzzStrategy {
  private java.io.PrintStream output = System.out;
  protected abstract FizzBuzzState judge(FizzBuzzVisitor visitor);
  public void print(FizzBuzzVisitor visitor) {
   if( visitor == null ) throw new IllegalArgumentException("visitor is null");
   FizzBuzzState state = judge(visitor);
   if( state == null ) { output.println(visitor.getVisitCount()); }
   else { output.println(state.getStateName()); }
   visitor.visit(this);
  }
 }
 class ThreeAndFiveFizzBuzzStrategy extends FizzBuzzStrategy {
  @Override
  protected FizzBuzzState judge(FizzBuzzVisitor visitor) {
   if( visitor == null ) throw new IllegalArgumentException("visitor is null");
   int count = visitor.getVisitCount();
   if( count % 3 == 0 && count % 5 == 0 ) { return new ThreeAndFiveFizzBuzzState(); }
   else if( count % 3 == 0 ) { return new ThreeFizzBuzzState(); }
   else if( count % 5 == 0 ) { return new FiveFizzBuzzState(); }
   return null;
  }
 }
 
 /**
  * 共有リソース。スレッド間のロックはコレを使うイメージ。
  */
 interface FizzBuzzState {
  String getStateName();
 }
 class ThreeFizzBuzzState implements FizzBuzzState{
  public String getStateName() { return "Fizz"; }
 }
 class FiveFizzBuzzState implements FizzBuzzState{
  public String getStateName() { return "Buzz"; }
 }
 class ThreeAndFiveFizzBuzzState implements FizzBuzzState{
  public String getStateName() { return "FizzBuzz"; }
 }
}

King

皆さんのに似てる&質が落ちてる気もしますが・・・。

static void Main()
{
  DoFizzBuzz(1, 100);
  Console.ReadLine();
}

static void DoFizzBuzz(int start, int end)
{
  int count = end - start + 1;

  List<FizzBuzzTemplate> l = new List<FizzBuzzTemplate>(count);

  System.Linq.Enumerable.Range(start, count).ToList().ForEach((a) => l.Add(GetFizzBuzzItem(a)));

  IEnumerator<FizzBuzzTemplate> e = l.GetEnumerator();

  while (e.MoveNext())
  {
    e.Current.Print();
  }
}

static FizzBuzzTemplate GetFizzBuzzItem(int num)
{
  FizzBuzzTemplate item = null;

  if (num % 3 == 0 && num % 5 == 0) item = new FizzBuzzForFizzBuzz();
  else if (num % 3 == 0) item = new FizzBuzzForFizz();
  else if (num % 5 == 0) item = new FizzBuzzForBuzz();
  else item = new FizzBuzzForNumber();

  item.Number = num;
  
  return item;
}

abstract class FizzBuzzTemplate
{
  public int Number { get; set; }
  public abstract void Print();
}

class FizzBuzzForFizzBuzz : FizzBuzzTemplate
{
  public override void Print()
  {
    Console.WriteLine("FizzBuzz");
  }
}

class FizzBuzzForFizz : FizzBuzzTemplate
{
  public override void Print()
  {
    Console.WriteLine("Fizz");
  }
}

class FizzBuzzForBuzz : FizzBuzzTemplate
{
  public override void Print()
  {
    Console.WriteLine("Buzz");
  }
}

class FizzBuzzForNumber : FizzBuzzTemplate
{
  public override void Print()
  {
    Console.WriteLine(Number.ToString());
  }
}

ひでみ

こんばんわです。ひでみです。


επιστημηさん。

トラックバックのお申し込みもしていただいているようですが、当方からリンク先の確認ができないため承認できません。
たどりつけない原因がどこにあるのかわかりませんが、明日(10/12)の22:00までこの状態が続くようでしたら、トラックバックとコメントを削除させていただきたいと考えています。
以上、ご承知おきくださいませ。


生島勘富さん。

> ちなみに、エスケープしてると修正のとき大変なので、私は本文でも、
> コメント欄でも、全角ブランクでインデントしています。

あっ、そんな簡単な話だったんですか(苦笑)。


ビガーさん。

ここのところ Java から遠ざかっていたので、そういえば Java ってこんなんだったなあ、としみじみ~と読んでしまいました。
言語ってのはちょっと離れると簡単に忘れますね。ちょっとコードを読めば簡単に戻ってきますけど。
Java のオブジェクト指向的キーワードが網羅されているので、とてもいい教材になりそうな気がします。
こんなお遊びにホンキでつきあってくださってありがとうございます。


Kingさん。

列挙を使うというのはおもいつきませんでした。
本当にいろいろと考えたつもりだったんですけど、やっぱり穴だらけでしたね。
う~ん、まだまだ頭が固いなあ。

あ~り~

ただ一言、「マジパネェ!」

皆さんすごすぎます。
FizzBuzzがここまで難しいコードになるとは。。。。

いまだに存在している、どの言語に対しても
「どれくらいのPGM書いたことある?」
という、ステップ数=すごいプログラム(ちょっと違うけど良さげな言葉が見つからず・・・)
な意識の方へアピールするにピッタリな感じですね^^

もちろん、嫌味ではありませんよ。

ここまできたら、『強烈さ』をアピールするために
IF文で1~100まで・・・しか対抗できそうにないな。
マッハで不採用の書類をいただく事になりますが・・・(最低すぎて音信不通かも)

ひでみ

こんばんわです。ひでみです。


επιστημηさん。

ようやくリンク先が確認できましたので、トラックバックを承認させていただきました。
どうして今までつながらなかったんでしょう……。とは言ってもいまだにつながらない時の方が多いです。

TBB というものの存在を知りませんでした。ホントに知らないことがたくさんあるなあ、私。
おもしろいものを教えてくださってありがとうございました。


あ~り~さん。

> 皆さんすごすぎます。
> FizzBuzzがここまで難しいコードになるとは。。。。

まったくです。
こうなると私のコードがめっちゃしょぼく見えます。
もっと修行しなくては!

Soda

>ひでみさん
パッとみた感じだと、どのように動作するのかわからなかったり(^^;
VB2005のコード書いたことないので、実際に動かして確認しましたw
想像してたのとまったく違う動きだったw
こー自分が最初に考えたものに引っ張られると、他人の書いたコードってパズルみたいですねぇ。

ひでみさんのコードを元に、こんな感じかなーと書いてみました。
一応動作確認まではしたんですが、なにぶん、VB2005自体よくわかっていないので、変なとこあるかも(^^;
・・・というか、配列はこんな感じで大丈夫だったんだろうか(^^;;;;;;;
まぁ、イメージだけ伝わればいいかなとw

Public Class WorkerClass
 Dim message As String
 Dim number As Integer

 Public Sub New(ByVal n As Integer)
  number = n
 End Sub

 Public Function GetMessage() As String
 Return message
 End Function

 Public Sub Worker()
 message = ""
  If ((number Mod 3) = 0) Then
   message = "Fizz"
  End If
  If ((number Mod 5) = 0) Then
   message += "Buzz"
  End If
  If (message = "") Then
   message = number.ToString()
  End If
 End Sub
End Class

Sub Main()
 Dim nLoop As Integer
 Dim aryThread(100) As System.Threading.Thread
 Dim wc(100) As WorkerClass

 For nLoop = 0 To 99
  wc(nLoop) = New WorkerClass(nLoop + 1)
  aryThread(nLoop) = New System.Threading.Thread( _
  New System.Threading.ThreadStart(AddressOf wc(nLoop).Worker))
  aryThread(nLoop).Start()
 Next

 For nLoop = 0 To 99
  aryThread(nLoop).Join()
 Next

 For nLoop = 0 To 99
  Console.WriteLine(wc(nLoop).GetMessage())
 Next
End Sub

PS.
επιστημηさんの所は、サーバが弱いのか、なかなか繋がらない時があるのが難点ですわ(^^;
でも、そこから派生している流れは、かなり面白いですよー。

ビガー

ビガーです。たびたびすみません。

2本シリーズでひでみさんの今回のネタを引用してコラムさせてもらいます。近日中に公開されます。

CMP

マルチスレッド系は、順番どおりに出力するのにテクニックが必要です。
そのままじゃ無理w。
あと、マルチスレッド系は同じ実行ファイルでもCPUのコア数が異なると、また違った動きをするので結構楽しいですよ。(特にIntelのHyperThreadなんて涙ものですよw)
.NETで作るより、Javaで作成してWindows、Linux、MacOSと異なるプラットフォームで試すのも面白いんだな。

セロ

ふとVB2005ですが
public Function ChangeString(ByVal value As Integre, ByVal i As Integer, ByVal str As String) As String
  If ((value Mod i) = 0) Then
    Return str
  Else
    Return value.ToString
  End If
End Function
なんて処理をかませば拡張性ができるかなと思ってみたり。

セロ

うは、ごめんなさい。
インテグレってなんだよ俺。

ひでみ

こんばんわです。ひでみです。


Sodaさん。

> VB2005のコード書いたことないので、実際に動かして確認しましたw
> 想像してたのとまったく違う動きだったw

コードを読んでイメージはわかりました。もっとバラけさせる感じだったんですね(←わかりづらい表現ですみません)。
同じテーマで短編小説を書く、といった趣向がありますけど、そのプログラム版みたいでおもしろいです。
マルチスレッドネタはもっとねじれた感じにできないかなあ、とか考えてるんですが、いい感じのがおもいつきません。


Jittaさん。

> わんくまサーバの機嫌が悪いみたいですね。

そうなんですか。飛び先が確認できないリンクをいつまでも放置しておくわけにもいかなくて、どうしたもんかなあ、と思ってたんですよ。
これからはわんくまサーバが相手の時はちょっと気長に待ってみることにします。


ビガーさん。

> 2本シリーズでひでみさんの今回のネタを引用してコラムさせてもらいます。
> 近日中に公開されます。

Sodaさんのコードもそうですが、リンクしている感じがステキですね。
楽しみにしています。


CMPさん。

> あと、マルチスレッド系は同じ実行ファイルでもCPUのコア数が異なると、また違った動きを
> するので結構楽しいですよ。(特にIntelのHyperThreadなんて涙ものですよw)

今のところそういう経験をしたことはないですね。
それを「結構楽しい」と言えるようになるまでにはかなりかかりそうです(笑)。


セロさん。

> インテグレってなんだよ俺。

このタイプミス、私もよくやります。
なんか、指と指の同期がうまくとれないことがあるみたいです。

ChangeString() ですが、これを組み込むとちょっとスマートな感じになりそうですね。

はやしさとし

こんばんは、ひでみさん。

「プロトタイプチェイン」で「FizzBuzz」を書いてみました。
言語は「JavaScript」です。

function DoFizzBuzz()
{
  var fb = new FizzBuzz();
  for (var i=1; i<=100; i++) alert(fb[i]);
}

function NORMAL()
{
  for (var i=1; i<=100; i++) this[i+""] = i+"";
}

function Fizz()
{
  for (var i=3; i<=100; i+=3) this[i+""] = "Fizz";
}

function Buzz()
{
  for (var i=5; i<=100; i+=5) this[i+""] = "Buzz";
}

function FizzBuzz()
{
  for (var i=15; i<=100; i+=15) this[i+""] = "FizzBuzz";
}

Fizz.prototype = new NORMAL();
Buzz.prototype = new Fizz();
FizzBuzz.prototype = new Buzz();

ひでみ

こんばんわです。ひでみです。

はやしさとしさん。

JavaScript の prototype はキーワードだけは知っていたんですが、はやしさんのコードを読みながら動きをあてはめてたら、ようやく挙動が理解できました。
なるほど、そういうことだったのか!
JavaScript 的オブジェクト指向は私にはとても難解です。
まあ、JavaScript をちゃんと掘り下げようと思ったことがない、というのが正確なところですが。

おもしろいものを教えていただけて感謝感謝です。
この記事を書いてホントによかったなあ(←自分の不勉強ぶりが露呈しちゃってるんだけど)。

CMP

はやしさとしさんのソースで質問なんだけど、だれか答えてくれないかな?

1つ結果を出すのにループを400回しているような気がするのですが、気のせいですか?
つまり、全結果を出すのに100x400回ループしていて、無駄にCPUリソースを使っているような・・・。

でも、プロトタイプチェインって面白いね。クラスで再帰処理してるみたいだ。
喰わず嫌いでJavaScriptは敬遠してたけど、真面目に勉強してみようかな。

ひでみ

こんばんわです。ひでみです。

CMPさん。

えっと、JavaScript は専門家ではないので、間違っている可能性もありますが、昨日、私が解釈したところでは、まず function FizzBuzz() を new した際に 15 の倍数の配列部分に 'FizzBuzz' が埋まる。
しかし、 DoFizzBuzz() 内で 100 個分の配列を求められているので、 Undefined になってしまっている部分を FizzBuzz.prototype が求めて、function Buzz() でつくられた 5 の倍数部分に 'Buzz' を埋めた配列から、足りない部分を参照する。
それでも Undefined な部分を Buzz.prototype が求めて、function Fizz() でつくられた 3 の倍数部分に 'Fizz' を埋めた配列から、足りない部分を参照する。
それでもまだ Undefined な部分を Fizz.prototype が求めて、 function NORMAL() でつくられた 100 個分すべてに数字を埋めた配列から、足りない部分を参照してようやく 100 個分の配列がすべて埋まる。
という、FizzBuzz() → Buzz() → Fizz() → NORMAL() の借り物リレーと解釈すると、new FizzBuzz() で 6(=100/5)、new Buzz() で 20(=100/5)、new Fizz で 33(=100/3)、new NORMAL で100 回ループしているので、ループは全部 159 回なのではないかと……。

この解釈が根本的に間違ってたらホントにすみません。
どなたか説明プリーズ!

CMP

ひでみさん、おはようございます(マテ

つまり、fb[1]のときに159回のループが行われ、fb[2]以降はループなしに結果が得られるってことですね。
ってことは159+100(DoFizzBuzzのループ)で259回ってことなのか!
ものすごいきれいなソースですね、これ。

P.S.インクリメントをちゃんと見てなかった(大汗)

大空あゆむ

無駄に長く,ではなく,逆に短く1行で書いてみました。
ちなみに言語はJavaです。

for (int i = 1; i <= 100; i++) { System.out.println((i % 15 == 0)? "FizzBuzz": (i % 3 == 0)? "Fizz": (i % 5 == 0)? "Buzz": String.valueOf(i)); }

大空あゆむ

↑書いた後で上のほうをみたら,すでにKingさんが同じようなコードを書いてるのを見つけて軽く鬱…

失礼しました。

ひでみ

こんばんわです。ひでみです。

↑そっ、そんなに落ち込まないで~っ。

Algol

ひでみさん、はじめまして。

無駄に長く…面白そうなので遅ればせながら私も作ってみました。
コンセプトは、「無駄に長くかつループ(for、foreach、while、do)未使用、さらに仕様を満たした上でなおかつ拡張できる。使い方はシンプルに。」です。
環境 .NET Framework 3.5 C#
※短くするために行間を詰めた関係で見難くなってしまいました。orz
※エラー処理は省いています。
※あと、インデントのスペースと比較の不等号とジェネリック型の型パラメータの括弧が全角に変換してあります(^^;

// Main
Console.WriteLine(new FizzBuzz());

// FizzBuzz クラス
// 完成仕様版
public sealed class FizzBuzz : FizzBuzz<FizzBuzzItem>
{
 public FizzBuzz()
  : base(1, 100, FizzBuzzSelctor.Fizz, FizzBuzzSelctor.Buzz, FizzBuzzSelctor.FizzBuzz)
 { }
}

// カスタマイズ用 FizzBuzzジェネリッククラス
// FizzBuzzアイテムの列挙子を公開します。また文字列への暗黙の変換を行います
public class FizzBuzz<T> : IEnumerator<T>, IEnumerable<T>
 where T : FizzBuzzItem
{
 public FizzBuzz(int start, int end, params FizzBuzzSelctor[] selectors)
 { this.value = Activator.CreateInstance(typeof(T), start, end, selectors) as T; }

 private T value;

 IEnumerator<T> IEnumerable<T>.GetEnumerator() { return this; }
 IEnumerator IEnumerable.GetEnumerator() { return this; }

 T IEnumerator<T>.Current { get { return this.value; } }

 object IEnumerator.Current { get { return this.value; } }
 bool IEnumerator.MoveNext() { return this.value.MoveNext(); }
 void IEnumerator.Reset() { this.value.Reset(); }

 void IDisposable.Dispose() { }

 public static implicit operator string(FizzBuzz<T> fizzbuzz)
 { return string.Join("\n", fizzbuzz.Select(item => item.Current).ToArray()); }
}

// カスタマイズ用 FizzBuzzアイテムクラス
// カウンタの反復処理および制御をします
public class FizzBuzzItem : IEnumerator<string>
{
 public FizzBuzzItem(int start, int end, FizzBuzzSelctor[] selectors)
 {
  this.Start = start; this.End = end;
  this.Selectors = new List<FizzBuzzSelctor>();
  if (selectors != null && selectors.Length > 0) this.Selectors.AddRange(selectors);
 }

 protected int Start { get; private set; }
 protected int End { get; private set; }
 protected List<FizzBuzzSelctor> Selectors { get; private set; }
 protected FizzBuzzSelctor ResultSelecter { get; private set; }
 public int CurrentValue { get; private set; }

 public virtual string Current
 {
  get
  {
   return this.ResultSelecter == null ?
    string.Format(FizzBuzzSelctor.NUM_FORMAT, this.CurrentValue, this.CurrentValue) :
    this.ResultSelecter.OnResult(this.CurrentValue);
  }
 }

 public virtual bool MoveNext()
 {
  if (this.CurrentValue != int.MinValue) this.CurrentValue++;
  else this.CurrentValue = this.Start;

  this.ResultSelecter = null;

  if (CurrentValue > this.End) return false;

  IEnumerable<FizzBuzzSelctor> selection =
   from item in this.Selectors
   where item.OnSelect(this.CurrentValue)
   orderby item.Priority
   select item;
  if (selection.Count() > 0) this.ResultSelecter = selection.First();

  return true;
 }

 public virtual void Reset()
 {
  this.CurrentValue = int.MinValue;
  this.ResultSelecter = null;
 }

 object IEnumerator.Current { get { return this.Current; } }
 void IDisposable.Dispose() { }
}

// カスタマイズ用 FizzBuzzセレクタクラス
// 選択および文字列の生成をします
public sealed class FizzBuzzSelctor
{
 public const string NUM_FORMAT = "{0,3} {1}";

 public static readonly FizzBuzzSelctor Fizz =
  new FizzBuzzSelctor(3, "Fizz", item => item % 3 == 0);
 public static readonly FizzBuzzSelctor Buzz =
  new FizzBuzzSelctor(2, "Buzz", item => item % 5 == 0);
 public static readonly FizzBuzzSelctor FizzBuzz =
  new FizzBuzzSelctor(1, "FizzBuzz", item => item % 3 == 0 && item % 5 == 0);

 public FizzBuzzSelctor(int priority, string value, Func<int, bool> selecter)
  : this(priority, item => string.Format(NUM_FORMAT, item, value), selecter)
 { }
 public FizzBuzzSelctor(int priority, Func<int, string> result, Func<int, bool> selecter)
 { this.Priority = priority; this.result = result; this.selecter = selecter; }

 private Func<int, string> result;
 private Func<int, bool> selecter;

 public int Priority { get; private set; }

 public string OnResult(int value) { return this.result(value); }
 public bool OnSelect(int value) { return this.selecter(value); }
}

ひでみ

こんばんわです。ひでみです。

Algolさん。はじめまして。

これはまた力作ですね。C# は扱ったことがないので、解読困難なんですけど(くやしい)。
列挙は使いようによってはコードをとてもシンプルにしてくれるんですけど、こういう使い方すると迷惑だなあ(笑)。
なんか、自分に書けないコードを読むと、むやみに闘争心が湧いてきますよね(←何と闘ってるんだよ、自分)。

k2

こんにちわ。
いまさらですがC言語で
if,switch,for,while,三項演算を
使わずに実現してみました。
五分あればタイプできるはず・・・。

int main(void)
{
  int i = 1;
  return fizzBuzz(&i,100);
}
int fizzBuzz(int *now, int max)
{
  ((!(*now % 5) && !(*now % 3)) && (printf("FizzBuzz\n"))) ||
  ((!(*now % 3)) && (printf("Fizz\n"))) ||
  ((!(*now % 5)) && (printf("Buzz\n"))) ||
  ((printf("%d\n", *now)));
  return (++*now > max) || fizzBuzz(now, max);
}

ひでみ

こんばんわです。ひでみです。

k2さん。

5分以内ルールを気にかけてくださってありがとうございます。
デスマーチ問題に気をとられちゃってて、うっかり放置状態になっちゃってました。本当にすみません。
FizzBuzz解答もまだまだ絶賛募集中です!

そうか if を使わなくてもできるのか、と C の文法をあらためて勉強しなおした思いです。
結構、単純なことを忘れているなあ、と反省(しばらく離れていたとはいえ忘れすぎだ、自分)。

k2

ひでみ様

レスありがとうございます。
いまさらなのに気にかけていただいてありがとうございました。
自分で書いておいて何なのですが、
なぜかnumがポインタ変数になってしまっていたので修正版です。
(別の複雑性を目指していた名残なのですが・・・)

int main(void)
{
  int start = 1;
  int max = 100;

  return fizzBuzz(start, max);
}

int fizzBuzz(int now, int max){
  return (
    (now +=
      (
        ((!(now % 5) && !(now % 3) ) && (printf("FizzBuzz\n"  ))) ||
        ((!(now % 3)        ) && (printf("Fizz\n"    ))) ||
        ((!(now % 5)        ) && (printf("Buzz\n"    ))) ||
        (                (printf("%d\n", now   ))) | 0xFF & 0x01
      )
    ) > max) || fizzBuzz(now, max);
}

福田(仮)

皆さん、はじめまして、こんにちは。

いろんなソースを楽しく拝見しました。
問題としては単純なのに、難しくしようとすると、
どうにでもなるものですねぇ…。

じつは、"Fizz-Buzz問題"をこの記事ではじめて知りました…^^;
自分でもC言語使って解いてみましたが、
無駄に長くするのは自分には無理なようですorz

N88-BASICとか使って解いてみようかな…。

Masa

はじめまして。@ITで本日このトライアル(?)見つけて面白そうだったので
私も解いてみました。

Perlです。

#!perl -Tw

use strict;

{
package MyObject;

use strict;
use IO::File;
use base 'Object::Accessor';

sub new {
my $class = shift;
$class->SUPER::new ( qw / last_num strings counter / );
}

sub replace {
my $self = shift;
my $num = shift;
my $str = shift;
${$num} = $str;
}

sub set_counter {
my $self = shift;
my $num = 0;
sub { return ++$num };
}

sub print {
my $self = shift;
my $out = IO::File->new;
$out->fdopen(fileno(STDOUT),'w');
$out->print (shift);
}
}

my $obj = MyObject->new;

$obj->last_num(100);
$obj->strings( ["Fizz","Buzz"] );
$obj->counter( $obj->set_counter );

while ( (local $_ = &{$obj->counter}) last_num ) {
if ( ! ( $_ % 5 or $_ % 3 ) ) {
$obj->replace( \$_,$obj->strings->[0].$obj->strings->[1]);
} elsif ( ! ( $_ % 3 ) ) {
$obj->replace( \$_,$obj->strings->[0] );
} elsif ( ! ( $_ % 5 ) ) {
$obj->replace( \$_,$obj->strings->[1] );
}
$obj->print($_."\n");
}

exit;


まだまだ複雑さが足りないかも。
とはいえPerlは文法的にすっきりしたプログラムになりやすいので、
これ以上はちょっときついです。

一応標準モジュール2個使ってオブジェクトとクロージャで複雑さを
増すようにしています。
モジュールの関係でPerl5.10以降対応です。

Fizz-Buzz問題って私も初めてしました。
複雑にするのは遊びとしては面白いけど、仕事じゃ絶対書きませんw。

Masa

すいません。最後のwhile節の条件文で演算子が消えてしまいました。

どうも入力が無理な様なのでwhileをuntilに変えて節全体を以下のように
書き換えます。

until ( (local $_ = &{$obj->counter}) > $obj->last_num ) {
if ( ! ( $_ % 5 or $_ % 3 ) ) {
$obj->replace( \$_,$obj->strings->[0].$obj->strings->[1]);
} elsif ( ! ( $_ % 3 ) ) {
$obj->replace( \$_,$obj->strings->[0] );
} elsif ( ! ( $_ % 5 ) ) {
$obj->replace( \$_,$obj->strings->[1] );
}
$obj->print($_."\n");
}

ひでみ

こんばんわです。ひでみです。


福田(仮)さん。はじめまして。

> いろんなソースを楽しく拝見しました。
> 問題としては単純なのに、難しくしようとすると、どうにでもなるものですねぇ…。

私としては、コードがみんな「どや顔」してるのが楽しいです(笑)。
ていうか、私が書いたマルチスレッド版が一番ショボイのがひっかかってます。
マルチスレッド使うんだったらもっとトリッキーな動きを出せそうな気がするんですけどねえ。ムダに複雑にするのって本当に難しい。

> じつは、"Fizz-Buzz問題"をこの記事ではじめて知りました…^^;

私も小飼弾氏の記事ではじめて知りました。業界内ではわりとメジャーな問題だったらしいですね。


Masaさん。はじめまして。

Perl はやったことがない言語なので解読できない~。でもこれで、言語が一通りそろった感じですね(あとはSmalltalkとかCOBOLとか……きりがないっ)。

> 複雑にするのは遊びとしては面白いけど、仕事じゃ絶対書きませんw。

私も仕事じゃ絶対に書きません。自分の首をしめるだけなので(いろんな意味で)。

Masa

昨日これ以上はきついと言っていたのですが、一晩考えたら改良(?)できました。
さらにオブジェクトメソッド増やしてカプセル化を進めたのと
Perlらしく配列インデックスの使用をやめてみました。

複雑にしたというよりは1000行レベルプログラムの書き方でFizz-Buzzを書いた
感じですね。

(この程度のプログラムでカプセル化なんて言葉を使う日が来るとはw)

相変わらずPerl 5.10以降対応です。


#!perl -Tw

use strict;

{
 package MyObject;

 use strict;
 use IO::File;
 use base 'Object::Accessor';

 sub new {
  my $class = shift;
  $class->SUPER::new ( qw / last_num strings counter / );
 }

 sub set_counter {
  my $self = shift;
  my $num = 0;
  $self->counter( sub { ++$num } );
 }

 sub get_counter {
  my $self = shift;
  &{$self->counter};
 }

 sub replace {
  my $self = shift;
  my $num = shift;
  my $flag = 0;
  my $str = "";
  #テストする場合、ここの<=>は半角に変換してから使用してください。
  foreach ( sort { $a <=> $b } keys %{$self->strings} ) {
   unless ( ${$num} % $_ ) {
    $str = $str.$self->strings->{$_};
    $flag = 1;
   }
  }
  ${$num} = $str if $flag;
 }

 sub print {
  shift;
  my $out = IO::File->new;
  $out->fdopen(fileno(STDOUT),'w');
  $out->print (shift);
 }
}

my $obj = MyObject->new;

$obj->last_num(100);
$obj->strings( {3=>"Fizz",5=>"Buzz"} );
$obj->set_counter;

until ( (local $_ = $obj->get_counter) > $obj->last_num ) {
 $obj->replace(\$_);
 $obj->print($_."\n");
}

exit;


> Perl はやったことがない言語なので解読できない~。でもこれで、言語が一通りそろった感じですね(あとはSmalltalkとかCOBOLとか……きりがないっ)。

個人的にはRubyとBashあたりが見てみたいです。Bashなんて複雑にしたら際限無さそうですし。

たいたい

ちょっと遅れましたが
一応この問題の本質は,できるだけ短い行数で,だったと思いますので,逆に長くって面白いですね.
しかし,短くってのも,ある程度やっているプログラマでも意外にできない人いるんですよね…….この前,経験3年目の集団でやったら10人いて3人しかできませんでした(C/C++)
悲しくなります.新人でやれると,「おっ」っと思いますよ.
そして大抵センス○です

ひでみ

こんばんわです。ひでみです。

たいたいさん。
Google問題にかまけててすっかり放置状態になってました。すみませんでした。

> この前,経験3年目の集団でやったら10人いて3人しかできませんでした(C/C++)
> 悲しくなります.新人でやれると,「おっ」っと思いますよ.

すると、この記事の元ネタになった記事に書いてあったことは、かなり信憑性が高いわけですね。
確かにそれは悲しくなる……。

はじめまして、どこからか流れてきてこの問題にぶち当たったので僕も解答してみます。
c++で関数ポインタと再帰です。

#include
#include

std::string FizzBuzz( int , int , std::string (*)(int) );
std::string FizzString( int );
std::string BuzzString( int );
std::string FizzBuzzString( int );
std::string IntString( int );

int main(int argc, char* argv[])
{

 return printf( FizzBuzz( 1 , 100 , IntString ).c_str() ) == -1 ? -1 : 0 ;
}

std::string FizzBuzz( int count , int max , std::string (*Func)(int) ){
 if ( count > max ) {
  return "\n";
 } else {
  return Func( count ) + FizzBuzz( count + 1 , max ,
   ( ( count + 1 ) % 15 ) == 0 ? FizzBuzzString :
   ( ( count + 1 ) % 3 ) == 0 ? FizzString :
   ( ( count + 1 ) % 5 ) == 0 ? BuzzString :
   IntString ) ;
 }
}
std::string FizzString( int /* count */ ){
 return "Fizz";
}
std::string BuzzString( int /* count */ ){
 return "Buzz";
}
std::string FizzBuzzString( int /* count */ ){
 return "FizzBuzz";
}
std::string IntString( int count ){
 char buffer[ 0xff ];
 sprintf( buffer , "%d" , count );
 return buffer ;
}

朧輝

はじめまして、ひよっこプログラマです
興味深く記事とコメント読ませていただきました
無駄に長くするって言うか、再利用色々できると面白いなと思いますね
PHPくらいしか出来ませんが自分も挑戦

class clsCreateList
{
protected $vList;
function __construct(array $list=null)
{
if ($list===null)
return;
foreach ($list as $id=>$value){
if( !is_int($id) || !is_string($value) )
return;
}
$this->vList = $list;
}
function addListElement($number, $str)
{
if(!is_int($number) || !is_string($str))
return false;
$this->vList[$number]= $str;
}
function dropListElement($number)
{
unset($this->vList[$number]);
}
function getList()
{
return $this->vList;
}
}
class clsFizzBuzz extends clsCreateList
{
function execute($start, $end)
{
if( !is_int($start) || !is_int($end) )
return false;
foreach ($this->vList as $id=>$value)
{
if( !is_int($id) || !is_string($value) )
return false;
}
for($i=$start;$ivList as $id=>$value)
{
if($i%$id===0)
$s .= $value;
}
if(strlen($s)===0)
$s .= $i;
$s .= "";
echo $s;
}
}
}
$s = new clsFizzBuzz(array(1=>"Bag"));
$s->dropListElement(1);
$s->addListElement(3, "Fizz");
$s->addListElement(5, "Buzz");
$s->execute(1, 100);

問題見てから大体20分位かな?
未熟だと痛感するばかり……

ひでみ

こんばんわです。ひでみです。FizzBuzzの方はひさしぶりですねえ。


求職PGさん。

コメントの日付が11月25日になってる……が~ん……多分、『ググるな危険』の騒ぎにまぎれて見落としてました。
本当にすみません~……って、今頃、レス書いても気づかれないですね、きっと。

関数ポインタというのはありそうでなかったと思います。C++ってやっぱりおもしろいです。


朧輝さん。

> 無駄に長くするって言うか、再利用色々できると面白いなと思いますね

わざわざ長くすると、言語の特徴がでやすくなるような気がします。
ここのコメント欄はちょっとした言語のカタログになっている感じで、とてもおもしろいです(かえすがえすも私のマルチスレッドパターンがヘボくて気に入らない)。
プログラミングのおもしろさを少しでも感じていただければうれしいと思います。

> 問題見てから大体20分位かな?
> 未熟だと痛感するばかり……

いえいえ、20分でこれが書けるなら、「ひよっこ」とはとても呼べませんよ。

あえら

FizzBuzz問題は剰余は使っちゃいけませんよ

コメントを投稿する