Two Dice of A sides ネタばらし
anarchy golf - Two Dice of A sides
時間切れにてソース公開したのでネタばらし。
下記はぐだぐだ書いてるだけなんで、上のリンクからソース見た方がはやいっす。
最初に問題を見た日に出来たのはこんなのでした。
main(n){for(;9/printf("N=%d,A=%d\n",n++,(n>9?n/11+11:n+1)/2););}
ループの終了条件9/printf(...)を思いついたりして削った結果64バイト。そのときのトップには1バイト及ばず。
色々考えても思いつかず、変数一個には限界を感じたのでAの値をインクリメントする作戦に切り替えました。
Aの値が切り替わる条件は、
- Nが奇数である (a)
- Nが10以下、または11の倍数 (b)
の両方を満たすときなので、あとは両方を満たすときに1、それ以外は0となるコードを短く書けばよい。
11の倍数判定は11で割った商か剰余でやるのが正しい(はず)、ということでまずは剰余を選んでみる。
Nを11で割ると、Nが11の倍数は余りが0になる。Nが10以下なら11の倍数ではないので0にはならない。N%11とNの大小を比べるとN<11のときだけ同じ、あとは後者の方が大きくなる。
よってN%11%NはNが10以下、または11の倍数のときだけ0、あとは1以上となる。
この式さえ出来てしまえば、(a)(b)を両方満たすかどうかは、CならN%2>N%11%N、JavaならN%2>>N%11%Nと書ける。
で、最終的にぼくが出したのはこんなコード(60バイト)でした。
a;main(n){for(;9/printf("N=%d,A=%d\n",n++,a+=n%11%n<n%2););}
(サブミットしたコードとは変数名が異なっています)
いろいろな言語で出してみる
一応これでCは打ち止めかなと思ったので、他の言語で同じことをやってみることにしました。
C++
#import<ios> int a,b;main(){for(;9/printf("N=%d,A=%d\n",a,b+=++a%11%a<a%2););}
D
void main(){for(int n,a;9/printf("N=%d,A=%d ",n,a);)a+=++n%2>n%11%n;}
Java(シフト)
class A{public static void main(String[]z){ for(int n,a=n=0;n++<99;System.out.println("N="+n+",A="+a)) a+=n%2>>n%11%n; } }
for(n=a=0;n++<99;print("N="+n+",A="+a))a+=n%2>n%11%n
<?for(;$n++<99&&$a+=$n%11%$n<$n%2;)echo"N=$n,A=$a ";
Ruby(シフト)
a=0;1.upto(99){|n|puts"N=#{n},A=#{a+=n%2>>n%11%n}"}
END{for(;n++<99;)print"N="n",A="(a+=n%11%n<n%2)}
で、Perlを考えているうちに2変数にせずにminがあればいいことに気付きました。
(その後さらにC++の別解を考えてるときにgcc拡張のminと三項演算子の二項目省略に行き着きましたorz)
Cで使った方法は使えないときはminで解き、結局13言語(C,C++,D,Java,JavaScript,PHP,Ruby,Perl,Python,AWK,Lua,OCaml,Scheme)でサブミット。1/3くらいはほとんど書いたことなかった言語でした。