第4回コードゴルフ大会 WriteUp - hakatashi/esolang-battle GitHub Wiki

お題

入力された4つの点を頂点とする四面体の体積を求めよ。

入力

  • 3次元空間上の4つの点の座標 A, B, C, D が改行(LF)区切りで与えられる。
  • 各座標は2桁の数字3つの空白区切りで表現され、それぞれX軸、Y軸、Z軸の値を表す。
    • 10未満の数字は先頭が0で詰められる。
  • 入力の各行は正規表現 ^\d{2} \d{2} \d{2}$ で表現される。
  • 入力の最後には改行が付与される。

出力

  • 入力された4つの点を頂点とする四面体の体積を整数で出力せよ。
  • 出力された数の前後に含まれる空白文字は無視される。
  • 出力された数の先頭に存在する数字の 0 はすべて無視される。
  • 数字と空白文字以外の文字を出力してはいけない。

制約

  • 各座標のX軸、Y軸、Z軸の値は1以上99以下の整数である。
  • 四面体の体積は整数であることが保証される。
  • 四面体の体積は5000以上であることが保証される。
  • 右手系の座標系において点 A から三角形 BCD を見たとき、点 B, C, D がこの順で時計回りに並んでいることが保証される。

一般的なテクニック

四面体の体積の導出

  • AB, AC, AD を張るベクトルを計算し、それらがなす3行3列の行列の行列式を6で割った値が四面体の体積となる
  • OA, OB, OC, OD を張るベクトルのなす3行4列の行列に (1, 1, 1, 1).T をくっつけた4行4列の行列の行列式を6で割った値が四面体の体積となる

入力のパース

  • ...

行列式の計算

  • ライブラリを使用
  • 直接計算 (サラスの公式)
  • 明示的な定義 (ライプニッツの公式)
  • 行列の固有値の実数成分の総乗
  • 行列のジョルダン標準形の対角成分の総乗
  • 行列のスミス標準形の対角成分の総乗
  • 余因子展開
  • ...

出題意図 (@hakatashi)

毎度そうだけど、コードゴルフ大会のお題は本当に難産。

今回はマップが立体ということでなるべく立体にちなんだ問題を用意したかった。 そんな折に見つけたのが Anarchy Golf の area of triangle で、 若干趣は異なるもののこれを3次元に拡張すればいいのでは? ということでこういうお題に。

(実際はこのお題にたどり着くまでにいろんなアイデアを経ているがそれは今後の大会のために取っておく)

結局のところ立体とは名ばかりで、実際には3次元の行列式を求めるのが本質となる問題である。 インターネットにすでに存在する類似問を探したところ、stackexchangeに一般次元の行列式を求める問題があったが、 やはり一般次元と3次元では勝手が異なるだろうと思った (実際そうだった) ので特に気にしなかった。 なお、既にここに良質な回答が多く上がっていたJellyやHaskellなどの言語は今回のマップに入れないようにした。

上の通り行列式の計算方法にバリエーションがあるので、色んな方法を工夫しながら楽しめるかと思ったが、 実際にはほとんどの言語で直接計算するはめになったのであまり楽しめなかった。 点BCDの座標から点Aの座標を引き算する部分は若干工夫しがいがあったように思う。

最悪簡単な加減算と乗算だけで済むしesolangでも力技で解けるやろ~と軽い気持ちで考えていたが、 計算途中の数値が8bitどころか16bitにも収まらないので、8bit以上の変数が持てない一部のesolangで非常なつらみが発生したのに加えて、 やはり12個の変数を同時に保持しておく必要があるのがいろんな言語でつらかったのは反省点。 むやみにbit数は増やさないほうがいいかも知れない。

今回アセンブリを多く出題したが、アセンブリのゴルフは不毛なので、やはり機械語は機械語のままゴルフしたほうがいいという学びを得た。

Alice (@kuromunori)

79 bytes

/o\5&ww]!k]2&wa&[???2&w]]]?-!k?[?*[[?5v
@i/:6k+*?[~w*?[&4kb-*?]]?]*?[&4?w-*?]&<

1文字が1コマンドであり、これを二次元平面に配置。

基本左上から右へ読み込むが、>v<^で向きが変わったり/\で斜めに反射したりする。

そして斜め移動中か水平垂直移動中かでコマンドの意味が変わる(!?)

まぁスタックも使えるし配列も使えるしfor文も書けるしサブルーチンも使えるしと完璧な言語(ほんまか)

Aliceは楽しい(洗脳済み)

Bash (busybox) (@kurgm)

104 bytes

tr '
' \ |awk '{for(i=9;i;)$i-=$(--i%3+10);print(($2*$4-$1*$5)*$9+($3*$5-$2*$6)*$7+($1*$6-$3*$4)*$8)/6}'

最初はreadechoだけで頑張っていたのだが@taiyoslime氏がこれのもとになるものをDiscordで提供してくれたのでそれを縮めていった。++とか--のあたりで手元のawkとサーバーの(busyboxの?)awkで挙動が違ってて、環境依存ですねえという感じ。

Befunge-98 (@satos___jp)

212 bytes

v
v   v        <
>66+>:&\0p1-:| v                         <
             >9>1-:::3%55++0g\1+0g-\1+0p:|
                                         >50g90g*60g80g*-10g*70g60g*40g90g*-20g*40g80g*70g50g*-30g*++6/0\-.@

befungeが見えたのが残り1日程度で、時間的に青チームと戦うことにはならないだろうと思ったのでとりあえず動くコードを提出。 わりと見た目どおりの直観的なコード。(ところでbefungeのよいonlineインタプリタが見当たらないんですが誰か知りませんか)

Brainfuck (BFI) (@akouryy1)

6456 bytes

Brainfuck (esotope) (@satos___jp)

31029 bytes

コード生成に使ったプログラムです。

https://gist.github.com/satos---jp/45cb82b84af41e8cc9c78dd02b07e68b

esotopeは各セルが256で一周するので""多倍長整数""を実装することになりました。 あといいインタプリタが見当たらなかったので自分でインタプリタを書いた。(結果的にこれでだいぶ楽になった)

C (GCC) (@n4o847)

116 bytes

i;X[9];main(s){~scanf("%d",X+i)?main(s-i/9*(X[i-3]-=X[i])*(X[++i%3]*X[3-~i%3]-X[3+i%3]*X[-~i%3])):printf("%d",s/6);}

初出場にして C を奪えて嬉しい。

det(A-D, B-D, C-D) == det(A-B, B-C, C-D) という処理のしやすい式変形が勝因だったと思う。

i/9 を掛けてループを一つにまとめるなど基本的な構造は @kurgm 氏と @taiyoslime 氏から受け継いだ。

X[9] としているが、実はアクセス範囲は -3 ~ 11 である。試したら X[4] くらいまで減らせた(C はこういうところが)。

for より main 再帰の方が 1byte 少ない。あと、s には最初に 1 が入るが最後に 6 で割るので問題ない。

cmd.exe (@kurgm)

209 bytes

set/pq=
for /f "tokens=1-12 delims=%q:~8,1% " %%a in ("%q%") do set/aa=%%d-%%a,b=%%e-%%b,c=%%f-%%c,d=%%g-%%a,e=%%h-%%b,f=%%i-%%c,g=%%j-%%a,h=%%k-%%b,i=%%l-%%c,v=(a*e*i+b*f*g+c*d*h-a*h*f-b*i*d-c*g*e)/6
echo %v%

@__dAi00氏のを縮めた感じ。入力の改行がCRLFじゃなくてLFなのがつらかったらしい。入力全体がset/pq=qに入ってきて、%q:~8,1%(入力の先頭から数えて8文字後からの1文字)がLFになっていてそれとスペースを区切り文字にしてfor /fで分解してる感じ(だと思います)。

Convex (@moratorium08)

121 bytes

0qN%{S%{i}%}%_1>\1<3*.{.-}e__1=\_3=@*\_4=\_0=@*@-\_8=@*@+\_0=\_5=@*\_2=\_3=@*@-\_7=@*@+\_4=\_2=@*\_1=\_5=@*@-\_6=@*@+6/\;

Crystal (@kurgm)

105 bytes

a=`dd`.split.map &.to_i;p (0..8).map{|z|z/6*(a[z]-=a[z+3])*(a[s=3+-~z%3]*a[t=-~s%3]-a[s-3]*a[t+3])}.sum/6

@taiyoslime氏のコードを縮めた。`dd`でddコマンドを呼んだ出力が得られて、要するに標準入力の全体がとれる。1行下を引いていって、1〜3行目の行列式を3行目に関する余因子展開で計算。

C# (Mono) (@kurgm)

196 bytes

using static System.Console;class _{static void Main(){int x=0,i=0;for(int[]X=new int[12];i<12;Read())x+=i/9*(X[i]=Read()*10+Read()-X[i%3])*(X[++i%3+3]*X[-~i%3+6]-X[i%3+6]*X[3-~i%3]);Write(x/6);}}

入力は一文字ずつ読んでいく方式。1行目を2〜4行目から引いて、2〜4行目の行列式を4行目に関する余因子展開で計算。

Cubix (@kuromunori)

223 bytes

.................................................
IIIIIIIIIIII3t-s;s6t-s;s9t-u
Uq;s;s-t6s;s-t4s;s-t2qqq;s;s
qq1t-s;s2t-s;s3t-s;s;5t*4t5u
Ut4*t4;;q-t3*t6t5*t4;;q-t3*t
6t*3t-q;;B5t*q2t4t*q4t5t*p+u
U@On,6+p....................

立方体上にソースコードを配置、その上をプログラムが走っていく、というもの。 立方体っぽさを出した形に成形すると以下。

              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
I I I I I I I I I I I I 3 t - s ; s 6 t - s ; s 9 t - u
U q ; s ; s - t 6 s ; s - t 4 s ; s - t 2 q q q ; s ; s
q q 1 t - s ; s 2 t - s ; s 3 t - s ; s ; 5 t * 4 t 5 u
U t 4 * t 4 ; ; q - t 3 * t 6 t 5 * t 4 ; ; q - t 3 * t
6 t * 3 t - q ; ; B 5 t * q 2 t 4 t * q 4 t 5 t * p + u
U @ O n , 6 + p . . . . . . . . . . . . . . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .
              . . . . . . .

7×7×7の立方体の展開図上にコードを記している。 ただお気づきの通り、上面と底面を使っていないので実質平面上のコーディングと一緒。

立体考えて設計する頭がなかった……

Cy (@akouryy1)

72 bytes

"\\#{require'matrix';p Matrix[*$<.map{|x|eval'A=1,'+x.split*?,}].det/6}"

D (DMD) (@kurgm)

145 bytes

import std.stdio;void main(){int p,x,i;for(int[12]X;readf("%d ",p);)x+=i/9*(X[i]=p-X[i%3])*(X[++i%3+3]*X[p=-~i%3+6]-X[i%3+6]*X[p-3]);write(x/6);}

1行目を2〜4行目から引いて、2〜4行目の行列式を4行目に関する余因子展開で計算。変数宣言を短くするため意味が違うところでpを使いまわしている。

Element (@kuromunori)

122 bytes

4'[_3:]9;(#(#10;(#(#(#(#(#11;
9'{"1-+k;k~3%j;j~'[(#(#(#]j~9+~-+k~;k~'}
4~8~*5~7~*-+0~*5~6~*3~8~*-+1~*3~7~*4~6~*-+2~*++6/-`

やるだけです。 入力は1行分が文字列として与えらえるので(#で適当に文字を削り部分文字列を作って対処

Emojicode (@xuzijian629_key)

593 bytes

🏁🍇🍮z🔷🔡👂🏼🍮a🍺🚂🔪z 0 2 10🍮b🍺🚂🔪z 3 2 10🍮c🍺🚂🔪z 6 2 10🍮z🔷🔡👂🏼🍮d🍺🚂🔪z 0 2 10🍮e🍺🚂🔪z 3 2 10🍮f🍺🚂🔪z 6 2 10🍮z🔷🔡👂🏼🍮g🍺🚂🔪z 0 2 10🍮h🍺🚂🔪z 3 2 10🍮i🍺🚂🔪z 6 2 10🍮z🔷🔡👂🏼🍦j🍺🚂🔪z 0 2 10🍦k🍺🚂🔪z 3 2 10🍦l🍺🚂🔪z 6 2 10🍮a➖a j🍮d➖d j🍮g➖g j🍮b➖b k🍮e➖e k🍮h➖h k🍮c➖c l🍮f➖f l🍮i➖i l😀🔡➗➖➖➖➕➕✖✖a e i✖✖b f g✖✖c d h✖✖a f h✖✖b d i✖✖c e g -6 10🍉
🍮z🔷🔡👂🏼

でzに一行の入力を文字列として読み込み、

🍮a🍺🚂🔪z 0 2 10

で、zの0文字目から2文字を10進数として評価したintegerをaに格納します。あとはやるだけ。演算子がポーランド記法なのに注意

><> (@n4o847)

68 bytes

0\&6,n;
?\ia*i+4[:{-}]i0(
&\{r9[0
!\r5[}:{:@{{:}@:}*@*-]r{*&+&0}}}:?

同じ2次元スタック言語として Alice をライバル視していたりしていなかったり。

\ でコードを反射していて、端と端はつながっているドラクエ方式。

  • 1行目前半:準備
  • 2行目(ループ):入力を数値化しつつ差分を取る(C と同じ)
  • 3行目:必要な数値だけ集める
  • 4行目(ループ):スタックまわして計算(結構ややこしい)
  • 1行目後半:出力

Fugue (@__Hyoga)

9391 bytes

Fugue(フーガと読むらしい)は複数スタックの間で値をやり取りしながら頑張る言語です。Preludeと等価なので、取り敢えずPrelude書きます。が、第1回コードゴルフ大会のkurgm師匠のコードを見て「何で最後文字コードにしていないんだろう?」と疑問に。Preludeの!は文字コード出力のはずなんですが(tioも文字コード出力)、何故か数字のまま出力されている模様。見てみると、pythonでのinterpreterでは数字のまま出力される模様。ってことでpreludeを書く際に任意の位置でどの数字が入っているのか簡単に確かめられて幸せになれます。

preludeで書くとこんな感じ。

                           v 0         v -      v +         v      #(1-)# (1-)v 0 v+      #
                          v #v  v #v #v #v #v #v -v #v #v #v #   ^      #0 v+  #     0 ^+  ^+  0 v+
                         v #v #v #v  v #v #v #v #v #v #v #v   v   #0 ^+       #  (1-)#(1-)   ^v     # ^-
                        v #v #v  v  v #v #v -v #v #v #v  v # # #v^                             #(1-)#(1-)^  0 v+
                       v  v #v #v #v #v #v -v #v #v #v #v # ^    #                                        ^v     # ^+   0 v+
6(1-)                 v #v #v #v #v #v  v #v #v #v #v  v #v    #                                         ^  #(1-)#(1-)^v     # ^-
  8+     v    #      v #v  v #v #v #v  v #v #v -v  v #v #  # #^ v                                                       #(1-)#(1-)^  0 v+
      ?^-  ^+ ?^-+?#  #  #   #  #  #  #  #  #  #  #  #      ^    #                                                                 ^v     # ^-
  2+ (1- 9(1-)#     )^ #^ #0^ -^ #^ #^ #^ #^ #^ +^ ^  #^ #  # # v v                                                                v #(1-)#(1-)^
                      ^ #^ # ^ #^ #^  ^ #^ #^ #^ #^ #^ #^ #^ ^ # # #    v                                                                       ^  0 v+
                       ^ #^ # ^ #^ #^  ^ #^ #^ #^ #^ #^ -^ #  ^          #                                                                       ^v     # ^+  
                        ^  ^ # ^ #^ #^ #^ #^ #^ #^  ^ #^ #^ #                                                                                   ^  #(1-)#(1-)^  0 v+
                         ^ #^   ^ #^ #^ #^ #^ #^ #^ #^ #^- ^ #                                                                                                ^v     # ^-                                                                                                           v         #
                          ^ #^ # ^ #^  ^ #^ #^ #^ #^  ^ #   ^ #                                                                                              ^  #(1-)#(1-)^  0 v+                                                #                                       v         # 1+ #^        8+ !
                           ^ #^ # ^ #^  ^ #^ #^ #^ #   ^ -   ^ #                                                                                                           ^v     # ^+                                           #                            v         # 1+ #^    55+-(55++0)#   8+  !
                            ^ #^ # ^     ^ #^ #^ #^     ^ #   ^ #                                                                                                         ^  #(1-)#(1-)^  0 v+                                   #                 v         # 1+ #^    55+-(55++0)#              8+   !
                             ^  ^ # ^ #   ^ #^ #^ #^ #   ^-    ^ #                                                                                                                      ^v     # ^-                              #      v         # 1+ #^    55+-(55++0)#                         8+    !
                                 ^ # ^ #   ^ #^  ^ #^           ^ #                                                                                                                    ^  #(1-)#(1-)^  0 v+                      #       1+  #^   55+-(55++0)#                                    8+     !
                                  ^ # ^ #   ^ #^  ^ #            ^-                                                                                                                                  ^v     # ^+                 #   1+55+-(55++0)#                                               8+      !
                                   ^   ^ #   ^ #   ^              ^ #                                                                                                                               ^  #(1-)#(1-)^  0 v+      0 1+ (1-                                                         )6(1-)
                                        ^     ^ #   ^ #            ^-                                                                                                                                             ^v     # ^-  (6-)               
                                               ^     ^                                                                                                                                                           ^  #(1-)#(1-)

基本的な方針は行列式を展開、可能な範囲でまとめて、それぞれの項を頑張って計算して足す感じです。最初12個の数字を全部回収(0の文字コードである48をちゃんと引いて10進表現で受け取る)して、それを22個(計算用スペースがある影響で項数のほぼ2倍のスタックを使っている)のスタックに飛ばします。分散後は各スタック(計算用除く)に3つ値が入っていて、これらの積を加減していく感じ。掛け算割り算は出来ないので、値が0になるまで足していきます。が、O(abc)だとTLEするので、いわゆる以下のコード

while(a--)while(b--)while(c--)ret++;

は通らず、

whlie(b--) tmp+=a;
whlie(c--) ret+=tmp;

とします。bやcがマイナスだと即TLEなのでスタックに何が入っているか気を付けます。その後はこれを6で割って(ここまで実装できる実力があれば楽勝)、文字コードにします。mod10ってどうやるの?と思ったので、ここは諦めてO(N)解法。カウンターを作っています。brainf∨ck辺りとかどうしてたんでしょうね…おかげで結構な確率でTLEします。

後はこれをMIDIに打ち込むだけです(白目)。音の高さの変化で判別するみたいです。僕は手書きでEsolangをやる人なので、これも手打ちしていたのですが、深夜にやっていたので当然ミス。バグらせます。fugueの神仕様があり、「/dis」オプションを用いるとMIDIファイルをpreludeのような感じのcsvにしてくれるので、これを使ってデバッグ(この間にkurgm師匠がpreludeをfugueに変換してくれるコードを書いてくださったので、それを用いてAC)。なんか全トラック最後に音を入れないと途中でコードが切れるみたいです。最後にバイナリをちょっと削って(闇操作)kurgm師匠のコードで自動生成されたコードを上回りました。

preludeはスタックを1つ増やすと大量のスペースでコード量が爆発するのですが、fugueは音符が入るまで大して増えないので、スタックをたくさん使って構いません。因みに、音の高さは気分で適当に分散させたので、最初に聴くと思わず笑ってしまい、以降聞き続けるとせいしんがふあんていになります。

Function (@kuromunori)

41427 bytes

ソースコード見ればわかるけど、エディタ上で配線をするクソ言語。 mnemoのGUIをクソクソのクソにした完全下位互換。

良い子はmnemoで遊びましょう https://mnemo.pro/

GolfScript (@akouryy1)

81 bytes

"
"/);{' '/}%(\{[1$\]zip{{~}%{-}*}%}%.{}/{(+\(+(+[@]zip{{*}*}%{+}*6/}:q~\{}/\q-\;

goruby (@xuzijian629_key)

66 bytes

require'matrix';p -Matrix[*$<.map{|l|l.split.map(&:toi)<<1}].det/6

satosの功績を縮めただけです。

gs2 (@hakatashi)

99 bytes

htms (@lip_of_cygnus)

2959 bytes

<htms id="htms"><var name="s"><q><code><q>stdin</q></code></q></var><var name="x"><a><ol><li><q><span>s</span><sub><i>0</i></sub></q></li><li><q><span>s</span><sub><i>1</i></sub></q></li></ol></a></var><var name="y"><a><ol><li><q><span>s</span><sub><i>3</i></sub></q></li><li><q><span>s</span><sub><i>4</i></sub></q></li></ol></a></var><var name="z"><a><ol><li><q><span>s</span><sub><i>6</i></sub></q></li><li><q><span>s</span><sub><i>7</i></sub></q></li></ol></a></var><var name="a"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>9</i></sub></q></li><li><q><span>s</span><sub><i>10</i></sub></q></li></ol></a></i></li><li><span>x</span></li></ol></s></var><var name="b"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>12</i></sub></q></li><li><q><span>s</span><sub><i>13</i></sub></q></li></ol></a></i></li><li><span>y</span></li></ol></s></var><var name="c"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>15</i></sub></q></li><li><q><span>s</span><sub><i>16</i></sub></q></li></ol></a></i></li><li><span>z</span></li></ol></s></var><var name="d"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>18</i></sub></q></li><li><q><span>s</span><sub><i>19</i></sub></q></li></ol></a></i></li><li><span>x</span></li></ol></s></var><var name="e"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>21</i></sub></q></li><li><q><span>s</span><sub><i>22</i></sub></q></li></ol></a></i></li><li><span>y</span></li></ol></s></var><var name="f"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>24</i></sub></q></li><li><q><span>s</span><sub><i>25</i></sub></q></li></ol></a></i></li><li><span>z</span></li></ol></s></var><var name="g"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>27</i></sub></q></li><li><q><span>s</span><sub><i>28</i></sub></q></li></ol></a></i></li><li><span>x</span></li></ol></s></var><var name="h"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>30</i></sub></q></li><li><q><span>s</span><sub><i>31</i></sub></q></li></ol></a></i></li><li><span>y</span></li></ol></s></var><var name="i"><s><ol><li><i><a><ol><li><q><span>s</span><sub><i>33</i></sub></q></li><li><q><span>s</span><sub><i>34</i></sub></q></li></ol></a></i></li><li><span>z</span></li></ol></s></var><div><ol><li><s><ol><li><s><ol><li><i>0</i></li><li><em><ol><li><span>a</span></li><li><span>f</span></li><li><span>h</span></li></ol></em></span></li><li><em><ol><li><span>b</span></li><li><span>d</span></li><li><span>i</span></li></ol></em></span></li><li><em><ol><li><span>c</span></li><li><span>e</span></li><li><span>g</span></li></ol></em></span></li></ol></s></li><li><s><ol><li><i>0</i></li><li><em><ol><li><span>a</span></li><li><span>e</span></li><li><span>i</span></li></ol></em></span></li><li><em><ol><li><span>b</span></li><li><span>f</span></li><li><span>g</span></li></ol></em></span></li><li><em><ol><li><span>c</span></li><li><span>d</span></li><li><span>h</span></li></ol></em></span></li></ol></s></li></ol></s></li><li><i>6</i></li></ol></div></htms>

NumberオブジェクトとStringオブジェクトしか返さないJavascriptっぽい言語。 添字が使えることに気づくと早い。基本的にただ計算するだけ。ただしadd関数が数値同士だとうまくいかないバグ?があるのでsub関数で足し算した。 最初eval関数を利用しようと考えたがStringオブジェクトに変換されるので無理っぽい。

Java (@kurgm)

230 bytes

import java.util.*;interface A{static void main(String[]a){int i=0,x=0,X[]=new int[12];for(Scanner s=new Scanner(System.in);i<12;)x+=i/9*(X[i]=s.nextInt()-X[i%3])*(X[++i%3+3]*X[-~i%3+6]-X[i%3+6]*X[3-~i%3]);System.out.print(x/6);}}

class A{public static void mainよりinterface A{static void mainの方が3文字短くて済む(@taiyoslime氏が縮めてくれた)。1行目を2〜4行目から引いて、2〜4行目の行列式を4行目に関する余因子展開で計算。

Kotlin (@kurgm)

205 bytes

import java.util.*
fun main(a:Array<String>){val s=Scanner(System.`in`)
val X=IntArray(12)
print((0..11).sumBy{i->X[i]=s.nextInt()-X[i%3]
i/9*X[i]*(X[(i+1)%3+3]*X[(i+2)%3+6]-X[(i+1)%3+6]*X[(i+2)%3+3])}/6)}

JavaをKotlinに変換したやつを縮めていった。-~iとかは-i.inv()になって長くなったので仕方なく(i+1)に。あとは複数の変数宣言がまとめられないので変数はむやみに増やさないほうがよさそう。

Labyrinth (@moratorium08)

630 bytes

????????????}}}}}}}}}{}}}:={={={-}{=}{}}:={={-}{=}{={=}=}{}:={-}{={=}=}{={={=}=}=}{}}}:={={={-}{={={=}=}=}{={={={=}=}=}=}{}}:={={-}{={={={=}=}=}=}{={={={={=}=}=}=}=}{}:={-}{={={={={=}=}=}=}=}{={={={={={=}=}=}=}=}=}{}}}:={={={-}{={={={={={=}=}=}=}=}=}{={={={={={={=}=}=}=}=}=}=}{}}:={={-}{={={={={={={=}=}=}=}=}=}=}{={={={={={={={=}=}=}=}=}=}=}=}{}:={-}{={={={={={={={=}=}=}=}=}=}=}=}{{{{{:}}=}=}=}=}{{:}}{*{{:}}=}{{{{{:}}=}=}=}{*-{{{{{{{{{:}}=}=}=}=}=}=}=}=}{*{{{:}}=}=}{{{{{:}}=}=}=}{*{:}}{{{{{{{:}}=}=}=}=}=}{*-{{{{{{{{:}}=}=}=}=}=}=}=}{*+{{:}}=}{{{{{{{:}}=}=}=}=}=}{*{{{{{:}}=}=}=}=}{{{{:}}=}=}{*-{{{{{{{:}}=}=}=}=}=}=}{*+_6/!@

LLVM IR (@kurgm)

1056 bytes

次のC言語をclang -S -emit-llvm hoge.cとかやって出てきたものを短くした。

int a,b,c,d,e,f,g,h,i,j,k,l;
int main(){
  scanf("%d%d%d%d%d%d%d%d%d%d%d%d",&j,&k,&l,&a,&b,&c,&d,&e,&f,&g,&h,&i);
  a-=j;b-=k;c-=l;d-=j;e-=k;f-=l;g-=j;h-=k;i-=l;
  printf("%d",(a*(e*i-h*f)+b*(f*g-i*d)+c*(d*h-g*e))/6);
}

Lua (@kurgm)

129 bytes

X={}
for i=-3,8 do
X[i]=io.read"*n"-(X[i%3-3]or 0)
p=-~i%3
q=~-i%3
x=i>5 and x+X[i]*(X[p]*X[q+3]-X[q]*X[p+3])or 0
end
print(x//6)

1行目を2〜4行目から引いて、2〜4行目の行列式を4行目に関する余因子展開で計算。

Luaには配列は無く、キーが数値であるハッシュテーブルとして済ませているらしい。ので、負数をインデックスにして1行目を格納することができる(その方が、行列式の計算で2行目にアクセスするときに3で割った余りに3を足したりする必要がなく、字数削減になる)。

Make (@satos___jp)

1956 bytes

Makeは文字列置換系言語なので、1進数表現で計算させると楽。 で、今回は整数を扱うので自然数の組で表現するが、そのままだと計算が進むにつれて値が爆発的に大きくなり、計算時間がかかりすぎるので 適宜正規化を施してやる必要がある。

Maybe Later (@lip_of_cygnus)

508 bytes

whenq is0{r=48s=10p=reada x=(r-(ordp[1]))+s*(r-(ordp))y=(r-(ordp[4]))+s*(r-(ordp[3]))z=(r-(ordp[7]))+s*(r-(ordp[6]))a=x+((ordp[s])-r)+s*((ordp[9])-r)b=y+((ordp[13])-r)+s*((ordp[12])-r)c=z+((ordp[16])-r)+s*((ordp[15])-r)d=x+((ordp[19])-r)+s*((ordp[18])-r)e=y+((ordp[22])-r)+s*((ordp[21])-r)f=z+((ordp[25])-r)+s*((ordp[24])-r)g=x+((ordp[28])-r)+s*((ordp[27])-r)h=y+((ordp[31])-r)+s*((ordp[30])-r)i=z+((ordp[34])-r)+s*((ordp[33])-r)j=a*e*i m=a*f*h k=b*f*g n=b*d*i l=c*d*h o=c*e*g p=m+n+o q=(j+k+l-p)/6}print q=0

ある条件を満たしたらそのコードを実行するイベント駆動型言語。今回は1つのwhen文に必要な命令を全部書けば問題なく動作した。標準入力は文字列として取得されるがord命令でその文字のコードが整数値として返されるので48を引くことで実際の値を得ることができる。四則演算が完全ではないので一旦別の変数に値を保存してから計算する必要がある。命令と変数名が区別できる限り余分なカッコやスペースを削除できるのでこんな形に。

Minus (@kuromunori)

2406 bytes

マイナスしか使えない言語。

もらとりあむ氏が過去にfor文を確立してくれているのでそれを拝借して書いた。

事前にテープにメモリをセットすることができるので、テープの201番から299番までに12を書き込んである(デフォルトの値は0)。

二ケタの数a,bの引き算をしたとき、値の正負で場合分けをしたかったがテープの(200+a-b)番に書いてある値だけプログラムを先へジャンプさせる と処理を書くことでa-bが正の時は続く12個の処理を飛ばし、負の時だけ12個の処理を実行するという場合分けが書ける。

なでしこ3 (@akouryy1)

170 bytes

JS{{{var p,q,s=0,z=9,a=(require('fs').readFileSync(0)+"").split(/\s/)
for(;z--;s-=z<3&&a[z]*(a[p=3+-~z%3]*a[q=6+(z+2)%3]-a[q-3]*a[p+3]))a[z]-=a[9+z%3]
console.log(s/6)}}}

Node.js (@kurgm)

139 bytes

for(a=(""+require("fs").readFileSync(z=v=0)).split(/\s/);z<9;)v+=(a[z]-=a[z+3])*(z++>5&&a[3+z%3]*a[t=-~z%3]-a[z%3]*a[t+3]);console.log(v/6)

1行下を引いていって、1〜3行目の行列式を3行目に関する余因子展開で計算。

OCaml (@kurgm)

185 bytes

let s=Scanf.scanf"%d %d %d ";;s(fun j k l->let q p=s(fun x y z->p(x-j)(y-k)(z-l))in q(fun a b c->q(fun d e f->q(fun g h i->Printf.printf"%d"((a*e*i+b*f*g+c*d*h-a*h*f-b*i*d-c*g*e)/6)))))

終始安全地帯にあった言語なのでもっと短くなるかもしれない。

Perl (@kurgm)

106 bytes

@z=glob`dd`;$A+=(@z[$_]-=@z[$_+3])*($_>5&&@z[++$_%3+3]*@z[++$_%3]-@z[$_%3+3]*@z[--$_%3])for 0..8;print$A/6

@taiyoslime氏が書いたのを少し短くした。1行下を引いていって、1〜3行目の行列式を3行目に関する余因子展開で計算。

PHP 7.0 (@kurgm)

165 bytes

<?php
for($x=[],$i=5;--$i;)$x=array_merge($x,fgetcsv(STDIN,9," "));for(;$i<9;)$a+=($i>5)*($x[$i]-=$x[$i+3])*($x[3-~$i%3]*$x[$t=~-$i%3]-$x[++$i%3]*$x[$t+3]);echo$a/6;

1行下を引いていって、1〜3行目の行列式を3行目に関する余因子展開で計算。

Piet (@satos___jp)

474 bytes

コード長で争うことはなさそうな位置にあったのでBefungeと同様ざっと書いた。 プログラム自体はBefungeよりも更に愚直にコピペして書いたかんじ。 (個人的には、.pngショートコーディング戦争もみてみたかったが、それはそれで闇が深そう)

PowerShell (@kuromunori)

156 bytes

$s=$Input.Split()
0..8|ForEach{$s[$_]-=$s[$_%3+9]}
echo(($s[2]*($s[4]*$s[6]-$s[7]*$s[3])+$s[1]*($s[3]*$s[8]-$s[5]*$s[6])+$s[0]*($s[7]*$s[5]-$s[4]*$s[8]))/6)

もらとりあむ氏のコードを縮めただけなので私の貢献度は2%くらい。 まぁ見たら読める。

Python 3 (@n4o847)

125 bytes

x,y,z,*s=map(int,open(0).read().split())
print(sum((s[i]-x)*((s[i-5]-y)*(s[i-1]-z)-(s[i-2]-y)*(s[i-4]-z))for i in[0,3,6])//6)

負のインデックスにアクセスできるおかげで、かなりすっきりしたコードになった。

203 bytes

read read read read + + + "%d%d" ↔
O "l" = O "k" = O "j" =
O l - z = O k - y = O j - x =
O l - Z = O k - Y = O j - X =
O l - x Y * X y * - * \ O k - z X * Z x * - * \ O j - y Z * Y z * - * \ [ + + 6 //

スタックとレジスタがある逆ポーランド記法の言語。read read read read + + + "%d%d" ↔で入力4行をつなげたものから数字2文字を検索した結果が得られる(正確には、スタックの一番上の要素として新しい配列が積まれていて、その配列の中身は12個の文字列になっている)。そこからOで1つずつpopしてレジスタのl, k, j, z, y, x, Z, Y, Xに代入していき、計算をする。

Ruby 2.5.0 (@kurgm)

65 bytes

require'matrix'
p Matrix[*$<.map{|l|eval"a=1,"+l.split*?,}].det/6

ライブラリがあるのが強いよねという話を会場で小耳に挟んだのでそれをヒントにした。

$<.mapで入力を1行ずつ処理する。l.splitで空白で区切って(この時点ではStringの配列)、?,","と同じ)で連結(*)して、a=1,とつなげてevalするとFixnumの配列が得られる(a=は文法上必要なだけで、a自体は使わない)。入力の3x4行列の左に[1, 1, 1, 1]の転置をつなげた4x4行列の行列式÷6を出力する。

Ruby 0.49 (@kcz146)

136 bytes

print(system2("bash -c 'a=(`cat`)
for((;z<9;)){
$[a[t=z]-=a[9+t++%3],s+=z/6*a[z++]*(a[p=t++%3+3]*a[t%=3]-a[t+3]*a[p-3])/6]
}
echo $s'"))

Rust (@kurgm)

233 bytes

use std::io::*;fn main(){let mut b=[0;36];stdin().read(&mut b);let mut m=[0;12];print!("{}",(0..12).fold(0,|x,i|{m[i]=b[i*3]as i32*10+b[i*3+1]as i32-m[i%3];x+i as i32/9*m[i]*(m[(i+1)%3+3]*m[(i+2)%3+6]-m[(i+1)%3+6]*m[(i+2)%3+3])})/6)}

入力を1文字ずつ読んでいく方式。1行目を2〜4行目から引いて、2〜4行目の行列式を4行目に関する余因子展開で計算。

SQLite3 (@satos___jp)

489 bytes

with a(a,b,c,d,e,f,g,h,i,j,k,l) as (
select 
substr(v,1,2) as a,
substr(v,4,2) as b,
substr(v,7,2) as c,
substr(v,10,2) as d,
substr(v,13,2) as e,
substr(v,16,2) as f,
substr(v,19,2) as g,
substr(v,22,2) as h,
substr(v,25,2) as i,
substr(v,28,2) as j,
substr(v,31,2) as k,
substr(v,34,2) as l
from i
),
b(m,n,o,p,q,r,s,t,u) as (
select 
d-a as m,
e-b as n,
f-c as o,
g-a as p,
h-b as q,
i-c as r,
j-a as s,
k-b as t,
l-c as u
from a
)
select (m*(q*u-t*r)+n*(r*s-p*u)+o*(p*t-s*q))/6 from b

SQLはチューリング完全(cf. https://qiita.com/utgwkk/items/20e887645da18e460fee )なので当然三角錐の体積が計算できる

STOP (@akouryy1)

1155 bytes

Stuck (@n4o847)

98 bytes

ssss["x:map(int,x.split())"mT"]_@;@_@;-@-@-[":_"]@["_@:_u:[_]u]0&u1&u2&u0&u2&u1&[T"]**@**-":]++6/F

スタック言語だが Python を eval できるのでずるい。

2次元配列の転置ができるのが面白い。

最後の F は int への変換用だが、実はドキュメントに載っていない。

2日目に出して以降放置なので、まだ改善の余地はありそう。

Swift (@lip_of_cygnus)

216 bytes

var x:[Int]=[]
for _ in 0..<4{x+=readLine()!.characters.split{$0==" "}.map{Int(String($0))!}}
for i in 0..<9{x[i]-=x[9+i%3]}
print((x[0]*(x[5]*x[7]-x[4]*x[8])+x[1]*(x[3]*x[8]-x[5]*x[6])+x[2]*(x[4]*x[6]-x[3]*x[7]))/6)

@moratorium08氏のコードを添字部分について改良しただけです。2つ目のfor文で工夫をしてprint命令に10以上の数字が出ないようにしています。

Taxi (@kuromunori)

9751 bytes

私の中のクソ言語オブザイヤー

変数が乗客であり、地名が関数に対応。 タクシーを運転することで変数を地名から地名へ運び計算を進める。

クソポイント1

タクシーなので一度に乗客は3人までしか運べない。 その他はNarrow Path Parkとかスタックに対応する地名などへ待機

クソポイント2

タクシーなのでガソリンがなくなると止まる。 乗客を目的地へ連れていくと運賃がもらえるので、定期的にガソリンスタンドへより給油が必要。

クソポイント3

タクシーなので道案内が必要。 地名から地名へ移動するとき、西へ行き1つ目の角を右へ、3つ目の角を左へ…と道案内がいる。 公式に地図があるのでそれとにらめっこし道案内する。クソ。

クソポイント4

タクシーなのでエラーメッセージもそういう仕様。 ”そんな地名はありません”、”その方向には曲がれません”、”乗客が多すぎます”、”車庫に車が戻っていません、あなたはクビになりました” エラーメッセージが終始こんなん。 恐ろしいことにソースコードの何行目でエラーが起きてるかも教えてくれない。

Unlambda (@satos___jp)

36027 bytes

今回のコードゴルフのために用意しておいた( http://satos.hatenablog.jp/entry/2018/04/23/235547 )ので容易に取ることができた。

今回のコンパイル元はこれ

	 (z. ri. ad. sb. ml. (a1. a2. a3. b1. b2. b3. c1. c2. c3. d1. d2. d3. 
	 	(p1. p2. p3. q1. q2. q3. r1. r2. r3.
		 	$print_int 
		 		(($divmod (ad (ad 
		 			(sb (ml (ml p1 q2) r3) (ml (ml p1 q3) r2))
		 			(sb (ml (ml p2 q3) r1) (ml (ml p2 q1) r3)))
		 			(sb (ml (ml p3 q1) r2) (ml (ml p3 q2) r1))
		 		) *6) (a. b. a))
	 	) (sb b1 a1) (sb b2 a2) (sb b3 a3) (sb c1 a1) (sb c2 a2) (sb c3 a3) (sb d1 a1) (sb d2 a2) (sb d3 a3)
	 ) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z) (ri z)) *0 $read_int $add $sub $mult

193 bytes

module m;integer X[0:11],v,s;initial begin
for(v=0;$fscanf(1<<31,"%d",X[v]);v+=1)X[v-3]-=X[v];s=0;for(v=11;v>2;v-=3)s+=X[v-5]*(X[v%9]*X[(v+2)%9]-X[(v-1)%9]*X[(v+3)%9]);$write(s/6);end
endmodule

1行下を引いていって,1〜3行目の行列式を1列目に関する余因子展開で計算。最初v[-3]v[-1]に代入してるけどなぜかエラー出ないんだよな……?

Vim (@lip_of_cygnus)

183 bytes

00000000  56 47 4a 3a 6c 65 74 20  6c 3d 6d 61 70 28 73 70  |VGJ:let l=map(sp|
00000010  6c 69 74 28 67 65 74 6c  69 6e 65 28 31 29 2c 27  |lit(getline(1),'|
00000020  20 27 29 2c 27 73 74 72  32 6e 72 27 29 0a 3a 66  | '),'str2nr').:f|
00000030  6f 72 20 69 20 69 6e 20  72 61 6e 67 65 28 39 29  |or i in range(9)|
00000040  0a 6c 65 74 20 6c 5b 69  5d 2d 3d 6c 5b 39 2b 69  |.let l[i]-=l[9+i|
00000050  25 33 5d 0a 65 6e 64 66  6f 72 0a 63 63 12 3d 28  |%3].endfor.cc.=(|
00000060  6c 5b 38 5d 2a 28 6c 5b  31 5d 2a 6c 5b 33 5d 2d  |l[8]*(l[1]*l[3]-|
00000070  6c 5b 34 5d 2a 6c 5b 30  5d 29 2d 6c 5b 37 5d 2a  |l[4]*l[0])-l[7]*|
00000080  28 6c 5b 32 5d 2a 6c 5b  33 5d 2d 6c 5b 30 5d 2a  |(l[2]*l[3]-l[0]*|
00000090  6c 5b 35 5d 29 2b 6c 5b  36 5d 2a 28 6c 5b 34 5d  |l[5])+l[6]*(l[4]|
000000a0  2a 6c 5b 32 5d 2d 6c 5b  31 5d 2a 6c 5b 35 5d 29  |*l[2]-l[1]*l[5])|
000000b0  29 2f 36 0a 1b 5a 5a                              |)/6..ZZ|
000000b7

Swiftと同様@hakatashi氏のコードを添字部分について改良しただけです。

補足 (@hakatashi)

最初@momochiが提出したコードが

:let l=[]
:for i in range(4)
for c in split(getline(i+1),'\_s')
call add(l,str2nr(c))
endfor
call setline(i+1,'')
endfor
:for i in range(9)
let l[i+3]-=l[i%3]
endfor
:call setline(1, (l[3]*l[7]*l[11]+l[6]*l[10]*l[5]+l[9]*l[4]*l[8]-l[5]*l[7]*l[9]-l[8]*l[10]*l[3]-l[11]*l[4]*l[6])/6)
ZZ

で、<Visual>J<C-R>=などを使って自明に縮む部分があったのでロジックはそのままで数十バイトほど縮めた。安全地帯だったので適当なタイミングで打ち止めた。プロVimmerならもっと縮むはず。

wake (@satos___jp)

3408 bytes

Makeを更にシンプルにした言語。整数演算が標準ライブラリについている!!ので今回のお題も苦しむことなく書けた(僕が書いたのは最初の4行だけ)。いい言語。

1171 bytes

@kurgm 氏のコードを縮めただけ。main 部分の擬似コードは以下。

do
  ;; 差分を取るので '0'* 11 を引く必要がない
  store[$0+12]=load8[$1+4097]+load8[$1+4096]*10
  store[$0]=load[$0]-load[($0=$0+4)+8]
while ($1=$1+3)!=36

$0=56 (14*4)
;; ここで偶然 $1==36 になる

do
  $2=(
    load[$0%36+12]*load[($0-16)%36+12]
    - load[($0-=12)%36+12]*load[($0+8)%36+12]
  )*load[$1]+$2
while $1=$1-12

$2=$2/6
store[$0=5]=0
;; ここは本来 store8 だが store の方が短い

do
  store8[$0=$0-1]=$2%10+48
  $2=$2/10
while $0

return 0

Whitespace (@moratorium08)

790 bytes

    
	
		    	
	
		    	 
	
		    		
	
		    	  
	
		    	 	
	
		    		 
	
		    			
	
		    	   
	
		    	  	
	
		    	 	 
	
		    	 		
	
		    		
			    
				  	    		
 
			     	  
			    	
				  	    	  
 
			     	 	
			    	 
				  	    	 	
 
			     		 
			    
				  	    		 
 
			     			
			    	
				  	    			
 
			     	   
			    	 
				  	    	   
 
			     	  	
			    
				  	    	  	
 
			     	 	 
			    	
				  	    	 	 
 
			     	 		
			    	 
				  	    	 		
 
			     
    		
			    			
			    	 		
				  
	  
	       	  
			    	   
			    	  	
				  
	  
	       	 	
			    	 	 
			    		 
				  
	  
	       		
			    	   
			    	 	 
				  
	  
	  	    	  
			    	 		
			    		 
				  
	  
	  	    	 	
			    			
			    	  	
				  
	  
	  	    		 
	 	 	
 	




Width (@kurgm)

299 bytes

QimGwwAGGwwwmwAiimacwimGwwAGGwwwmwAiiwAfcwwfcwGfcwmfcwWfcGifcGffcGcfcGacwwAfiimwWfiGafaGcfiGiiWffwwfiimGifiGffaGafiwmiWffwGfiimwmfiGcfaGffiwWiWiWimfiAWGaGmmFimmaAWGafffWwfiWfaGaGmmFimmaAWGaiAfWwfiWGiGWmciiGaiiGaGmiimcwAGmGfwWimcAiWwfiWiWimGWmiwWGmimfwiWfFmcwWwAwmimiWfFmamiGwGamFimiWiWQwwAwZwZcwcaww

アルファベットが文字幅をもとに0〜9に対応付けられていて、0〜9が各種コマンドや制御構文などと対応付けられている言語。

これはかなりクソをやっていて、

(lambda*s:(lambda a,b,c,d,e,f,g,h,i:a*(e*i-h*f)+b*(f*g-i*d)+c*(d*h-g*e))(*[s[i+3]-s[i%3]for i in range(9)]))(*map(int,open(0).read().split()))

という文字列をpushして、Python evalしたのを6で整数除算して出力している。(安全地帯だったし最後の方にとったのでやっつけ)

220 bytes

アセンブリとは……?という感じですが。。。

  1. C言語を書きます

    #define read(fd, buf, count) __asm__ __volatile__(\
      "int $0x80"\
      : "=a" (ret)\
      : "a" (3), "b" (fd), "c" (buf), "d" (count)\
    )
    #define write(fd, buf, count) __asm__ __volatile__(\
      "int $0x80"\
      : "=a" (ret)\
      : "a" (4), "b" (fd), "c" (buf), "d" (count)\
    )
    #define exit(error_code) __asm__ __volatile__(\
      "int $0x80"\
      :\
      : "a" (1), "b" (error_code)\
    )
    
    void start() {
      int X__[15] = {0};
      int ret;
      int i = 0;
      int *X = X__ + 3;
      int s = 0;
      char buf[36];
      read(0, buf, 36);
      for (i = 0; i < 12; i++) {
        X[i - 3] -= X[i] = buf[i * 3] * 10 + buf[i * 3 + 1];
      }
      for (i -= 3; (i -= 3) > -3;) {
        s += X[i] * (
          X[(i + 7) % 9] * X[(i + 5) % 9]
          - X[(i + 4) % 9] * X[(i + 8) % 9]
        );
      }
      s /= 6;
      for (i = 5; i--; s /= 10) {
        buf[i] = '0' + s % 10;
      }
      write(1, buf, 5);
      exit(0);
    }
  2. clang -S -masm=intel -m32 -mno-sse -O1 -fno-stack-protector hoge.c でIntel構文のアセンブリにします

  3. nasmが読めるようにptrを消したり要らない情報(##から始まるコメントとか)を削ったりします

  4. アセンブリショートコーディングをします

    • たとえば割り算(と剰余)がimulとmovとshrとaddと云々を組み合わせたものに最適化されてるので素直にdivに置き換える
    • lea ecx,[ecx+4*ecx]とかはlea ecx,[5*ecx]の方が短い
    • xor ebx,ebxとかはmov ebx,0の方が短い
    • スタック領域の初期化は特にしなくても大丈夫(正しい答えが出る)っぽい……?ので消す
    • exitしなくてもSegmentation Faultで落ちてくれるのでwriteのシステムコールから後ろを消す
    • push ebpmov ebp,espのくだりも要らないので消す
    • などなど……

    それでも赤チームには届かないのでつらいなあという感情になります

  5. C言語のchar main[]="\xeb\xfe〜〜";みたいにdb`\xeb\xfe〜〜` みたいに機械語バイナリで書いてったら短いのでは?:thinking:ということに気づきます

  6. 3.で消したptrを戻してclang -masm=intel -m32 -c hoge.sでアセンブルします

  7. hoge.oから必要な部分を取り出してnon-printableな文字をエスケープしたものを得ますがそれでも赤チームには届かないのでつらいなあという感情になります

  8. というか何故か答えが変わってるので逆アセンブルして目で比較したところ4.で書き換えたlea ecx,[5*ecx]lea ecx,[8*ecx]になっていることを発見して修正します(は〜〜〜)

  9. エスケープする必要があるのはヌル文字(\0)と改行(\n)とバックスラッシュ(\\)だけだと判明して、赤チームに勝ちます

  10. バイナリショートコーディングをします

    • やっぱりmov ebx,0よりxor ebx,ebxの方が短い
    • 定数が長いのでそこをなんとかする(ebpは終始9を格納するレジスタとなった)
    • などなど……

もちろん1.から10.までストレートに進んだわけはなくて、4.でアセンブリを最適化してる途中にCのコードが間違ってることに気づき1.からやり直したり2.のオプションを変えてやり直したり、何故か答えが出る前にセグフォで落ちたり何故か入力を取る前にセグフォになったりして提出デバッグがつらかったり……

Z80 (@hakatashi)

631 bytes

アセンブリ (320行)

しんどい~~~~~~~。

乗算命令も除算命令もないうえにワードサイズが8bitなので、行列式の計算をするためにレジスタ3つの乗算器と除算器を実装する必要がある。

あと、地味に10進数の変換が辛かった⋯⋯。(前回はインターフェースが2進数だったのでだいぶ楽だったんだなあと)

サブルーチンでゴリ推したのでゴルフ的なことは何も考えてない。

ところで前回のコードゴルフ大会といいSECCONといい博多市がZ80職人みたいな扱いになってる感

⚠️ **GitHub.com Fallback** ⚠️