はじめに
出題者のtbpgrです。
当記事では「不適切なFizzBuzzの世界」問題の優秀解答発表を行います。
記事の構成は以下のようになります。
- 出題の経緯
- 問題文
- 解答公開
出題の経緯
こちらの記事が元で, この問題を作問することになりました。
Rubyによる不適切なFizzBuzzの世界
supermomonga 様 、急な作問要望に対して快く許可いただき、誠にありがとうございます。
問題文
仕様
出力内容が以下の2種類のどちらかになっていれば、プログラムの内容は問わず正解とします。
末尾改行なし正解
12Fizz4BuzzFizz78FizzBuzz11Fizz1314FizzBuzz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829FizzBuzz3132Fizz34BuzzFizz3738FizzBuzz41Fizz4344FizzBuzz4647Fizz49BuzzFizz5253FizzBuzz56Fizz5859FizzBuzz6162Fizz64BuzzFizz6768FizzBuzz71Fizz7374FizzBuzz7677Fizz79BuzzFizz8283FizzBuzz86Fizz8889FizzBuzz9192Fizz94BuzzFizz9798FizzBuzz
末尾改行あり正解
12Fizz4BuzzFizz78FizzBuzz11Fizz1314FizzBuzz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829FizzBuzz3132Fizz34BuzzFizz3738FizzBuzz41Fizz4344FizzBuzz4647Fizz49BuzzFizz5253FizzBuzz56Fizz5859FizzBuzz6162Fizz64BuzzFizz6768FizzBuzz71Fizz7374FizzBuzz7677Fizz79BuzzFizz8283FizzBuzz86Fizz8889FizzBuzz9192Fizz94BuzzFizz9798FizzBuzz
# 改行
※ # 改行、の部分はシンタックスハイライトの都合上 # 改行 と記載していますが、実際はただの改行です。
以下に、FizzBuzzの仕様を提示しますが、あくまで参考です。
- 1から100など、一定範囲の整数列を入力として順に与えます
- 各入力に対して以下の出力を行います
- 以下の優先順でどれか一つを出力する
- 15 で割り切れる場合は FizzBuzz を出力する
- 5 で割り切れる場合は Buzz を出力する
- 3 で割り切れる場合は Fizz を出力する
- その他の場合は入力した数値をそのまま出力する
変態コードの自由度を高めるため、出力さえあっていれば処理内容は問いません。
真のFizzBuzzerは、基本仕様を守っていないと認めてくれないかもしれません。
しかし、基本仕様を破ることでより面白いコードを書けるならあるいは…。
CodeIQ MAGAZINEに掲載された際に、読み手が喜びそうなコードを想像してください。
制約
・ideoneのソースコード入力欄に貼り付けてそのまま実行できること ・標準入力は使用禁止 ・利用可能な言語はideoneで選択可能な言語とします。
解答公開
takuseno 様
タイトル:FizzBuzz
言語:C
説明文
普通のFizzBuzzです。
プログラム
#include<stdio.h>
#include<stdlib.h>
int main(){
int i;
for(i = 1;i <= 100;++i){
char* number = (char*)malloc(128);
sprintf(number,"%d",i);
printf("%s",i % 15 == 0 ? "FizzBuzz" :
i % 3 == 0 ? "Fizz" :
i % 5 == 0 ? "Buzz" : number);
}
return 0;
}
出題者コメント
問題の趣旨を無視するという不適切さを発揮していただくとともに
トップバッターとして最適な解答です。
takuseno 様、いろんな意味でありがとうございます。
amama 様
タイトル:とりあえずsubmit
言語:Bash
説明文
みりゃわかんでしょ
echo "12Fizz4BuzzFizz78FizzBuzz11Fizz1314FizzBuzz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829FizzBuzz3132Fizz34BuzzFizz3738FizzBuzz41Fizz4344FizzBuzz4647Fizz49BuzzFizz5253FizzBuzz56Fizz5859FizzBuzz6162Fizz64BuzzFizz6768FizzBuzz71Fizz7374FizzBuzz7677Fizz79BuzzFizz8283FizzBuzz86Fizz8889FizzBuzz9192Fizz94BuzzFizz9798FizzBuzz"
出題者コメント
そのまま出力する、というストレートな不適切さ。
nakazye 様
タイトル:僕のスキルが不適切
言語:Prolog(swi)
説明文
どうせだからやったことがない言語でやろうと思いました。
僕のスキルからは不適切な言語を選んでしまいましたが、コードは割と綺麗な形になったのではと思ってます。
コレがProlog的に適切かどうかはわかりませんが…。
プログラム
% fizzbuzzの仕様
% 15 で割り切れる場合は FizzBuzz を出力する
% 5 で割り切れる場合は Buzz を出力する
% 3 で割り切れる場合は Fizz を出力する
% その他の場合は入力した数値をそのまま出力する
%
% 参考文献
% http://ja.wikipedia.org/wiki/Prolog
% http://wiki.bit-hive.com/y10/pg/Prolog%B4%F0%C1%C3
% http://stackoverflow.com/questions/16776166/create-something-like-a-for-in-swi-prolog
% 条件定義
'15で割り切れる'(X) :- X mod 15 =:= 0.
'5で割り切れる'(X) :- X mod 5 =:= 0.
'3で割り切れる'(X) :- X mod 3 =:= 0.
'その他の場合'(X) :- \+'15で割り切れる'(X), \+'5で割り切れる'(X), \+'3で割り切れる'(X). % 処理上なくてもいいけど、言葉の定義に合わせる
% 結果定義
'FizzBuzzを出力する'(_) :- print('FizzBuzz').
'Buzzを出力する'(_) :- print('Buzz').
'Fizzを出力する'(_) :- print('Fizz').
'数値をそのまま出力する'(X) :- print(X).
% 処理定義
'Fizz?Buzz?FizzBuzz?'(X) :-
'15で割り切れる'(X) -> 'FizzBuzzを出力する'(X);
'5で割り切れる'(X) -> 'Buzzを出力する'(X);
'3で割り切れる'(X) -> 'Fizzを出力する'(X);
'その他の場合'(X) -> '数値をそのまま出力する'(X).
% 1〜100を渡す
:- forall(between(1,100,I), 'Fizz?Buzz?FizzBuzz?'(I)).
出題者コメント
適切を目指しているものの、不適切にしか実装できない(と自身では思っている)自身の不適切さ、
という意味での「不適切なFizzBuzz」ですね。
きっとProlog界の方がアドバイスをくださるのではないでしょうか。
ちなみに、nakazye様はちょっと前にバズっていたProgrammer Profileの作者さんです。
バズっていた記事は以下。
趣味プログラミングの勧め:仕事しながら1週間で作ったサービスを紹介してみる
Programmer Profileは以下。
http://www.programmerprofile.net/
このサービス自体面白いコンセプトですし、生煮えでも物怖じせず公開する姿勢は
見習うべきだと感じています。
todaemon 様
タイトル:時計ぽくFizzBuzz
言語:Ruby
説明文
3,5,15の周期を剰余計算ではなく時計ぽく回る配列を用いました。
プログラム
class Fizzbuzz
def initialize()
@idx = 0
@f=["","","Fizz"]
@b=["","","","","Buzz"]
end
def get()
ret = @f[0]+@b[0]
@idx += 1
@f.rotate!
@b.rotate!
ret.empty?? @idx.to_s : ret
end
end
fb=Fizzbuzz.new()
100.times{print fb.get}
出題者コメント
確かに回ってます。
suppy193 様
タイトル:第5回デスマコロシアム
言語:C
説明文
しまった。間違えて、第5回デスマコロシアムに挑戦してた! しかも、言語最短ではないという中途半端。
プログラム
main(i){for(;i<101;i++)printf((i%15<1)?"FizzBuzz":(i%5<1)?"Buzz":(i%3<1)?"Fizz":"%d",i);}
出題者コメント
出題者の掲載したい心をくすぐるという意味では一番狡猾な解答でした。
歌○さんをヨイショして座布団をもらう昇○さんのようなテクニック。
※デスマコロシアムは私が出題しているシリーズ物の問題。
第5回は FizzBuzz を出力する問題でした。
チョコレートバー 様
タイトル:シンプルに不適切なFizzBuzz
言語:Java
説明文
FizzBuzzにおいて、3と5、という数字は非常に意味のある数字です。
というか、この数字じゃないと駄目。
T(n)=T(n-1)+n
という数列、つまり1,(1+2=)3,(3+3=)6,(6+4=)10,(10+5)15…という数列を考えます。
この数列において、Fizz,Buzzとなる条件はそれぞれ偶数回目の3の倍数および偶数回目の5の倍数です。
なぜか?
n+(n+1)+(n+2)=3n+3で3の倍数に、n+(n+1)+(n+2)+(n+3)+(n+4)=5n+10で5の倍数になるからです。
つまり、fizz条件以外の数の和は3の倍数でfizz条件に、buzz条件以外の数の和は5の倍数になるのです。
この性質を利用したのがSumFizzBuzzです。
まず、IntStreamで1,2,…99,100という数列を作り、それをmapで1,3,6,10,15…という数列に変換しています((t->sumval+=t)。
さらにそれをFizzBuzz文字列に変換するのですが、この際にboolean型の変数を用いて2回に1回だけFizz/Buzzに変換します。
それ以外のケースでは本来の数字を出力するのですが、T(n)=T(n-1)+nという数列に変換してしまったため、元の数字がわかりません!
そこでピタゴラスの定理の登場です。
ピタゴラスの定理ではT(n)=T(n-1)+nの数列の値x=(n+1)(n)/2で求められます。
そのため、sqrt(x2)=n+α(α<1)となります。
それが(int)Math.sqrt(sum2)の意味です。
プログラム
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.IntStream;
class SumFizzBuzz {
private static final int FIZZ_INDEX=0;
private static final int BUZZ_INDEX=1;
private static int sumval=0;
public static void main(String[] args) {
boolean[]fizzbuzz={true,true};
IntStream.rangeClosed(1,100).map(t->sumval+=t)
.mapToObj(sum->{
StringBuilder ret=new StringBuilder();
if(sum%3==0 &&(fizzbuzz[FIZZ_INDEX]=!fizzbuzz[FIZZ_INDEX]))
ret.append("Fizz");
if(sum%5==0 &&(fizzbuzz[BUZZ_INDEX]=!fizzbuzz[BUZZ_INDEX]))
ret.append("Buzz");
return ret.length()==0?String.valueOf((int)Math.sqrt(sum*2)):ret.toString();
}).forEach(System.out::print);
}
}
出題者コメント
非常に丁寧でわかりやすいコメントにコンパクトなコード。
StreamAPI を活用している点など「新鮮な Java のコード」ですね。
サスペンド 様
タイトル:Pythonワンライナー
言語:Python
説明文
- 一文字変数を使いすぎている
- 分かりにくい長いlambda式を利用している
- python -c … とすればシェルから実行できる ( pythonコマンドが利用できないためideoneでは無理です )
プログラム
print(''.join(tuple(map(lambda x:'FizzBuzz x x Fizz x Buzz Fizz x x Fizz Buzz x Fizz x x'.replace('x',str(x)).split()[x%15],map(lambda x:x+1,range(100))))))
出題者コメント
インデントによる可読性を意識している Python だからこそ不適切さを強く実感できる ワンライナーの解答です。
リーシェル 様
タイトル:15
言語:C
説明文
3と5の剰余判定なので、最小公倍数の15でケース分けできます。
ということで、15までで実際に行ってみると以下のようになります。
“12Fizz4BuzzFizz78FizzBuzz11Fizz1314FizzBuzz”
ここで、文字や数字が連結している部分を考えてみると、以下の法則になります。
任意の数の15の剰余をnとすると、
n mod 8 = 3 以外の奇数のとき、数字か文字(FizzかBuzz)が連続する
n mod 9 = 3 のとき、単独でFizzが表示される
n mod 9 = 0 のとき、FizzBuzzが表示される
n = 5 のとき、BuzzFizzが表示される
n mod 6 = 1 のとき、数字が連続する
ということで、これをプログラミングしてみました。
プログラム
#include <stdio.h>
main(){
int n;
for(n=1;n<101;n++){
if((n % 15) % 9 == 3){
printf("Fizz");
}
else
if((n % 15) % 9 == 0){
printf("FizzBuzz");
}
else
if(n % 15 == 5){
printf("BuzzFizz");
}
else
if((n % 15) % 6 == 1){
printf("%d%d",n,n+1);
}
else
printf("%d",n);
if(((n % 15) % 2 == 1) && ((n % 15) % 8 != 3)){
n++;
}
}
}
出題者コメント
FizzBuzz の定石を外す不適切さ。
%20 様
タイトル:素因数分解を用いたFizzBuzz
言語:Perl
説明文
○ 1行目:なくても動きます。飾りです。
○ 2行目:FizzBuzzする下限($from)と上限($to)を定義します。
○3~ 5行目:1~$toの全ての整数に対して、素因数分解をします。
○6~11行目:$from~$toの全ての整数に対して以下の処理をします。
・7~ 9行目:その数を素因数分解した結果を表示。(コメントアウトしてあります)
・ 10行目:その数が2番目に小さい素数(すなわち3)を素因数としてもつならばFizzを表示。
その数が3番目に小さい素数(すなわち5)を素因数としてもつならばBuzzを表示。
その数が3,5いずれをも素因数としてもたないならばその数自身を表示。
プログラム
#!/usr/bin/perl
$from=1;$to=100;
for($n[1][0]=@p=$i=1;$i++<$to;$i-$j||++$n[$i][push(@p,$i)-1]){
for($k=@n[$j=$i];++$k<@p&&$j-1;$j/=$p[$k],++$n[$i][$k]until$j%$p[$k]){}
}
for($_=$from-1;$_++<$to;){
# print"$_";$j='=';
# for($i=-1;++$i<@p;$j='*'x print" $j $p[$i]"."^$n[$_][$i]"x($n[$_][$i]>1)if$n[$_][$i]){}
# print"\n";
($n[$_][2]&&print'Fizz')+($n[$_][3]&&print'Buzz')||print
}
出題者コメント
素数を用いてスマートに FizzBuzz を出力しており、 不適切という言葉が似合わない美しい解答ですね。
Ca65 様
タイトル:いろんなJSでフィズバズする
言語:JavaScript(rhino),JavaScript(spidermonkey),node.js
説明文
引数が一つしか与えられていない場合は、その数字に対して判定して答えを出力。
引数が二つ与えられた場合は、範囲指定と解釈してその範囲内の数字を判定して出力。
プログラム
(function () {
var min = arguments[0],
max = arguments[1]||"UNDEFINED";
var wrap = {};
wrap.isFizz = function (n) {
var r = n % 3 ? 0 : 'Fizz';
return r;
};
wrap.isBuzz = function (n) {
var r = n % 5 ? 0 : 'Buzz';
return r;
};
wrap.isFizzBuzz = function (n) {
var r = n % 15 ? 0 : 'FizzBuzz';
return r;
};
var _returnArray = [];
function log(str){
try{
console.log(str);
}
catch(e){
print(str);
}
};
var _returnString=wrap.isFizzBuzz(min) || wrap.isBuzz(min) || wrap.isFizz(min) || min;
if(max==="UNDEFINED"){
log(_returnString);
return;
}
while (min != max + 1) {
_returnArray.push(wrap.isFizzBuzz(max) || wrap.isBuzz(max) || wrap.isFizz(max) || max);
max--;
}
_returnString = _returnArray.reverse().join('');
log(_returnString);
}(1,100));
出題者コメント
「いろんなJSでフィズバズする」というコンセプトが面白いですね。
フィズバズをカタカナにしている点も、良い不適切さが漂っています。
Blankstare 様
タイトル:単純にputs
言語:Ruby
説明文
出力内容をputsするだけのプログラムです。
出力内容をコピー&ペーストするのが面倒だったので、「出力内容をputsするだけのプログラム」を作ってevalすることにしました。
大事なことなので二度言いますが、あくまでこれは、「出力内容をputsするだけのプログラム」です。
プログラム
def fizzbuzz( from, to, conveter )
[ "puts '", ( from .. to ).map { | i | conveter[ i ] }, "'" ].join
end
def conv( array )
lambda { | i | array.map { | j | j[ i ] }.tap { | a | break i if a.none? } }
end
def cond( x, s )
lambda { | i | s if ( i % x ).zero? }
end
eval fizzbuzz 1, 100, ( conv [ ( cond 3, 'Fizz' ), ( cond 5, 'Buzz' ) ] )
出題者コメント
面倒とは一体。
akouryy 様
タイトル:ぴょんぴょん
言語:Ruby
説明文
ぴょんぴょん
全てがぴょんぴょんしているコードです。ぴょんぴょんを普通の名前に戻しても決して読みやすくありません。
***_missing フックと undef、いろいろな種類の [] メソッドを使ったり、sortのブロックに副作用を渡して悪用しています。
「001」「100」「ぴょん」に見えるリテラル以外を排除したので”Fi”と”Bu”と”zz”を作るのに苦労しました。
Rubyのordはぴょんぴょん可能性があって良いですね。
ぴょんぴょん
プログラム
#ぴょんぴょんcoding:utf-8ぴょんぴょん
tap{|ぴょん|
def ぴょん.method_missing ぴょん;"#{ぴょん}".ord;end
ぴょん=ぴょん.class
def ぴょん.const_missing ぴょん;"#{ぴょん}".ord;end
}
undef p
trace_var(:$ぴょん){print$ぴょん}
ぴょぴょ=->ぴょん{ぴょん.size}
ぴょん=->ぴょん{(ぴょん/0x100).chr+(~-ぴょん%0x100).chr}
ぴ=ぴょん[P*y+O*n-p-y-on]
ぴょ=ぴょん[PY*on+py*ON+ぴょぴょ[' p']*(yo*N_P-YO*n_p)-y+on]
ょん=ん=ぴょん[-(-ぴょんぴ-ょ-んぴょん)+ぴょぴょ["ぴょんぴょん"]+PYON+P+Y-O*N]
ぴょーん=ぴょぴょ[[0][0][1]]
->ぴょん{ぴょん..ぴょん+(ぴょん+ぴょん)*-(ぴーょーん+ぴーょーんーぴ-ょ-んーぴーょーん)}[[1][0][0]].sort{
|ぴょん,ぴょんぴょん|ぴょんぴょん-ぴょん<ぴょーん&&($ぴょん="#{ぴょん%~-ぴょーん==$.?ぴ+ょん :""}#{ぴょん%~ぴょーん==$.?ぴょ+ん :""}"[/[^ぴょん]+/]||ぴょん);ぴょん}
出題者コメント
ぴょんぴーょーんぴょんPYON
hanachin 様
タイトル:きれいなJavaScript
言語:JavaScript (spidermonkey)
説明文
変数を一切宣言せず、かつグローバル変数も汚さないきれいなJavaScriptです。
簡単に説明すると以下のようなコードです。
this.print(文字列を組み立てる処理);
文字列を組み立てる処理では、FizzBuzzの上限を関数の引数として受け取っています。
(function (max) { 1からmaxまでFizzBuzzする })(100);
1からmaxまでFizzBuzzするため、Zコンビネータを使って関数に名前をつけずに再帰しています。
((function (f) {
return (function (p) {
return f(function (arg) {
return (p(p))(arg); }); })(function (p) {
return f(function (arg) {
return (p(p))(arg); }); }); })(function (f) {
return function (n) {
/* 略 */
// この中でfを呼ぶとこの関数自身が呼ばれる
// tはnをFizzBuzzの文字列にした結果にf(n+1)を呼び出した結果を連結して返す関数
return n <= max ? t() : end();
/* 略 */
}
}))(1); // ↑の関数を引数1で呼び出す
ごく普通の変数を使わないFizzBuzzですね。
プログラム
this.print((function (max) {
return ((function (f) {
return (function (p) {
return f(function (arg) {
return (p(p))(arg); }); })(function (p) {
return f(function (arg) {
return (p(p))(arg); }); }); })(function (f) {
return function (n) {
return (function (t) {
return (function (end) {
return n <= max ? t() : end(); })(function () {
return ""; }); })(function () {
return (function (str) {
return (((function (str) {
return "" !== str ? str : n; })((function (str) {
return ((n % 5) ? str : (function (str2) {
return str + str2; })("Buzz")) })((function (str) {
return ((n % 3) ? str : (function (str2) {
return str + str2; })("Fizz")); })("")) ))) + str; })(f((function (x) {
return n + x; })(1))); }); }}))(1); })(100));
出題者コメント
>変数を一切宣言せず、かつグローバル変数も汚さないきれいなJavaScriptです。
きれい…見た目は綺麗ですね、ある意味。
>ごく普通の変数を使わないFizzBuzzですね。
普通ってなんだろう、と考えさせられます。
neko_the_shadow 様
タイトル:逆転の発想
言語:Ruby
説明文
メソッド名やメソッドの戻り値などをいろいろと「逆転」させてみました。
トップレベルだけ見るとわけわからないことになっています。
書いたわたしも頭が爆発しそうになりました。
class Range
# (10..1)のようなRangeオブジェクトを反転させ、順にブロックを実行する。
def hcae
range = Range.new(self.last,self.first)
range.each{|r| yield(r)}
end
end
# 引数がfalseならブロックを実行する。
def fi(bool)
yield unless bool
end
# 引数がtrueならブロックを実行する。
def sselnu(bool)
yield if bool
end
# 引数を逆転させて出力する。
def tnirp(arg)
if arg.class == Fixnum
print arg
else
print arg.reverse
end
end
# 引数が5で割り切れたらfalse、割り切れなければtrue。
def zzif(i)
!(i % 5 == 0)
end
# 引数が3で割り切れたらfalse、割り切れなければtrue
def zzub(i)
!(i % 3 == 0)
end
# == main ==
(100..1).hcae{|rebmun|
fi (zzub(rebmun)) {tnirp "zziF"}
fi (zzif(rebmun)) {tnirp "zzuB"}
sselnu (zzub(rebmun) && zzif(rebmun)) {tnirp rebmun}
}
出題者コメント
鏡の中に迷い込んだかのような不適切さ。
さて、実はもう一点不適切な解答であることを挑戦者様から
コメントいただいているのですが、個人情報になるので公開できないのが残念です。
公開できない不適切さを含んでいる、という意味の不適切さでもあるわけですね。
ryo-pinus 様
タイトル:悪いなのび○、このC#のコード、Mono専用なんだ。
言語:C
説明文
【概要】
本プログラムは、.NET Framework互換環境であり、ideone.comで使用されているMono環境でのみ、期待した動作となるコードとなります。
Microsoftが提供する.NET Framework環境では正常に動作いたしません。
【実装方式】
本プログラムの実装では、割り切れる数をString#GetHashCodeから求める方式を採用しています。
例えば、”FizzBuzz”の割り切れる数「15」を求める場合は、「”FizzBuzz”.GetHashCode() – “FizzBuzk”.GetHashCode()」の結果を使用します。
【参考資料】
1.Mono環境におけるString#GetHashCodeの戻り値
“FizzBuzz”:-251213610
“FizzBuzk”:-251213625
“Fizz”:2190179
“Fizw”:2190176
“Buzz”:2082547
“Buzu”:2082542
2.NET Framework4.5環境におけるString#GetHashCodeの戻り値
“FizzBuzz”:-94704318
“FizzBuzk”:1007676738
“Fizz”:-1526827758
“Fizw”:-1864534766
“Buzz”:-1526565610
“Buzu”:-1481935594
3.MonoのString#GetHashCodeの実装
https://github.com/mono/mono/blob/master/mcs/class/corlib/System/String.cs
4.NET Framework4.5.2のString#GetHashCodeの実装
http://referencesource.microsoft.com/#mscorlib /system/string.cs
using System;
using System.Linq;
public class Test
{
public static void Main()
{
var fizzBuzz = new[] { new { s1 = "FizzBuzz", s2 = "FizzBuzk" }, new { s1 = "Fizz", s2 = "Fizw" }, new { s1 = "Buzz", s2 = "Buzu" }, };
foreach (var n in Enumerable.Range(1, 100))
{
var result = fizzBuzz.FirstOrDefault(_ => (n % (_.s1.GetHashCode() - _.s2.GetHashCode())) == 0);
if (result != null)
{
Console.Write("{0}", result.s1);
}
else
{
Console.Write("{0}", n);
}
}
Console.WriteLine();
}
}
出題者コメント
秀逸なタイトル, 不適切な実装, 適切な説明 すきがないですね。
Cartman0 様
タイトル:昔流行ったギャグ
言語:Python 3
説明文
3の倍数のときアホになり、5の倍数のときバカになり、15の倍数のときアホバカになるゲーム
# coding: utf-8
# 3の倍数のときアホになり、5の倍数のときバカになり、15の倍数のときアホバカになるゲーム
AHO = "Fizz"
BAKA = "Buzz"
if __name__== "__main__":
min_in = 1
max_in = 100
for i in range( min_in, max_in + 1 ):
game = ""
if i % 3 == 0:
game = AHO
if i % 5 == 0:
game += BAKA
if game == "":
game = i
print( game, end="" )
出題者コメント
シンプルだけど好きです、こういうの。
NeoCat 様
タイトル:猫猫猫(本当は猫の絵文字だったのですが、CodeIQ MAGAZINEの制約上変更しました)
言語:Ruby
説明文
以下のコードを、aliasなどを使って猫の絵文字に置き換えたものです。
(1.100).map{|x| print x%5 != 0 ? x%3 != 0 ? x : :Fizz : x%3 != 0 ? :Buzz : :FizzBuzz }
数値 n は 0 に succ メソッドを n 回適用することで作っています。
なお、自分で絵文字を定義するのは面倒だという方も、
ActiveEmoji という
「絵文字を使ってこどもや英語がわからない人にもにも簡単にRubyプログラムが読み書きできる」gemが公開されていますので、
これを使えばすぐに絵文字プログラミングを始められるでしょう。
※都合によりソースコードの一部をキャプチャして掲載致します
出題者コメント
まさかのEmojiプログラミング。
Active Emojiは以前私も試してみました。
Active Emoji で Hello, world!
ふぉぐ 様
タイトル:仲良し3人組と嫌われ者
言語:C++ 4.9.2
説明文
first君、second君、third君は仲良し3人組。
今日は3人でFizzゲームをすることにしました。
順番に数字を言っていきますが、3で割り切れる数の時には”Fizz”と叫ぶゲームです。
first君から順番に始めることになりましたが、面白くないのが嫌われ者のnuisance君。
いつも意地悪ばかりするので、今日も誘われなかったのです。
そこで、時々邪魔をすることにしました。
さて、3人でfizzゲームを始めてしまった3人組と、微妙に几帳面に邪魔をする嫌われ者はどうなってしまうのでしょうか。
尚、4人の平均年齢は28歳です。
#include <iostream>
using namespace std;
class man
{
public:
static int counter;
};
int man::counter = 0;
class count_man : public man
{
public:
void shout()
{
counter++;
if(!(counter % 5))
throw "うわっ!何をする!やめろ!\n";
cout << counter;
}
};
class fizz_man : public man
{
public:
void shout()
{
counter++;
cout << "Fizz";
if(!(counter % 5))
throw "ふっ。既に叫び終わっているわ。\n";
}
};
class buzz_man : public man
{
private:
int limit;
public:
buzz_man(int i)
{
limit = i;
}
int shout()
{
cout << "Buzz";
cerr << "ひゃっはー!\n";
return counter >= limit ? -1 : counter % 3;
}
void end_of_the_world()
{
cerr << "バルス!\n";
}
};
int main()
{
const int limit = 100;
int victim = 0;
count_man *first = new count_man();
count_man *second = new count_man();
fizz_man *third = new fizz_man();
buzz_man *nuisance = new buzz_man(limit);
while(1)
{
try
{
switch(victim)
{
case 0: first->shout();
case 1: second->shout();
case 2: third->shout();
default: victim = 0;
}
}
catch(const char *e)
{
cerr << e;
if((victim = nuisance->shout()) < 0)
{
nuisance->end_of_the_world();
break;
}
}
}
return 0;
}
標準出力は仕様通りなのですが、標準エラーにも出力が行われる手の込みようです。
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
ふっ。既に叫び終わっているわ。
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
うわっ!何をする!やめろ!
ひゃっはー!
バルス!
出題者コメント
素晴らしい世界観です。
ひゃっはー!
cia_rana 様
タイトル:shiftしまくりたい症候群
言語:Ruby
説明文
shiftをしたくてしたくてたまらなかったので
shift尽くめにしてみました。
# cording: utf-8
# 3の倍数判定
def mul3(n)
n = ((n >> 4) & 0x0f) + (n & 0x0f)
n = ((n >> 4) & 7) + (n & 0xf)
(0x9248 >> n) & 1 == 1
end
# 5の倍数判定
def mul5(n)
n <<= 1
m = (n * 0xcccccccd >> 35) << 1
n ^ m + (m << 2) == 0
end
# FizzBuzzをつくる
def make_fizz_buzz
z = '>'.ord + '<'.ord
b = ('>'.ord + ~'<'.ord << 2) + '>'.ord
f = ('>'.ord + ~'<'.ord << 2) + b.ord
u = (Time.now.year >> 4) + ~('>'.ord >> 3)
i = (f.ord + ~b.ord << 5) + (((f.ord << 1) + ~b.ord) >> 3)
[[f, i, z, z], [b, u, z, z]].map { |fb| fb.pack 'c*' }
end
# FizzBuzzする
def play_fizz_buzz(length)
(1..length).each.inject('') do |memo, n|
fizz_buzz_n = FIZZ_BUZZ + [n.to_s]
r, s = 4, 2
r, s = r>>2, s+1 if mul3(n)
r, s = r>>1, s+1 if mul5(n)
memo << fizz_buzz_n.rotate(r>>1).shift(s >> 1)*""
end
end
# Main
FIZZ_BUZZ = make_fizz_buzz
puts play_fizz_buzz(100)
出題者コメント
# ruby
print *"y".chars.to_a<<'o'<<'u'<<' '<<'a'<<'r'<<'e'<<' '<<'s'<<'h'<<'i'<<'f'<<'t'<<' '<<'m'<<'a'<<'n'<<'i'<<'a'
angel 様
タイトル:言語が不適切なFizzBuzz
言語:Brainf**k
説明文
使い回し感が満載ですが。
書くだけでネタ扱いされる美味しい^H^H^H^H厄介な言語を逃す手はありません。
暗号めいて他人に読ませる気ゼロの、自分ですら何やってるか分からなくなる不適切な可読性。
四則演算ですら一部しかなく、望みの値をセットするだけでも難儀する不適切な機能性。
( 比較して、同じ難読系でもWhitespaceは読みにくいだけで、機能としては素直です )
そして1文字間違えただけで簡単に暴走し無限ループを引き起こす、危険で不適切な動作性。
とある言語は「コンパイルが通ればバグはない」と豪語されているそう ( 未確認 ) ですが、
こちらは「正常終了すればバグはない」と言えましょうか。( 言い過ぎ )
最後に。
本当に何より不適切なのは…。
口にしただけで下ネタ特定されかねない、その卑猥で不適切な言語名。
ですので、使う時には伏字は欠かせません。適切な伏字をゆめゆめ忘れる事のないよう。
例えば Brainf*ck とか…ね。
( Brainf*ck の部分は本当は天狗の絵文字だったのですが、Emoji に対応していないため、変更しました )
++++++++[<<+<++<++[++++>]>-]++++>>+++++++[>>++++++>->++++[+++++++++++<]<-]>>+++<++<<<<<[<+>>>>>+>[-<-]<[->++>>.>.<<..<<<<<->>]+<[->-]>[->>>>----.++++<-----.+++++..<<<<++++<[+]-<--<<<[-<+<+>>>+>----------<<]+<[->-<]>>>>>>>>]<<<+[<<<<<<[>>>.<<]<[<]>>>>>.>>-]<]
出題者コメント
>使い回し感が満載ですが。
ちょうど同時期に倫理的に不適切な出題者による Brainf*ck で FizzBuzz を書く問題が出題されていました。
プログラムの問題にも関わらず、コメント内容で掲載が決まるという良例です。
tails 様
タイトル:寝ながら並列処理
言語:Bash
説明文
なぜかうまく動きません!
誰か完成させてください…
( for x in `seq 33` ; do sleep 0.12 ; echo -n Fizz ; done ) &
( for x in `seq 25` ; do sleep 0.20 ; echo -n Buzz ; done ) &
( for x in `seq 100` ; do sleep 0.04 ; echo -n $x ; done )
出題者コメント
不正解ですがわざと不正解にしていることと、面白いので。
実行結果はこうなりました。
12Fizz34Buzz5Fizz678Fizz9Buzz1011Fizz121314BuzzFizz151617Fizz1819Buzz20Fizz212223Fizz24Buzz2526Fizz272829BuzzFizz303132Fizz3334Buzz35Fizz363738Fizz39Buzz4041Fizz424344BuzzFizz454647Fizz4849Buzz50Fizz515253Fizz54Buzz5556Fizz575859BuzzFizz606162Fizz63Buzz6465Fizz666768FizzBuzz697071Fizz7273BuzzFizz747576Fizz7778Buzz79Fizz808182Fizz83Buzz8485Fizz868788BuzzFizz899091Fizz9293Buzz94Fizz959697Fizz98Buzz99100
naoki_kp 様
タイトル:隠密
言語:Whitespace
説明文
誰にも気づかれずにFizzBuzzを出力することができます。
※スペースは S, タブは T に変換してあります。
本来のコードは何も見えません。
SSS SS SSST TSSSSSS STSST SSTTT TSTT TTS STT SSS STSST SSTTST TSTT TTTS STTT SSTS TTTSS S ST ST SSTSS S SSSSTTSSSTT TSST TT SSTT SSSTTTSTST SSSTSSSSTS S TST SST SSSTTSTSST SSSTSSSTTS SSTST T SST SSSSSTTTTSTS S ST SST SSSSST TSST T
出題者コメント
シンプルかつ不適切です。
さすが忍者、汚い(解答者様コメントより引用)。
nyuki 様
タイトル:不適切な再利用
言語:Falcon
説明文
偶然にも手元にbrainf**kで記述したFizzBuzzのコードがあったので、
それらを有効活用するためにFalconでbrainf**kの(中途半端な)処理系を実装しました。
なるべく新規のコードは書きたくなかったのですが
Falconでの処理系が見つからなかったのでしょうがないですね。
src = "++++++[->++++>>+>+>-<<<<<]>[<++++>>+++>++++>>+++>+++++>+++++>>>>>>++>>++<<<<<<<<<<<<<<-]<++++>+++>-->+++>->>--->++>>>+++++[->++>++<<]<<<<<<<<<<[->-[>>>>>>>]>[<+++>.>.>>>>..>>>+<]<<<<<-[>>>>]>[<+++++>.>.>..>>>+<]>>>>+<-[<<<]<[[-<<+>>]>>>+>+<<<<<<[->>+>+>-<<<<]<]>>[[-]<]>[>>>[>.<<.<<<]<[.<<<<]>]<<<<<<<<<<]"
jmp = arrayBuffer(src.len())
mem = arrayBuffer(1024)
tmp = []
mp = ip = 0
for i in mem: .= 0
for i in [0:src.len()]
switch src[i]
case "[" : tmp += [i]
case "]" : jmp[jmp[i] = arrayTail(tmp)] = i
end
end
while ip < src.len()
switch src[ip]
case "+" : mem[mp]++
case "-" : mem[mp]--
case ">" : mp++
case "<" : mp--
case "[" : if mem[mp] == 0 : ip = jmp[ip]
case "]" : ip = jmp[ip] - 1
case "." : >>chr(mem[mp])
end
ip++
end
出題者コメント
コード自体にとどまらない、不適切さを遺憾なく発揮しておられます。 手元にあるコードを利用する不適切さ。 そもそも 偶然手元に brainf**k で記述した FizzBuzz のコードがある不適切さ。 よりにもよって、 Falcon で処理系を実装する不適切さ 。
また、コメントの言い回しが趣深い。 いろいろ含めて秀逸です。
せきゅあ 様
タイトル:Recursive Anonymous Klasses
言語:Ruby
説明文
匿名クラスを再帰で作りつつ、
関数型プログラミング風にFizzBuzzの文字列を組み立てました。
副作用なしで作れたと思います。
def fizzbuzz
Class.new(String) do
def characters
n = self.to_i
s = 'FizzBuzz'[(i=n**4%-15+1)==1?0:i,i+12]||self
if n > 1
fizzbuzz.new("#{n-1}").characters + s
else
s
end
end
end
end
print fizzbuzz.new("100").characters
出題者コメント
再帰+Ruby の黒魔術を利用した不適切コードですね。
Ruby を知らない方のために補足しておくと、 Class.new(String) は
String クラスを継承した匿名クラスを生成し、 fizzbuzz メソッドの戻り値にしています。
tatsy 様
タイトル:I love Fizz Buzz
言語:Ruby
説明文
I love Fizz Buzz
(必ず等幅フォントでご覧ください)
プログラム
出題者コメント
愛を感じます
hattori 様
タイトル:縛って汚コード(FizzBuzz問題)
言語:C99 Strict
説明文
いろいろ縛って書いてみました
1. C99規格準拠(警告も許さない)
2. 文字列定数は1個
3. if文および3項目演算子使用不可
4. 文字列出力関数呼んでいいのは100回まで
というかただのショートコード崩れ
プログラム
#include <stdio.h>
#define S "\t\f\4\0FizzBuzz\0%d\0Fizz"
#define FizzBuzz(i) printf(S+4+S[!(i%5)*2+!(i%3)],i)
int main() {
for (int i = 1; i < 101; i++) {
FizzBuzz(i);
}
return 0;
}
出題者コメント
タイトルで掲載を決めました
なおう 様
タイトル:読みにくいけど、少し目を凝らせば読めるくらいのFizzBuzz
言語:Ruby
説明文
タイトル通りです!
一瞬あれ?って思うけど、少し目を凝らせば意図が伝わるくらいを狙ってみました!
そこそこ抽象化したようなクラスや、
map とか any? が大好物なので、
好きなモノをたくさん使って作ってみました。
満足。
プログラム
class Checker
def initialize(msg, count)
@msg = msg; @count = count; @alive = false
end
def process
@alive &&= @num >= @count
@num -= @num > @count ? @count : 0
(@hit ||= @num == @count) ? @msg : ''
end
def setNum(num)
@num = num; @alive = true; @hit = false
end
def alive?; @alive end
def hit?; @hit end
def destroy; @alive = false end
end
checkers = [Checker.new('Fizz', 3), Checker.new('Buzz', 5), Checker.new('FizzBuzz', 15)]
(1..100).each do |i|
checkers.each {|c| c.setNum(i)}
while checkers.any?(&:alive?); checkers.tap{|c| print c.map(&:process).join}.any?(&:hit?) && checkers.each(&:destroy) end
checkers.none?(&:hit?) && print(i)
end
出題者コメント
好きなモノで実装する、という不適切さ。
そして、読み解くのに一定の Ruby 力が必要とされるコードです。
あなたは読めますか?
kusohako 様
タイトル:たらいまわしFizzBuzz
言語:C
説明文
たらいまわし関数を利用したFizzBuzzです。
たらいまわし関数は処理をたらいまわしにする関数で、
適当な引数を与えると膨大な再帰呼び出しを行います。
wikipediaにある定義のものを用いました。
このたらいまわし関数をメモ化し、
再帰処理を行う場合の回数が100となるような引数を与えることで
カウンタ変数からたらいまわし関数内でFizzBuzzの出力を行います。
プログラム
c,m[12][12][12];
tarai(x,y,z){
if(x<=y)return y;
if(m[x][y][z])return m[x][y][z];
printf(c%3?c%5?"%d":"Buzz":c%5?"Fizz":"FizzBuzz",++c);
return m[x][y][z]=tarai(tarai(x-1,y,z),tarai(y-1,z,x),tarai(z-1,x,y));
}
main(){c=!tarai(10,0,11);}
出題者コメント
たらいまわしという言葉の響き自体不適切ですよね。
kabio7 様
タイトル:妖精さんのお仕事
言語:C
説明文
寝ていたら(zzzzzz)妖精さんが完成させてくれた!
=========================以下妖精=========================================
最初にFizzとBuzzのzzだけをすべて並べて
後から順に5で割れたらBu、3で割れたらFiそれ以外は数字を
zzの文字列に足していきました。
足す場所は3や5で割り切れる場合は2個前にずらし
そうでない場合は前の文字を埋めた場所と同じところに文字を挿入していきます。
プログラム
using System;
public class Test
{
public static void Main()
{
Console.Write(WorkOfFairies("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"));
}
public static string WorkOfFairies(string zzz)
{
int maxnum = 100;
int warinum = maxnum / 3 + maxnum / 5;
string out_str = zzz.PadLeft(warinum * 2, 'z');
for (int i = maxnum; i > 0; i--)
{
if (warinum == ((i - 1) / 3 + (i - 1) / 5))
{
out_str = out_str.Substring(0, warinum * 2) + i + out_str.Substring(warinum * 2);
}
if (i / 5 != ((i - 1) / 5))
{
out_str = out_str.Substring(0, (warinum - 1) * 2) + "Bu" + out_str.Substring((warinum - 1) * 2);
warinum--;
}
if (i / 3 != ((i - 1) / 3))
{
out_str = out_str.Substring(0, (warinum - 1) * 2) + "Fi" + out_str.Substring((warinum - 1) * 2);
warinum--;
}
}
return out_str;
}
}
出題者コメント
最近 CodeIQ の採点に力を注ぎすぎて、深夜に PC の前で寝落ちする私にも
「寝たる間に勝手にフィードバックしてくれる妖精さん」
が欲しいです。
えちごやえちぜん 様
タイトル:不適切なまるなげ返し
言語:VB.NET
説明文
あら、田中クンにお願いしてた例の答案、もうできたのね。
やっと私の「まるなげ」にも慣れてきたのかしら。
どれどれ…なにコレ!?
文字が化けてて、全然読めないじゃない。
でっでも、コード理解する気なんて最初からないし?
とりあえず実行、と…あっ動いた動いた。
もうこれでいいから出しちゃえ♪
プログラム
Option explicit Off
Public Class Test
Public Shared Sub Main()
'不適切なFizzBuzz問dくぁwせdrftgyふじこlp;@:[]
魑鵺="愈猷虔榔艘虔甕靄虔艘愈愈虔愈"
魅鰤鰯="漣愈榔鑓愈囀愈甕虔愈筵艘虔猷猷猷漣虔艘猷囀虔猷"
魍霞霧="靄猷筵鑓漣愈漣猷虔漣榔艘虔漣甕漣靄虔艘榔愈虔"
魎越後="榔漣榔榔鑓榔囀榔甕虔榔筵艘虔竈"
神罰="猷竈漣虔艘竈囀虔竈靄竈筵鑓囀愈囀猷虔囀榔艘虔囀甕"
社勤務="囀靄虔艘甕愈虔甕漣甕榔鑓甕"
仏蓮華="囀甕甕虔甕筵艘虔靄猷靄漣虔艘靄囀虔靄靄靄筵"
閣僚賄="鑓筵愈筵猷虔筵榔艘虔筵甕筵靄虔艘"
礎=魑鵺+魅鰤鰯+魍霞霧+魎越後+神罰+社勤務+仏蓮華+閣僚賄
鍵="鑓愈猷漣榔竈囀甕靄筵艘虔"
For Each 漢 In 礎
j=InStr(鍵,漢)'
s &=If(j=1,"FizzBuzz",If(j=11,"Buzz", _
If(j=12,"Fizz",Trim(Str(j-1)))))
Next
Console.WriteLine(s)
End Sub
End Class
出題者コメント
まさかのシリーズ化。
そして「くぁwせdrftgyふじこ」とか小ネタの仕込みに抜かりがありません。
「シリーズ化」が何のことか分からない方は、下記の記事を「えちごやえちぜん」でページ内検索してください。
汚コードグランプリ!秀逸な汚コードにまみれた解答臭をご覧あれ
Azicore 様
出題者コメント
全国 7,777 万 の Azicore ファンの皆様、お待たせ致しました。
Brainf*ck 界のファンタジスタ、 Azicore 様の登場です。
タイトル:コードジェネレータ&インタープリタ内蔵型FizzBuzz
言語:JavaScript (rhino)
説明文
某言語のコードジェネレータとインタープリタを内蔵してしまったFizzBuzzです。
JavaScriptは、ごく普通のFizzBuzz処理(「fizzbuzz」関数)を行ない、出力直前まで行きますが、
そのまま出力すればいいものを、なぜか某言語の文字列出力用コードに変換(「codegen」関数)してしまいます。
このとき、ささやかではありますが、なるべく短いコードを探す処理(「loopgen」関数)を行なったりもしています。
それにしても生成されてしまったものは仕方ないので、内蔵のインタープリタ(「bf」関数)にコードを渡して、
最終的に元のFizzBuzzの文字列を出力させる、という流れになっています。
プログラム
String.prototype.repeat = function(n) {
return Array(Math.abs(n) + 1).join(this);
};
Number.prototype.pm = function() {
return (this >= 0 ? '+' : '-').repeat(this);
};
Number.prototype.rl = function() {
return (this >= 0 ? '>' : '<').repeat(this);
};
var bf = function(c) {
var s = [], l = {};
for (var i = 0; c.length > i; i++) {
if (c[i] == '[') s.push(i);
if (c[i] == ']') l[l[i] = s.pop()] = i;
}
var a = [0], p = 0, out = '';
for (var i = 0; c.length > i; i++) {
var o = c[i];
if (o == '[' && !a[p]) i = l[i];
if (o == ']') i = l[i] - 1;
if (o == '+') a[p]++;
if (o == '-') a[p]--;
if (o == '>') a[++p] |= 0;
if (o == '<' && p > 0) p--;
if (o == '.') out += String.fromCharCode(a[p]);
}
return out;
};
var loopgen = function(mul) {
var code = null, n = mul.length, tmp;
var min = Math.min.apply(null, mul);
var select = function(tmp) {
if (!code || code.length > tmp.length) code = tmp;
};
tmp = '[';
for (var i = 0; n > i; i++) {
tmp += '>' + mul[i].pm();
}
tmp += (-n).rl() + '+]>';
select(tmp);
for (var i = 0; +(min > 1) >= i; i++) {
tmp = '[';
for (var j = 0; n > j; j++) {
tmp += '>' + (mul[j] - i).pm();
}
tmp += '[' + i.pm() + '<]>' + (1 - i).pm() + ']>';
select(tmp);
}
var unavail = Array(min * 2 - 1);
for (var i = 0; n > i; i++) {
if (unavail.length >= mul[i]) unavail[mul[i] - 1] = true;
}
for (var i = 0; unavail.length > i; i++) {
if (!unavail[i]) {
tmp = '[>';
for (var j = 0; n > j; j++) {
tmp += '>' + (mul[j] - i - 1).pm();
}
tmp += '[' + (i + 1).pm() + '<]<+]>>';
select(tmp);
}
}
return code;
};
var codegen = function(str) {
if (str === '') return '';
var base = 8;
var code = '>' + (-base).pm();
var char, m;
var strinfo = [], mul = [], buf = {}, n = 0;
for (var i = 0; str.length > i; i++) {
char = str.charCodeAt(i);
m = (char + (base - 1 >> 1)) / base | 0;
strinfo[i] = {char: char, m: m};
if (!buf[m]) {
mul.push(m);
buf[m] = {pos: n++, val: base * m};
}
}
code += loopgen(mul);
var pos = 0, s, b;
for (var i = 0; strinfo.length > i; i++) {
s = strinfo[i];
b = buf[s.m];
code += (b.pos - pos).rl();
pos = b.pos;
code += (s.char - b.val).pm();
b.val = s.char;
code += '.';
}
code += (n - pos).rl();
return code;
};
var fizzbuzz = function(limit) {
var fizz = 'Fizz';
var buzz = 'Buzz';
var delimiter = '';
var str = '';
for (var i = 1; limit >= i; i++) {
var tmp = '';
if (i % 3 == 0) tmp += fizz;
if (i % 5 == 0) tmp += buzz;
if (tmp == '') tmp += i;
if (i > 1) str += delimiter;
str += tmp;
}
return codegen(str);
};
print(bf(fizzbuzz(100)));
- 中間生成された Brainf*ck のコード
>--------[>>---->->+++>+++++>-->---[++++++++++<]<+]>>+.+.>--.>+.>++..<<<++.>>>>++.<-----.+++++..<<.>.>..>>-.+.<<<<.>.>..>.<-----.+++++..<<<---..>.>.>..<<<.++.--.+++.>.>.>..>.<-----.+++++..<<<---.>>>>>--.<<<<<.>>>>>+.<<<<.>.>..<<<.>>>>>++.<.<-----.+++++..<<.>.>..<<<+...+.>.>.>..>.<-----.+++++..<<<-.>>>>>---.<<<<.>.>..<<<.>>>>>++.<<<<<.>>>>>+.<<<<.>.>..>.<-----.+++++..<<<+.--.++.-.>.>.>..<<<+.+.>>>>.<-----.+++++..<<.>.>..<<<-.>>>>>--.<<<<<.>>>>>+.<<<<.>.>..>.<-----.+++++..<<<+.---.>.>.>..<<<+++.-.+..>.>.>..>.<-----.+++++..<<<.>>>>>--.<<<<<.>>>>>+.<<<<.>.>..<<<.>>>>>++.<.<-----.+++++..<<.>.>..>>----.<<<<<--.>>>>>.<<<<<+.>.>.>..>.<-----.+++++..>>.+.<<<<.>.>..>>-.+++.---.++++.<<<<.>.>..>.<-----.+++++..>>---.<<<<<--.>>>>>.<<<<<+.>.>.>..>>.<<<<<++.>>>>.<-----.+++++..<<.>.>..>>.+.-.++.<<<<.>.>..>.<-----.+++++..>>-.<<<<<---.>.>.>..>>.<<<<<++.>>>>>.<<<<<+.>.>.>..>.<-----.+++++..>>.-.+..<<<<.>.>..>>.++.<.<-----.+++++..<<.>.>..>>-.<<<<<--.>>>>>.<<<<<+.>.>.>..>.<-----.+++++..>>.--.<<<<.>.>..>>++...+.<<<<.>.>..>.<-----.+++++..>>.<<<<<--.>>>>>.<<<<<+.>.>.>..>>.<<<<<++.>>>>.<-----.+++++..<<.>.>..>>.--.++.-.<<<<.>.>..>.<-----.+++++..>>>
ciel 様
言語:Whitespace+6言語
説明文
「esoteric programmingガチ勢 の皆様」とスライドショーに記述があったので、Whitespaceでがんばりました。
ただし、Whitespaceだけだと面白くないので、Ruby/Perl/C/Pike/C#/F#でも解答を作成しました。
Whitespaceは次のプログラムで生成しました。
#!/usr/bin/ruby
#coding:utf-8
def f(s)
print s if @output
s
end
def gen_label(n)
raise 'gen_label' if !n.is_a?(Integer) || n<0
n.to_s(2).tr('01'," \t")+"\n"
end
def gen_number(n)
raise 'gen_number' if !n.is_a?(Integer)
(n<0 ? "\t" : ' ')+gen_label(n.abs)
end
#stack
def push_stack(n)
f " "+" "+gen_number(n)
end
def duplicate_stack
f " "+"\n "
end
def copy_stack(n)
f " "+"\t "+gen_number(n)
end
def swap_stack
f " "+"\n\t"
end
def discard_stack
f " "+"\n\n"
end
def slide_stack(n)
f " "+"\t\n"+gen_number(n)
end
#arithmetic
def add
f "\t "+" "
end
def sub
f "\t "+" \t"
end
def mul
f "\t "+" \n"
end
def div
f "\t "+"\t "
end
def mod
f "\t "+"\t\t"
end
#heap
def store_heap(n=nil)
s=''
s=push_stack(n) if n
f "\t\t"+" "+(@output ? s : '')
end
def retrive_heap(n=nil)
s=''
s=push_stack(n) if n
f "\t\t"+" "+(@output ? s : '')
end
#flow
def set_label(n)
f "\n"+" "+gen_label(n)
end
def call(n)
f "\n"+" \t"+gen_label(n)
end
def jmp(n)
f "\n"+" \n"+gen_label(n)
end
def jz(n)
f "\n"+"\t "+gen_label(n)
end
def jl(n)
f "\n"+"\t\t"+gen_label(n)
end
def rtrn
f "\n"+"\t\n"
end
def over
f "\n"+"\n\n"
end
#IO
def printc
f "\t\n"+" "
end
def printn
f "\t\n"+" \t"
end
def readc
f "\t\n"+"\t "
end
def readn
f "\t\n"+"\t\t"
end
@output=true
push_stack(0) # start
set_label(1)
push_stack(1)
add
duplicate_stack
push_stack(3)
mod
jz(2)
duplicate_stack
push_stack(5)
mod
jz(3)
duplicate_stack
printn
jmp(7)
set_label(3)
push_stack(?B.ord)
printc
push_stack(?u.ord)
printc
push_stack(?z.ord)
printc
push_stack(?z.ord)
printc
jmp(7)
set_label(2)
push_stack(?F.ord)
printc
push_stack(?i.ord)
printc
push_stack(?z.ord)
printc
push_stack(?z.ord)
printc
duplicate_stack
push_stack(5)
mod
jz(4)
jmp(7)
set_label(4)
duplicate_stack
push_stack(?B.ord)
printc
push_stack(?u.ord)
printc
push_stack(?z.ord)
printc
push_stack(?z.ord)
printc
set_label(7)
duplicate_stack
push_stack(100) # end
sub
jl(1)
#over
rtrn
プログラム
便宜上、タブは [T] に置換してあります。
#if false
;
[T];
[T];
[T] ;
[T][T];
[T] [T][T];
[T] [T] ;
;
[T] [T];
[T] [T][T];
[T] [T][T];
;
[T];
[T];
;
[T][T][T];
;
[T][T];
[T] [T] ;
[T];
[T][T][T] [T] [T];
[T];
[T][T][T][T] [T] ;
[T]
[T][T][T][T] [T] ;
[T];
;
;
[T][T][T];
;
[T] ;
[T] [T][T] ;
[T];
[T][T] [T] [T];
[T];
[T][T][T][T] [T] ;
[T];
[T][T][T][T] [T] ;
[T];
;
[T] [T];
[T] [T][T];
[T] [T] ;
;
;
[T][T][T];
;
[T] ;
;
[T] [T] ;
[T];
[T][T][T] [T] [T];
[T];
[T][T][T][T] [T] ;
[T];
[T][T][T][T] [T] ;
[T];
;
[T][T][T];
;
[T][T] [T] ;
[T] [T];
[T][T][T];
;
[T];
eval("(1..100).each{|i|if i%3>0 then print i%5==0?'Buzz':i else print 'Fizz';print 'Buzz' if i%5==0 end};exit") if "0"; #Ruby
eval("for(\$i=1;\$i<=100;\$i++){if(\$i%3){print(\$i%5?\$i:'Buzz')}else{print(\$i%5?'Fizz':'FizzBuzz')}};exit;"); #Perl
=begin DATA
#elif __STDC__
//C
int main(i){for(;i<=100;i++)if(i%3)printf(i%5?"%d":"Buzz",i);else{printf("Fizz");if(i%5==0)printf("Buzz");}return 0;}
#elif __PIKE__
//Pike
int main(){for(int i=1;i<=100;i++)if(i%3)Stdio.stdout.write(i%5?(string)i:"Buzz");else{Stdio.stdout.write("Fizz");if(i%5==0)Stdio.stdout.write("Buzz");};return 0;}
#elif __MonoCS__
//Csharp
using System;
class fizzbuzz{
[T]static void Main(){
[T][T]for(int i=1;i<=100;i++)if(i%3==0){
[T][T][T]Console.Write(i%5==0 ? "FizzBuzz" : "Fizz");
[T][T]}else{
[T][T][T]Console.Write(i%5==0 ? "Buzz" : i.ToString());
[T][T]}
[T]}
}
#else
//Fsharp
open System
for i in 1..100 do
if i%3=0 then
Console.Write(if i%5=0 then "FizzBuzz" else "Fizz")
else
Console.Write(if i%5=0 then "Buzz" else i.ToString())
#endif
#if false
=end DATA
#endif
出題者コメント
polyglot programming!
gmk 様
タイトル:BFで3Dプログラミング
言語:Ruby
説明文
Befunge( http://quadium.net/funge/spec98.html )はソースコードを2次元上に配置する個性的な言語です。
今回は、その3次元拡張(Trefungeと呼ばれるらしい)でFizzBuzzをコーディングしてみました。
プログラム
#Befunge(http://quadium.net/funge/spec98.html)はソースコードを2次元上に配置する個性的な言語です。
#今回は、その3次元拡張(Trefungeと呼ばれるらしい)でFizzBuzzをコーディングしてみました。
#Trefungeの公式仕様が見付からなかったので、三次元拡張に際し以下の記号を導入しました。
# ・'D'/'U':移動方向を"奥"/"手前"向きに変える
#二次元平面(5行5列)が4階層積み重なったソースコード。
#・上端と下端、左端と右端、奥端と手前端は繋がってループしている。
#・”や\が命令に含まれるため、エスケープ回避のため%qを使用。
code =
[[%q(1>v>5D), %q( v% *<), %q("z> ^ ), %q( 2^<v<)],
[%q( +:3>v), %q(:_$vD5), %q(<"|%<^), %q( ^<6*8)],
[%q( 1::,:), %q(zz"<v"), %q(v<$v_v), %q(^<\%+6)],
[%q(>|0\|<), %q("Bu"<v), %q("v<:%$), %q(</+* |)],
[%q(-@>^$:), %q(v"zz"<), %q(u" 23U), %q(:**5 $)],
[%q(^"d"<^), %q(>"iF"U), %q(Bz D:U), %q( 58^>U)]]
.transpose.map{|l|l.map{|s|s.split("")}}
#以下、TrefungeのインタープリタをRubyで実装しました。
#上記で使用していない命令は実装対象外としています。
require 'matrix'
pos = Vector[0,0,0] #現在座標
dir = Vector[1,0,0] #移動方向(初期値は右方向)
stack = []
quote_mode = false
while true
c=code[pos[2]][pos[1]][pos[0]]
if !quote_mode
case c
when /[0-9]/ #数値をスタックにプッシュする
stack.push c.to_i
when "+","-","*","/","%" #スタックの先頭2要素で算術演算を行い結果をプッシュする
stack[-1],stack[-2] = stack[-2],stack[-1]
stack.push eval(stack.pop.to_s + c + stack.pop.to_s)
when "v" #移動方向を"下"に変える
dir = Vector[0,1,0]
when "^" #移動方向を"上"に変える
dir = Vector[0,-1,0]
when ">" #移動方向を"右"に変える
dir = Vector[1,0,0]
when "<" #移動方向を"左"に変える
dir = Vector[-1,0,0]
when "D" #移動方向を"奥"に変える
dir = Vector[0,0,1]
when "U" #移動方向を"手前"に変える
dir = Vector[0,0,-1]
when ":" #スタックの先頭要素を複製する
stack.push(stack[-1])
when "\"" #次に"が出現するまで、文字のASCIIコードをスタックにプッシュする
quote_mode = 1
when "\\" #スタック先頭の二要素を交換する
stack[-1],stack[-2] = stack[-2],stack[-1]
when "_" #スタックをポップして、その値が0ならば実行の向きを右に、そうでなければ左にする
dir = stack.pop==0?Vector[1,0,0]:Vector[-1,0,0]
when "|" #スタックをポップして、その値が0ならば実行の向きを下に、そうでなければ上にする
dir = stack.pop==0?Vector[0,1,0]:Vector[0,-1,0]
when " " #何もしない
#nop
when "," #スタックをポップして、その値をASCIIコードに持つ文字を表示する
print(stack.pop.chr)
when "$" #スタックをポップして捨てる
stack.pop
when "@" #プログラムの実行を停止する
exit
else
p "ERROR!"
end
else
case c
when "\""
quote_mode = false
else
stack.push c.ord
end
end
pos=(pos+dir).map{|i|i%6}
end
出題者コメント
まさかの 三次元 FizzBuzz
hevo2 様
タイトル:AIを実装して推論によってFizzBuzzを解いた(嘘は言ってない)
言語:Lua
説明文
僕の考えた、最も不適切なFizzBuzzプログラムです。
LuaでなんっちゃってRule-based System(RBS)を実装して推論によってFizzBuzzを解きました
え?張り切りすぎ?効率? あーあー、聞こえなーい。
プログラムをそのまま実行すると、FizzBuzz仕様通りの出力を行います。
オプション”step_option=true”に書き換えて実行するとRBSは1ステップずつの推論内容を表示します。
裏でどんな推論やっているのか気になった方には後者でご確認ください。
なお「こんな適当な実装でRBS名乗れるはずないだろ、マッチングの実装と最適化こそがRBSの肝だろうが!!!」とおっしゃる方。
あなたとはおいしいお酒が飲めそうです^^
プログラム
-- ###############################################
-- Rule-based FizzBuzz version 0.1
-- Written by hevohevo, License: MIT
-- Twitter: @hevohevo
-- http://hevohevo.hatena.com/
-- 僕の考えた、最も不適切なFizzBuzzプログラムです。
-- コンセプトは、「LuaでAI実装して推論によってFizzBuzzを解かせた」(嘘は言ってない)
-- つまりは、なんっちゃってRule-based SystemのLua実装です。
-- 効率皆無で自己満足以外の何者でもないけれど、今回のお題的にはこれでよい……はず。
-- プログラムをそのまま実行すると、FizzBuzz仕様通りの出力を行います。
-- オプション"step_option=true"に書き換えて実行するとRBSは推論内容を表示します。
-- 裏でどんな推論やっているのか気になった方には後者をおすすめします。
-- ###############################################
-- Options
-- falseでFizzBuzz仕様どおりの出力
-- trueでステップ実行(Ideoneだとキー入力待たずに一気に出力されます)。
local step_option = false
-- ###############################################
-- Classes and Functions
-- WM Class
WM = {}
function WM.new(init_table)
local obj = {}
-- 命題を蓄えておくテーブル
obj.facts = init_table
-- WMからキーを元に命題を探す
obj.find = function(self, key)
return self.facts[key]
end
-- WMに命題を加える
obj.add = function(self, key, value)
value = value or true
self.facts[key]=value
return true
end
-- WMから命題を消す
obj.delete = function(self, key)
self.facts[key]=nil
return true
end
-- WMに命題"terminated"を加える
obj.terminate = function(self)
return self:add("terminated")
end
-- WMに命題"terminated"があるか調べる(あると推論終了)
obj.isTerminated = function(self)
return self:find("terminated")
end
return obj
end
-- Rule Class
Rule = {}
function Rule.new(opts)
local obj = {}
obj.name = opts.name -- ルールは一意な名前を持つ
obj.priority = opts.priority or 0 -- 値が小さい方が優先度は高い。標準は0
obj.cond = opts.cond -- ルールの条件部はbooleanを返す関数(true=ルール実行可能、false=不可)
obj.run = opts.run -- ルールの実行部はbooleanを返す関数(true=正常実行完了)
obj.fired_log = {0} -- このルールが発火したステップ番号を配列に蓄積
-- 発火履歴を書き込む
obj.addLog = function(self, step)
table.insert(self.fired_log, step)
end
-- 発火履歴の末尾を取り出す(直近の発火したステップ数)
obj.tailLog = function(self)
return self.fired_log[#self.fired_log]
end
return obj
end
-- RuleDB Class
RuleDB = {}
function RuleDB.new(init_table)
local obj = {}
-- init_tableによって与えられたデータを使ってルール作成・蓄積
obj.rules = {}
for i,v in ipairs(init_table) do
obj.rules[i] = Rule.new(v)
end
return obj
end
-- すべてのルールの条件部を調べ、現在、発火可能なルールをすべて集める
function collectTriggeredRules(_rule_db, _wm)
local results = {}
for _, rule in ipairs(_rule_db.rules) do
if rule.cond(_wm) then
table.insert(results, rule)
end
end
return results
end
-- 発火可能なルール群の中で最も優先すべきルールを1つ返す
-- 「競合解消戦略」は以下の通り
-- 1. priority値が小さいほうが優先度高い(デフォルト0、負も可)
-- 2. priority値が同じならば、最近発火したルールは後回し
-- 3. 発火履歴も同じならば、ルール登録順
function resolveConflict(triggered_rules)
local best_rule = triggered_rules[1] -- 先頭のルールを代入
for i, rule in ipairs(triggered_rules) do
if i>1 then -- 2番目以降と比較
if best_rule.priority > rule.priority then
best_rule = rule -- 優先度の高い(値が小さい)方を選択
elseif best_rule.priority == rule.priority then
if best_rule:tailLog() > rule:tailLog() then
best_rule = rule
end
end
end
end
return best_rule
end
-- ジェネリックfor文を使って独自のイテレータを作る
-- 返し値の先頭がnilのときにジェネリックfor文は停止する
-- (参考:http://qiita.com/hevo2/items/604b5405a981fd5fd207)
function RBEngine(_rule_db, _wm, max_step)
local max_step = max_step or 500
local step = 0
return function()
local fired_rule = nil
local triggered_rule = {}
step = step + 1
-- WMに "terminated" があるか、最大ステップ数を超えているので終了
if _wm:isTerminated() or (step > max_step) then
fired_rule = nil
return fired_rule, step, triggered_rule, _wm
end
-- 発火可能なルールをすべて集める
triggered_rules = collectTriggeredRules(_rule_db, _wm)
if type(triggered_rules) == "table" and #triggered_rules > 0 then
-- 発火可能ルール群の中からもっとも優先するルールを取り出す(競合解消)
fired_rule = resolveConflict(triggered_rules)
assert(fired_rule.run(_wm)) -- run部の実行時にtrueが返ってこなかったらエラー
fired_rule:addLog(step) -- ルールに発火履歴を書き込み
else
-- 発火可能なルールがない
fired_rule = nil
end
return fired_rule, step, triggered_rules, _wm
end
end
-- #############################################
-- Rule-base System のデータ部分
-- Working Memory
-- key=value
data_wm = {
num=1
}
-- Rule DataBase
-- rule = {
-- name, ルールは一意な名前を持つ
-- priority, 値が小さい方が優先度は高い。標準は0
-- cond, ルールの条件部はbooleanを返す関数(true=ルール実行可能、false=不可)
-- run, ルールの実行部はbooleanを返す関数(true=正常実行完了, その他異常終了)
-- fired_log このルールが発火したステップ番号を配列に蓄積
-- }
data_rules = {
{ name = "terminated",
cond = function(wm) return wm:find("num") > 100 end,
run = function(wm) return wm:terminate() end,
priority = -1 },
{ name = "fizz",
cond = function(wm) return (wm:find("num") % 3) == 0 end,
run = function(wm) return wm:add("say", "Fizz") end,
priority = 1 },
{ name = "buzz",
cond = function(wm) return (wm:find("num") % 5) == 0 end,
run = function(wm) return wm:add("say", "Buzz") end,
priority = 1 },
{ name = "fizzbuzz",
cond = function(wm) return (wm:find("num") % 15) == 0 end,
run = function(wm) return wm:add("say", "FizzBuzz") end,
priority = 0 },
{ name = "others",
cond = function(wm) return true end,
run = function(wm) return wm:add("say", wm:find("num")) end,
priority = 2 },
{ name = "say",
cond = function(wm) return wm:find("say") end,
run = function(wm)
io.write(wm:find("say"))
wm:delete("say")
wm:add("said")
return true
end,
priority = 0 },
{ name = "increase",
cond = function(wm) return wm:find("said") end,
run = function(wm)
wm:add("num", wm:find("num") + 1)
wm:delete("said")
return true
end,
priority = 0 }
}
-- ###########################################
-- Main
-- 標準入力から実行オプションを入手(Ideoneだとうまくいかない?)
local args = {...}
if args[1]=="step" then
step_option = true
end
-- WorkingMemory と Rule DBを作成
local wm = WM.new(data_wm)
local rule_db = RuleDB.new(data_rules)
-- ジェネリックFor文で1ステップずつ推論を進めていく。
for fired_rule, step, triggered_rules, current_wm in RBEngine(rule_db, wm) do
if step_option then
-- 1ステップずつ推論
print()
io.read()
print("step: "..step)
print(" number:"..current_wm:find("num"))
print(" fired_rule: "..fired_rule.name)
print()
else
-- FizzBuzz仕様通りの出力
end
end
--print()
出題者コメント
おいしいお酒が飲めそうな方は、ツイートすべし。
shinh 様
タイトル:なんちゃって x86 インタプリタ
言語:nasm / ruby の polyglot
説明文
ごく普通のアセンブリで書かれた FizzBuzz だなぁと思うかと思います。
事実だいたいそうなのですが、末尾に Ruby コードがくっついていて、
Ruby でも実行できるようになっています。この Ruby のコードは
x86 のアセンブリをなんとなく Ruby に翻訳して実行するプログラムで、
上の方のアセンブリを Ruby として実行して FizzBuzz を出力します。
- nasm のコードってだいたい Ruby のパース通りそうだよね、
- ていうのが着想です。実際にはラベルが通りませんでした。
- しょうがないのでラベルの直後に nop をくっつけて、
- にはシンボルの一部になっていただいています。
全ての行の先頭に ; がついている、 Ruby 部分のコードは不思議な
感じがするかもしれませんが、 Chromium の開発メーリングリストでも
提案されたことのある、由緒正しいコーディングスタイルであります。
プログラム
_start:nop
mov ecx, esp
sub esp, 80
mov byte [esp], 48
mov byte [esp+1], 48
mov byte [esp+2], 0
mov byte [esp+3], 0
fb_loop:nop
add byte [esp], 1
add byte [esp+2], 1
add byte [esp+3], 1
cmp byte [esp], 58
jne output
mov byte [esp], 48
add byte [esp+1], 1
output:nop
cmp byte [esp+2], 3
je fizz
cmp byte [esp+3], 5
je buzz
cmp byte [esp+1], 48
je output2
mov edi, [esp+1]
call putchar
output2:nop
mov edi, [esp]
call putchar
jmp fb_loop
fizz:nop
mov byte [esp+2], 0
mov edi, 70
call putchar
mov edi, 105
call putchar
mov edi, 122
call putchar
call putchar
cmp byte [esp+3], 5
je buzz
jmp fb_loop
buzz:nop
mov byte [esp+3], 0
mov edi, 66
call putchar
mov edi, 117
call putchar
mov edi, 122
call putchar
call putchar
cmp byte [esp+1], 58
jne fb_loop
mov edi, 10
call putchar
mov eax, 1
mov ebx, 0
int 128
putchar:nop
mov [ecx], edi
mov eax, 4
mov ebx, 1
mov edx, 1
int 128
ret
; BEGIN{
; def byte(*x) x end
; def method_missing(*s)
; v = $regs.index(s[0].to_s)
; return 2 ** 32 + v * 256 if v
; if $ops.include?(s[0])
; args = !s[2] && s[1].is_a?(Array) ? s[1] : s[1..-1]
; case op = s[0]
; when :mov, :add, :sub, :cmp
; lr = args.map do |a|
; if a.is_a?(Array)
; "mem[#{$regs[a[0] / 256 % 8]}+#{a[0] % 256}]"
; elsif a >= 2 ** 32
; "#{$regs[a / 256 % 8]}"
; else
; a.to_s
; end
; end
; $code << lr * '=' if op == :mov
; $code << lr * '+=' if op == :add
; $code << lr * '-=' if op == :sub
; $code << "cmp = #{lr * '=='}" if op == :cmp
; when :je, :jne, :jmp, :call
; $code << "stk << pc" if op == :call
; c = 1
; c = "cmp" if op == :je
; c = "!cmp" if op == :jne
; $code << "pc = $labels[:#{args[0]}] - 1 if #{c}"
; when :int
; $code << "syscall eax, ebx, ecx, edx, mem"
; when :ret
; $code << "pc = stk.pop + 1"
; else
; p $code
; raise
; end
; $asms << args
; $code[-1] += " # #{s}"
; return nil
; end
; $labels[s[0]] = $code.size if s[1].is_a?(Symbol)
; return s
; end
; def syscall(eax, ebx, ecx, edx, mem)
; case eax
; when 1
; exit ebx
; when 4
; putc mem[ecx]
; else
; raise 'Unknown syscall'
; end
; end
; $regs = %w(eax ebx ecx edx esi edi ebp esp)
; $ops = %w(mov add sub cmp int jmp je jne call ret).map(&:to_sym)
; $labels = {}
; $asms = []
; $code = []
; }
; pc = $labels[:_start]
; mem = {}
; eax = ebx = ecx = edx = esi = edi = ebp = 0
; esp = 100
; cmp = false
; stk = []
; while true
; c = $code[pc]
; #p "eax=#{eax} ebx=#{ebx} ecx=#{ecx} edx=#{edx} esp=#{esp} mem=#{mem}"
; #p c
; eval(c)
; pc += 1
; end
; exit
; while true
; op, *args = $asms[pc]
; puts '==='; p [op, args]; p reg; p mem
; case op
; when :mov, :add, :sub, :cmp
; b = args[1]
; b = reg[b / 256 % 8] if b > 2 ** 32
; if args[0].is_a?(Array)
; da = mem; di = reg[args[0][0] / 256 % 8] + args[0][0] % 256
; else
; da = reg; di = args[0][0] / 256 % 8
; end
; da[di] = b if op == :mov
; da[di] += b if op == :add
; da[di] -= b if op == :sub
; cmp = da[di] == b if op == :cmp
; when :je, :jne, :jmp, :call
; stk << pc if op == :call
; pc = $labels[args[1]] - 1 if op == :je && cmp || op == :jne && cmp
; when :int
; p reg
; case reg[0]
; when 1
; exit reg[1]
; when 4
; putc mem[reg[2]]
; else
; raise 'Unknown syscall'
; end
; else
; raise 'Unknown op'
; end
; pc += 1
; end
出題者コメント
コードゴルフ界の神様の絶技をご覧あれ。
みけCAT 様
タイトル:鍵が鍵
言語:Perl
説明文
まずこのコードのために生成したRSA鍵を貼り、
「FizzBuzzの計算に用いる数値は貼った鍵から取る」という縛りで実装しました。
さらに、コードを鍵の本体と同じ1行64文字に整形しました。
処理自体は普通のFizzBuzzです。
- $hoge++;や$hoge += 1;ではなく$hoge = $hoge + 1;を使っているところが不適切
- 最適化を狙わず、足し算とか掛け算とかシフト演算とか累乗とかを適当に混ぜているところが不適切
- 1を得るために($kagi>=$kagi)、($kagi==$kagi)、($kagi<=$kagi)を適当に混ぜているところが不適切
- 行の文字数をコードで調整せずに、適当に空白をまぜてごまかしているところが不適切
プログラム
#!/usr/bin/perl
use strict;
my $kagi=<<KAGI;
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1CCScF4JnMOUGeZZDE46qMLXbZzAznuuEJhpQBPxXp5IM0ql
Y9luYGrAlFuJLxVh3h0m9PpQslrPNV6r2860oAOEKcaL21TODRRFfr6vL2oKQ9zI
FNcOwpbZfAD3oG1sMdcokCG+KAzrkRCeBTemCgILW02khYviDqed7jEA/ThjqsWI
Qt+VfIQNcl3Gw+10aRzPiPkJVKBqpruXgoDBOJ3vC3CSaBPIuVQpHeu4OEbsu5fg
1FEG00WvsRIfniOpGNTgiw6jz7LOffgHuueGnyjt+PH8pHHik6H/gLXbwI+sssQE
JcEo/TGoT/ktzp+lXmGvE25BbQSqJI2/bAmoLQIBIwKCAQBIurXdYhHsmtOxG8bC
Y/baxnW/Lm39pr9WJaBtvbHXTDYC9QWBUdyzV8z/qlrrkk1wuYmzE/5pCTEZnM01
a3Eg60NBhebO2z9U8QHiUAGMmWKa7Jxe6qX5ks45JOcvsHzd415dTWXElrcqbBjr
2JCy+WL6u4jdVIgFBkTGsbcyPpfrPgKV73F4mDfX0MvqgnNzh1JjfthOuos2NQAS
YkYYc7H/JZLPspW0R2Uz4e0wEWgl7BF/jZ1IrfOSrBXS0c+3skTR771ATCAaSmBv
ZoBKiKVzBL2NbVZaAJGtYbcWUt+iZgQ6wKpVlYaDDTP0O4/7pUKnx0klWR5/Gkqo
IxmLAoGBAPokN075syn9qZlEv4OLTGbPVlccfTOg1qLHc0Hg1yPWy+clR59av0Iy
UP1VUWlAe++ysa6JR2AlvvGY0TNVawspecZZMqhQzUKUPKvQ5c1wq5jqxqyaL31k
KqET1y5HWJ4IUFTHLCEbopEiC09O4nv6LGc7G/aUbdLRPF1ySZrNAoGBANkYbrG+
h2CJySai0psh+eeI0R109Il41FyBLcAWtaZFK0C9+1wvi6c5Mu9GnLCA7Y1E9ans
V0aZi2JXIFdMf1Vs6Hwi4L4uB4OdDRf6bBhVGXJ+stHYbilToGAzLFd4Gq0QyiMI
jcG9RaQvsgb3ZMVw6JrETQrWUukLRLLkrwLhAoGBAIfKhGyzb+OYVMDqzl1aP2sC
1xlYm7zw6YuQ2CsTp/2DO316ozk/5Cs/4tKqqImYCMPzSoNR1kojHoMnEnrz2wYP
M3pNrckV68UOpJfJLEr0BWGkBXOkKGikFyQ9+Hg1W/4Eg2E47BH5DxuWI2WROR67
AilpOxDUO55UU/g2uj4XAoGBAKd5P3MslFHJYKjGv7mAnDZE+Ra5Tu20+5fRXc6y
bt9Z7iqhL57i2XJfUy2c30ZU1ILsDfgcuFsIu/tnyH3b7TNFYuNrXOp7R6ALcIA2
NiFmODPA0xboygKfmPnBE5Pu8AHZwIFs/6QVqsB8kKZJ0WUcli4/qSWeBXHyv/e3
ujVrAoGBAIZ2FjPzKII9oyjYIAIANlRQZJ/jerBEiu6d9NvtV3jOq9vhMyX2XkO0
W6yzXoPiFlk+yNC3ZwvSS8nYTRxQqu+2DRuTiDAUaPB74GjiAVswNSK8MKonP/zB
mhiq7qUpkZn1xFpiGoLZ8x9XTd51yPXFJH4jb0/Q2SAUDaYPwlGk
-----END RSA PRIVATE KEY-----
KAGI
for(my $Kagi=substr($kagi,(((((($kagi>=$kagi)<<(($kagi==$kagi)+(
$kagi>=$kagi)+($kagi==$kagi)))+($kagi>=$kagi))<<(($kagi==$kagi)+
($kagi<=$kagi)+($kagi>=$kagi)))-($kagi<=$kagi))<<(($kagi==$kagi)
<<(($kagi>=$kagi)+($kagi>=$kagi))))+($kagi==$kagi),$kagi>=$kagi)
;substr($kagi,$Kagi-($kagi<=$kagi)-($kagi==$kagi)-($kagi>=$kagi)
,$kagi==$kagi)!=substr($kagi,((($kagi>=$kagi)<<(($kagi==$kagi)+(
$kagi<=$kagi)+($kagi==$kagi)+ ($kagi>=$kagi)+($kagi<=$kagi)))-($
kagi<=$kagi ))<<(($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi)+($
kagi==$kagi)+($kagi>=$kagi)),$kagi==$kagi );$Kagi=$Kagi+substr($
kagi, ((($kagi<=$kagi )+($kagi==$kagi )+($kagi>=$kagi)+($kagi==$
kagi)+($kagi<= $kagi))*(($kagi<=$kagi)+($kagi>=$kagi)))**(($kagi
==$kagi)+($kagi<=$kagi)+($kagi>=$kagi)),$kagi==$kagi)){my $kagI=
hex(substr($kagi,(($kagi<=$kagi)+($kagi==$kagi)+($kagi>=$kagi))*
((($kagi==$kagi)+($kagi<=$kagi))**(($kagi<=$kagi)+($kagi==$kagi)
+($kagi>=$kagi)+($kagi==$kagi))),($kagi>=$kagi)+($kagi==$kagi)+(
$kagi<=$kagi)));if($Kagi%substr($kagi,(((($kagi==$kagi)+($kagi>=
$kagi)+($kagi<=$kagi)+($kagi>=$kagi)+($kagi==$kagi))<<(($kagi==$
kagi)<<(($kagi<= $kagi)+( $kagi>=$kagi)))) +($kagi==$kagi))*((($
kagi==$kagi)+($kagi>=$kagi))**(( $kagi==$kagi)+($kagi>=$kagi)+($
kagi <=$kagi)+($kagi==$kagi))),$kagi<=$kagi)== substr($kagi,((($
kagi==$kagi)<<(($kagi<=$kagi )+($kagi>= $kagi)+($kagi==$kagi)+($
kagi>=$kagi)+($kagi==$kagi)))+(($kagi>=$kagi)<<(($kagi<=$kagi)+$
kagi==$kagi))+($kagi<=$kagi))<<(($kagi==$kagi)+($kagi<=$kagi)+($
kagi>=$kagi)+($kagi==$kagi)),$kagi>=$kagi)){$kagI=$kagI+substr($
kagi,((($kagi==$kagi)<<(($kagi >=$kagi)+($kagi==$kagi)+($kagi<=$
kagi)+($kagi>=$kagi )+($kagi==$kagi)+($kagi<=$kagi)))+ ($kagi==$
kagi)+($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi)+($kagi>=$kagi
))*(($kagi==$kagi)<<(($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi
))),$kagi==$kagi);}if($Kagi%substr($kagi,((($kagi==$kagi)+($kagi
>=$kagi)+($kagi<=$kagi ))<<((($kagi<=$kagi)<< (($kagi>=$kagi)+($
kagi==$kagi)+($kagi<=$kagi)))-($kagi>=$kagi)))-($kagi>=$kagi)-($
kagi==$kagi)-($kagi<=$kagi)-($kagi== $kagi)-($kagi<=$kagi),$kagi
==$kagi)==substr($kagi,((($kagi==$kagi)+($kagi<=$kagi)+($kagi>=$
kagi)) <<((($kagi==$kagi )<<(($kagi>=$kagi)+ ($kagi<=$kagi)))+($
kagi>=$kagi))) -($kagi==$kagi )-($kagi>= $kagi)-($kagi<=$kagi),$
kagi==$kagi)) {$kagI=$kagI+substr($kagi,((((($kagi ==$kagi)<<(($
kagi<=$kagi)+($kagi>=$kagi)+($kagi<=$kagi)))+($kagi==$kagi))<<((
($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi))<<($kagi==$kagi)))+
($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi))*(($kagi>=$kagi)+($
kagi<=$kagi)),$kagi==$kagi);}my $KagI=substr($kagi,$kagI,$kagi==
$kagi);if($KagI eq substr($kagi,(($kagi<=$kagi)<<((($kagi>=$kagi
)<<(($kagi==$kagi)+($kagi>=$kagi)+($kagi<=$kagi)))-($kagi==$kagi
)))-($kagi>=$kagi)-($kagi==$kagi)-($kagi>=$kagi)-($kagi<=$kagi)-
($kagi== $kagi), $kagi>=$kagi)) {print substr($kagi,(((($kagi==$
kagi)<<(($kagi<=$kagi)+($kagi>=$kagi)+($kagi<=$kagi)))+($kagi==$
kagi))*((($kagi>=$kagi)+($kagi==$kagi)+ ($kagi<=$kagi)+($kagi==$
kagi)))+($kagi<=$kagi))<<(($kagi>=$kagi)+($kagi<=$kagi)),$kagi>=
$kagi).substr($kagi,((((($kagi>=$kagi )+($kagi<=$kagi)+($kagi==$
kagi)+($kagi<=$kagi) +($kagi>=$kagi))<<(($kagi<=$kagi)+($kagi==$
kagi)))+($kagi>=$kagi))<<(($kagi==$kagi)<<(($kagi>=$kagi)+($kagi
<=$kagi))))+($kagi>=$kagi)+($kagi<=$kagi)+($kagi>=$kagi),$kagi<=
$kagi).substr($kagi ,((((($kagi>=$kagi)+($kagi<=$kagi)+($kagi==$
kagi))<<(($kagi<=$kagi)+($kagi>=$kagi)+($kagi<=$kagi)))-($kagi==
$kagi))<<(($kagi>=$kagi)+($kagi<=$kagi)+($kagi==$kagi)+($kagi<=$
kagi)))+($kagi==$kagi),$kagi <=$kagi).substr($kagi,((((($kagi==$
kagi)+( $kagi>=$kagi)+($kagi<=$kagi))<<((($kagi==$kagi)<<(($kagi
>=$kagi)+($kagi<=$kagi)))+($kagi==$kagi)))+($kagi<=$kagi)+($kagi
==$kagi)+($kagi>=$kagi))<<(($kagi<=$kagi )+($kagi==$kagi)+($kagi
>=$kagi)+($kagi==$kagi)))+($kagi>=$kagi)+($kagi==$kagi)+($kagi>=
$kagi)+($kagi <=$kagi)+( $kagi==$kagi) ,($kagi<=$kagi)+($kagi==$
kagi)).substr($kagi,((($kagi==$kagi)<<(($kagi>=$kagi)<<(($kagi==
$kagi)+($kagi<=$kagi))))+($kagi>=$kagi)+($kagi<=$kagi)+($kagi>=$
kagi))<< ((($kagi>= $kagi)<<(($kagi==$kagi) +($kagi<=$kagi)))+($
kagi==$kagi)),$kagi>=$kagi). substr($kagi,((($kagi<=$kagi)<<((($
kagi==$kagi)<<(($kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi)))-($
kagi>=$kagi)))-($kagi<=$kagi)-($kagi>=$kagi)-($kagi==$kagi))*(($
kagi<=$kagi)+($kagi==$kagi)+($kagi<=$kagi)+($kagi>=$kagi)),$kagi
<=$kagi).substr($kagi,((($kagi>=$kagi)+($kagi ==$kagi)+($kagi<=$
kagi))<<((($kagi== $kagi)<<(($kagi<=$kagi)+($kagi==$kagi)+($kagi
>=$kagi)))-($kagi==$kagi)-($kagi<= $kagi)))-(($kagi==$kagi)<<(($
kagi >=$kagi) +($kagi<=$kagi ))),$kagi>= $kagi );}elsif($KagI eq
substr($kagi,(((($kagi==$kagi)<<((($kagi>=$kagi)<<(($kagi>=$kagi
)+($kagi==$kagi)))+($kagi<=$kagi )))-(($kagi>=$kagi)<<(($kagi==$
kagi)+($kagi<=$kagi)+($kagi==$kagi)))-($kagi>=$kagi))<<(($kagi==
$kagi)+ ($kagi>=$kagi )+($kagi<=$kagi)+( $kagi==$kagi)+($kagi>=$
kagi)))+($kagi==$kagi),$kagi<=$kagi)){print substr($kagi,(((((($
kagi==$kagi)+($kagi<=$kagi)+($kagi>=$kagi))*((($kagi==$kagi)<<((
$kagi>=$kagi)+($kagi<=$kagi)+($kagi==$kagi)))-($kagi<=$kagi)))<<
(($kagi>=$kagi)+($kagi<=$kagi)))+($kagi==$kagi))<<(($kagi>=$kagi
)+($kagi<=$kagi)+($kagi==$kagi)))-( $kagi>=$kagi),$kagi==$kagi).
substr($kagi, ((($kagi<=$kagi)+($kagi==$kagi) +($kagi>=$kagi)+($
kagi<=$kagi)+($kagi>=$kagi))<<(($kagi==$kagi)<<(($kagi>=$kagi)+(
$kagi<=$kagi)+($kagi>=$kagi))))-((($kagi==$kagi)+($kagi<=$kagi)+
($kagi==$kagi))<<(($kagi>=$kagi)+($kagi==$kagi)+($kagi>=$kagi)))
,$kagi<=$kagi).substr($kagi, (((($kagi>=$kagi)<<((($kagi==$kagi)
<<(($kagi>= $kagi)+($kagi<=$kagi))) +($kagi==$kagi )))+($kagi<=$
kagi)+($kagi==$kagi)+($kagi>=$kagi)+($kagi==$kagi)+($kagi>=$kagi
))<<(($kagi>=$kagi)<<(($kagi==$kagi)+($kagi<=$kagi))))+(($kagi==
$kagi)<<(($kagi<=$kagi)+($kagi>=$kagi)+($kagi==$kagi)))-($kagi<=
$kagi),$kagi >=$kagi).substr ($kagi,((($kagi<=$kagi)<<(($kagi==$
kagi)<<(($kagi<=$kagi)+($kagi>=$kagi))))+($kagi>=$kagi)+($kagi==
$kagi)+($kagi<=$kagi))<<(($kagi==$kagi)+($kagi<=$kagi)),$kagi>=$
kagi);}elsif($KagI eq substr($kagi,(($kagi>=$kagi)+($kagi==$kagi
)+($kagi<=$kagi))<< ((($kagi==$kagi)<<(($kagi >=$kagi)+($kagi==$
kagi)+ ($kagi<= $kagi)))- ($kagi>=$kagi )),$kagi ==$kagi)){print
substr($kagi,((((((($kagi==$kagi)<<(($kagi>=$kagi)+($kagi==$kagi
)+($kagi <=$kagi)))-($kagi==$kagi ))<<(($kagi>= $kagi)+($kagi==$
kagi)+($kagi<=$kagi) +($kagi==$kagi)))+ ($kagi<=$kagi)+($kagi==$
kagi)+($kagi>=$kagi))<<(($kagi==$kagi)+($kagi>=$kagi)))+($kagi==
$kagi))*(($kagi>=$kagi )+($kagi<=$kagi)), $kagi>=$kagi).substr($
kagi,(((($kagi==$kagi)<<(($kagi >=$kagi)<<(($kagi==$kagi)+($kagi
<=$kagi ))))-($kagi>=$kagi)-($kagi<=$kagi)-($kagi ==$kagi))<<(($
kagi<=$kagi)+($kagi>=$kagi) +($kagi==$kagi) +($kagi>=$kagi)))+($
kagi<=$kagi),$kagi>=$kagi).substr($kagi,((((((($kagi==$kagi)<<((
$kagi>=$kagi)+($kagi==$kagi)+($kagi<=$kagi)))+($kagi>=$kagi))<<(
($kagi==$kagi)+($kagi<=$kagi)))+($kagi>=$kagi))<<(($kagi<=$kagi)
+($kagi>=$kagi)+($kagi==$kagi)))-($kagi<=$kagi))<<(($kagi>=$kagi
)+($kagi<=$kagi)),$kagi>=$kagi).substr($kagi,(($kagi==$kagi)<<((
$kagi<=$kagi)<<(($kagi==$kagi)+($kagi>=$kagi)+($kagi<=$kagi))))-
(($kagi>=$kagi)<<(($kagi<=$kagi)+($kagi==$kagi)+($kagi>=$kagi)))
-($kagi <=$kagi) -($kagi==$kagi )-($kagi>=$kagi),$kagi<=$kagi);}
else{print $Kagi;}}
出題者コメント
( ゚д゚)ポカーン
( Д ) ゚ ゚ スポーン
カニ戯(ry 様
タイトル:プログラミング言語 “FizzBuzz” とJavaによる処理系の実装
言語:Java
説明文
【 プログラミング言語 “FizzBuzz” 仕様】
○ はじめに
プログラミング言語”FizzBuzz”(以下、FizzBuzz言語)は、
命令数16個の小さな命令セットからなるスタック指向の手続き
型言語である。
FizzBuzz言語は、その命令セットを小さく保つため、「標準
入力を取り扱えない」「整数演算しかおこなえない」という制
限があるが、スタックを用いた整数の四則および剰余演算、条
件分岐とジャンプ、数値およびキャラクタの標準出力が可能と
なっている。
○ ソースコードの構造
FizzBuzz言語が解釈するソースコードは、いくつかの文字列
が区切り文字で連結された1つの文字列である(以下、FizzBu
zz列)。
区切り文字は、「コンマ・半角空白・水平タブ・復帰・改行」
文字である。
区切り文字で連結された各文字列を「項」といい、(大文字・
小文字を無視して)”fizz”・”buzz”・”fizzbuzz”のいずれかで
ある項を「FizzBuzz項」、それ以外の項を「非FizzBuzz項」と
いう。
FizzBuzz項は、処理系への命令を示す「命令項」と、一部の
命令項の動作パラメータとなる「オペランド項」に分類される。
各項は、FizzBuzz列先頭の項を1番目として、それが何番目
の項かを示す「項番号」という属性値を持つ。
FizzBuzz言語の処理系は、
(1) FizzBuzz列の第1項から評価を開始し、
(2) ある項が非FizzBuzz項であれば、
何もせずに次の項の評価に移る
(3) ある項がFizzBuzz項であれば、
その文字列と項番号の偶奇によって命令を決定し、
その処理をおこない、次の項の評価に移る
(4) 次の項とは、
オペランドを持たない命令であれば次のFizzBuzz項、
オペランドを持つ命令であればオペランド項の次の
FizzBuzz項である
ただし、命令によっては次の項となるFizzBuzz項を
指定するものがある
という手順で実行処理をおこなう。
○ 命令とオペランド
FizzBuzz項は、その文字列(大文字・小文字を区別する)と
項番号の偶奇によって対応する命令が以下のように決定される。
・項番号が偶数の場合、文字列が
”fizz” => MOD
”Fizz” => LABEL*
”buzz” => ROLL
”Buzz” => DUP
”fizzbuzz” => JZ*
”Fizzbuzz” => DROP
”fizzBuzz” => MUL
”FizzBuzz” => JNZ*
・項番号が奇数の場合、文字列が
”fizz” => ADD
”Fizz” => PUSH*
”buzz” => PUTN
”Buzz” => PUTC
”fizzbuzz” => EXIT
”Fizzbuzz” => SUB
”fizzBuzz” => DIV
”FizzBuzz” => JMP*
対応する命令のニモニックを記し、*のついた命令はオペラ
ンドを持つ。
ある項がオペランドを持つ命令だった場合、その項より大き
な項番号のFizzBuzz項のうち、最小の項番号のものがオペラン
ドとして解釈される。例えば、以下の全ての例において、3番
目の”Fizz”のオペランドは”Buzz”となる。
・1 2 Fizz Buzz 5 6 FizzBuzz
・1 2 Fizz 4 Buzz 6 FizzBuzz
・1 2 Fizz 4 5 Buzz FizzBuzz
FizzBuzz言語において、オペランドは -128 から +127 まで
の整数であり、2の補数で表現された8ビット2進数の各ビット
を、ビットが”1″なら大文字、”0″なら小文字が、”FIZZBUZZ”の
8文字に以下のように割り当てられる。
F I Z Z B U Z Z
4 5 6 │ │ 1 2 3
MSB ┘ └ LSB
例えば、
・”fizZbuzz” => -128
・”fizZBuzz” => -127
・”FIZZbUZZ” => -2
・”FIZZBUZZ” => -1
・”fizzbuzz” => 0
・”fizzBuzz” => 1
・”fizzbUzz” => 2
・”FIZzBUZZ” => 127
となる。
オペランドが(大文字・小文字を無視して)”fizz”のみだった
場合は、その後ろに全て小文字で”buzz”が追加された文字列と
して、また”buzz”のみだった場合には、同様に全て小文字で前
に”fizz”が追加された文字列として数値に解釈される。
つまり、
・”Buzz” === “fizzBuzz” => 1
・”Fizz” === “Fizzbuzz” => 16
となる。
○ スタック
FizzBuzz言語の持ついくつかの命令は、その処理にスタック
を用いる。スタックには整数を積むことができ、その整数の範
囲や積める最大段数は処理系依存である。
以下では、スタックの状態を以下の様に図示する。
「| 1 2 3 」
・左端の”|”がスタックの底を表す
・スタックの各段は空白で区切られることで表す
・スタックが積まれていく様子を右へ伸びることで表す
・スタック最上段は一番右の数値で表される
○ 命令セットとその処理
FizzBuzz言語は16個の命令を持ち、それらは数値演算・
スタック操作・分岐の3種類に分類される。以下に、それらの
ニモニックと実行する処理を記す。
・数値演算命令
・ADD:スタック上位の2数を破棄し、
代わりにそれらの和を積む。
| 1 2 3 = (ADD) => | 1 5
・SUB:スタック上位の2数を破棄し、
代わりにそれらの減算結果を積む。
スタック最上段が減数(引く方)である。
| 1 2 3 = (SUB) => | 1 -1
・MUL:スタック上位の2数を破棄し、
代わりにそれらの乗算結果を積む。
スタック最上段が乗数(掛ける方)である。
| 1 2 3 = (MUL) => | 1 6
・DIV:スタック上位の2数を破棄し、
代わりにそれらを除算した商を積む。
スタック最上段が除数(割る方)である。
| 1 7 2 = (DIV) => | 1 3
・MOD:スタック上位の2数を破棄し、
代わりにそれらを除算したときの剰余を積む。
スタック最上段が除数(割る方)である。
| 1 7 2 = (MOD) => | 1 1
・スタック操作命令
・DROP:スタック最上段を破棄する。
| 1 2 3 = (DROP) => | 1 2
・DUP:スタック最上段を複製し、それを積む。
| 1 2 3 = (DUP) => | 1 2 3 3
・ROLL:スタック最上段を破棄し、
その値に応じた段をスタック最上位に移動する。
値がゼロならスタック最上段を破棄するのみである。
値が正なら、スタック最上段から底に向かって数え、
値が負なら、スタックの底から最上段に向かって
数える(以下の図を参照)。
6 5 4 3 2 1 0
| a b c d e f g
-1 -2 -3 -4 -5 -6 -7
| 1 2 3 4 5 0 = (ROLL) => | 1 2 3 4 5
| 1 2 3 4 5 1 = (ROLL) => | 1 2 3 5 4
| 1 2 3 4 5 2 = (ROLL) => | 1 2 4 5 3
| 1 2 3 4 5 -1 = (ROLL) => | 2 3 4 5 1
| 1 2 3 4 5 -2 = (ROLL) => | 1 3 4 5 2
・PUTN:スタック最上段を破棄し、
その数値を標準出力に出力する。
| 1 2 3 = (PUTN) => | 1 2 そして “3″
・PUTC:スタック最上段を破棄し、
その数値に相当する文字コードを持つキャラクタ
を標準出力に出力する。
| 67 66 65 = (DROP) => | 67 66 そして “A”
・PUSH:オペランドの数値をスタック最上段に積む。
| 1 2 3 = (PUSH 4) => | 1 2 3 4
・分岐命令
・LABEL:オペランドを目印とする、他の分岐命令の評価
後の移動先となるラベル。
・JMP:オペランドと同じ目印を持つLABEL命令に無条件に
ジャンプする。
・JZ:スタック最上段を破棄し、
その値がゼロならオペランドと同じ目印を持つ
LABEL命令にジャンプする。
・JNZ:スタック最上段を破棄し、
その値が非ゼロならオペランドと同じ目印を持つ
LABEL命令にジャンプする。
・EXIT:FizzBuzz列の項の評価を停止する。
○ 付録 - FizzBuzz言語によるプログラミング例 -
・1から100までの「FizzBuzz」の出力
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14
FizzBuzz 16 Fizz 18 BUZZ fizz 21 FizzBuzz buzz 24
Fizz FIZzbUzZ 27 Buzz Fizz FIZzBuZz Fizz fiZzbUzz
Fizz FIZzbUzZ 35 Buzz Fizz fIZzBuzZ Fizz fiZzbUZz
Buzz 42 Buzz 44 Buzz 46 Buzz 48 Buzz 50 Buzz 52
Buzz 54 Buzz 56 FizzBuzz 58 Buzz Fizz buzz 62 63
Buzz Fizz 66 BuZz fizz 69 FizzBuzz bUzz 72 Fizz
FIZzbUzZ 75 Buzz Fizz FIZzBuZz Fizz fiZzbUzz Buzz
82 Buzz 84 Buzz 86 Buzz 88 FizzBuzz 90 Buzz Fizz
bUzz 94 95 Buzz Fizz 98 BUzz fizz 101 FizzBuzz
BUzz 104 Fizz FIZzbUzZ 107 Buzz Fizz fIZzBuzZ
Fizz fiZzbUZz Buzz 114 Buzz 116 Buzz 118 Buzz 120
FizzBuzz 122 Buzz Fizz BUzz Buzz buzz 128 129 Fizz
Buzz 132 Fizz Buzz fizz Buzz 137 138 Fizz fIZzBuZz
Fizz Buzz 143 buzz Fizzbuzz FizzBuzz Fizz 148 fizzbuzz
・第20項までのフィボナッチ数列の出力
1 2 Fizz Buzz buzz 6 Fizz buzz 9 Buzz Fizz Buzz 13
Fizz Buzz 16 Fizz fIzzbuZZ Buzz 20 21 Buzz Fizz
FIZZBUZZ 25 buzz Fizz Buzz 29 buzz Fizz FIZZBUZZ 33
buzz Fizz FIZZBUZZ 33 buzz fizz Buzz buzz 42 Fizz
FIZZBUZZ 45 buzz Fizz Buzz fizz Buzz Fizz FizzBUzz
Fizzbuzz 54 Fizz FIZZBUZZ 57 buzz Fizz Buzz 61 buzz
Fizz FIZZBUZZ 65 buzz Fizz Buzz 69 buzz 71 FizzBuzz
Buzz 74 fizzbuzz
・100までの素数列の出力
1 2 Fizz bUzz buzz 6 Fizz BUzz Fizz Buzz 11 Fizz
Buzz 14 Fizz Buzz fizz Buzz Fizz FIZZBUZZ 21 buzz
23 Buzz Fizz FIZZBUZZ 27 buzz Fizzbuzz FizzBuzz
bUzz 32 Fizz Buzz 35 buzz 37 Fizzbuzz Fizz fIzzbuZZ
Buzz Buzz buzz 44 FizzBuzz BUzz 47 Fizz bUzz Buzz
Fizz FIZZBUZZ 53 buzz 55 Buzz Fizz FIZZBUZZ 59 buzz
Fizz Buzz 63 buzz 65 fizz 67 FizzBuzz Buzz Fizzbuzz
71 Fizz BUzz 74 Fizz Buzz fizz Buzz Fizz fIZzBuZz
Fizzbuzz fizzbuzz buZz 84 Fizz Buzz FizzBuzz Buzz
89 Fizz buZz 92 fizzbuzz
以上
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
new Main().new FizzBuzzInterpreter(
"1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " +
"16 Fizz 18 BUZZ fizz 21 FizzBuzz buzz 24 Fizz FIZzbUzZ 27 " +
"Buzz Fizz FIZzBuZz Fizz fiZzbUzz Fizz FIZzbUzZ 35 Buzz Fizz " +
"fIZzBuzZ Fizz fiZzbUZz Buzz 42 Buzz 44 Buzz 46 Buzz 48 Buzz " +
"50 Buzz 52 Buzz 54 Buzz 56 FizzBuzz 58 Buzz Fizz buzz 62 63 " +
"Buzz Fizz 66 BuZz fizz 69 FizzBuzz bUzz 72 Fizz FIZzbUzZ 75 " +
"Buzz Fizz FIZzBuZz Fizz fiZzbUzz Buzz 82 Buzz 84 Buzz 86 " +
"Buzz 88 FizzBuzz 90 Buzz Fizz bUzz 94 95 Buzz Fizz 98 BUzz " +
"fizz 101 FizzBuzz BUzz 104 Fizz FIZzbUzZ 107 Buzz Fizz fIZzBuzZ " +
"Fizz fiZzbUZz Buzz 114 Buzz 116 Buzz 118 Buzz 120 FizzBuzz " +
"122 Buzz Fizz BUzz Buzz buzz 128 129 Fizz Buzz 132 Fizz Buzz " +
"fizz Buzz 137 138 Fizz fIZzBuZz Fizz Buzz 143 buzz Fizzbuzz " +
"FizzBuzz Fizz 148 fizzbuzz").exec();
}
public class FizzBuzzInterpreter {
public String code;
public int[] mnemonics = null;
public int pc;
private List<Integer> stack;
private FizzBuzzInterpreter() { this(""); }
public FizzBuzzInterpreter(String s) {
this.code = s.trim();
mnemonics = null;
this.pc = 0;
this.stack = new ArrayList<>();
}
public void compile() {
String[] terms = code.split("[ ,\t\r\n]+");
List<Integer> list = new ArrayList<>();
List<String> commands = Arrays.asList("fizz","Fizz","buzz","Buzz","fizzbuzz","Fizzbuzz","fizzBuzz","FizzBuzz");
for (int i = 0, len = terms.length ; i < len
{
if (terms[i].toLowerCase().matches("fizz|buzz|fizzbuzz")) {
list.add(commands.indexOf(terms[i])+(i%2>0?1:9));
if ("Fizz".equals(terms[i]) || "FizzBuzz".equals(terms[i]) || ("fizzbuzz".equals(terms[i]) && i%2>0)) {
while (!terms[++i].toLowerCase().matches("fizz|buzz|fizzbuzz"));
list.add(FizzBuzz2Num(terms[i]));
} else list.add(0);
}
i++;
}
mnemonics = new int[list.size()];
int i = 0; for (int v : list) mnemonics[i++] = v;
}
public boolean step() throws Exception {
if (mnemonics == null || mnemonics.length < 1) return false;
switch (mnemonics[this.pc]) {
case 1: stack.add(0, stack.remove(1)); stack.add(0, stack.remove(0) % stack.remove(0)); break; // MOD
case 2: break; // LABEL
case 3: // ROLL
int n = stack.remove(0);
if (n < 0 && n + stack.size() >= 0) stack.add(0, stack.remove(stack.size()+n));
else if (n > 0 && n < stack.size()) stack.add(0, stack.remove(n));
break;
case 4: stack.add(0, stack.get(0)); break; // DUP
case 5: if (stack.remove(0) == 0) searchLabel(this.mnemonics[this.pc+1]); break; // JZ
case 6: stack.remove(0); break; // DROP
case 7: stack.add(0, stack.remove(0) * stack.remove(0)); break; // MUL
case 8: if (stack.remove(0) != 0) searchLabel(this.mnemonics[this.pc+1]); break; // JNZ
case 9: stack.add(0, stack.remove(0) + stack.remove(0)); break; // ADD
case 10: stack.add(0, this.mnemonics[this.pc+1]); break; // PUSH
case 11: System.out.print(stack.remove(0)); break; // PUTN
case 12: System.out.print(String.format("%c", stack.remove(0))); break; // PUTC
case 13: return false; // EXIT
case 14: stack.add(0, -stack.remove(0) + stack.remove(0)); break; // SUB
case 15: stack.add(0, stack.remove(1)); stack.add(0, stack.remove(0) / stack.remove(0)); break; // DIV
case 16: searchLabel(this.mnemonics[this.pc+1]); break; // JMP
default: break; // UNKNOWN
}
this.pc+=2;
return true;
}
public boolean exec() {
if (this.mnemonics == null || this.mnemonics.length < 1) this.compile();
try { while (this.step()); return true;
} catch (Exception e) { return false; }
}
private void searchLabel(int label) {
for (int i = 0, len = this.mnemonics.length ; i < len ; i+=2) {
if (this.mnemonics[i] != 2 || this.mnemonics[i+1] != label) continue;
this.pc = i; return;
}
}
private int FizzBuzz2Num(String s) {
if (!"fizzbuzz".equalsIgnoreCase(s)) {
if ("buzz".equalsIgnoreCase(s)) s = "fizz" + s;
else if ("fizz".equalsIgnoreCase(s)) s += "buzz";
else s = "fizzbuzz";
}
s = s.replaceAll("[a-z]", "0").replaceAll("[^0]", "1");
s = new StringBuilder(s.substring(4) + s.substring(0, 4)).reverse().toString();
return Integer.parseInt(s.substring(1), 2) - (s.charAt(0)=='0'?0:128);
}
}
}
出題者コメント
なぜ言語を作ったし。
……とびきり不適切です。
是非皆さん、 FizzBuzz 言語で何かしらのプログラムを実装してみてください。
え?私?今からちょっと外出しなければならないので…。
ところで、非FizzBuzz項 って言いにくいですね。
「赤非FizzBuzz項 青非FizzBuzz項 黃非FizzBuzz項」
はい、あなたの番です。
supermomonga 様
オオトリは、 不適切な FizzBuzz 問題出題のきっかけとなった ネタ元の supermomonga 様です。
タイトル:Ripper FizzBuzz
言語:Ruby
説明文
Rubyの標準ライブラリであるRubyパーサ「Ripper」を用いることで、
ソースコード自身をロジックとして組み込みました。
Ripperには、コードをS式に変換するRipper.sexpというメソッドがあります。
それによって変換されたコードのS式からは各コマンドのソースコード内での出現位置などの各種情報を取得することができます。
ソースコード内の1から14行目までには、それぞれ以下のようにコードを配置しています
1行目 … シンボルリテラルで開始
3n+1行目 … 代入式
5n+1行目 … 文字を含む文字列リテラル
それ以外 … 文字を含まない文字列リテラル(空文字)
1行目をS式に変換したものは以下の様になります。
[[:method_add_block,
[:call,
[:symbol_literal, [:symbol, [:@ident, "ripper", [1, 1]]]],
〜中略〜
]]],
4行目である代入式をS式に変換したものは以下の様になります。
[:assign,
[:var_field, [:@ident, "itself", [4, 0]]],
〜中略〜
],
6行目である文字を含む文字列リテラルをS式に変換したものは以下の様になります。
[:string_literal, [:string_content, [:@tstring_content, "Fizz", [6, 2]]]],
それ以外である文字を含まない文字列リテラル(空文字)をS式に変換したものは以下の様になります。
[:binary,
〜中略〜
[:binary,
[:string_literal, [:string_content]],
〜中略〜
:%,
[:string_literal, [:string_content]]],
この様に、文字を含まない文字列リテラル(空文字)以外の行のコマンドには、ソースコード上での出現位置が
[行,列]という形で格納されています。正確にはリテラルを除いた識別子や文字の出現位置となるので、
それぞれ列数が以下のような法則になります。
代入式 … 1列目
文字列 … 3列目
シンボル … 2列目
これを用いて、17行目から22行目の処理ではソースコード自身から以下の様な行列を表す配列を含む配列を取得しています。
[
[1, 8],
[4, 0],
[6, 2],
[7, 0],
[10, 0],
[11, 2],
[13, 0]
]
ある自然数nを15で割ったあまりに1を足したものの取り得る範囲は1〜15です。
1から100までの自然数について、15で割ったあまりに1を足した数と、
行番号が一致する配列を抜き出し、その列番号によって出力する内容(Fizz、Buzz、FizzBuzz)を分岐しています。
一致する行番号の配列が見つからなかった場合は自然数自身を出力します。
プログラム
:ripper.tap{|ripper| require %%\%s%% ripper }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
itself = ->{__FILE__}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%Fizz%
source = ->{File.read itself[]}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
s_expression = ->{Ripper.sexp source[]}
%%Buzz%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
commands = ->{s_expression[][1].take 15}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$><< 1.upto(100).map{|n|
commands[].map{|_|
_[1][-1][-1].tap{|__|
break _[1][-1] unless Array === __
}
}.reject{
|_|Symbol === _[0]
}.find{|_,__|
_ == n % 15 + 1
}.tap{|_|
break case [_].flatten.last
when 0 then commands[][5][1][1][1]
when 2 then commands[][10][1][1][1]
when 8 then commands[][5][1][1][1] + commands[][10][1][1][1]
else n
end
}
}.join
出題者コメント
さすがのネタ元です。
まとめ
皆様、素晴らしい解答をありがとうございました。
読み手の皆様、お気に入りの解答はありましたか?
気が向いたら、ハッシュタグ付きで呟いてみてください。
○○さんの解答イイ! #codeiq #fizzbuzz
また、今回掲載していただいた以外にも面白い解答は多くありました。
掲載されていない方も是非、答えを共有してみてください。
私の解答 url #codeiq #fizzbuzz
などのように。
私が出題する問題は出題後にツイッターで感想戦が行われる事が多く、
この感想戦に参加することで他のエンジニアさんと繋がるチャンスがあります。
これは、 CodeIQ の楽しみが広がるだけではなく、エンジニアとしての楽しみも
広がっているように見受けられます。
気が向いたら感想戦の輪に飛び込んでみてはいかがでしょうか。