GOTO M.

趣味のコーディングとか、勉強とか、読書とか

Code golf 反省メモ(海のダンジョン)(JavaScript)

挑戦した問題

codeiq.jp

要約

以下のような形式で、3艘の”船”の性能が与えられる。3艘のうち性能÷定員の値が最大のもののindex(0~2)を求める。ただし、性能・定員のいずれかが3以下のものは最低値として扱う。

ほぼ文字制限の無いレベル1と、いくつかの文字列が禁止されたレベル2が有るが、今回はレベル1の方の反省。

q=[
    [ 3, 19],  // 0艘目の船 [船の性能, 定員]
    [ 5, 17],  // 1艘目の船 [船の性能, 定員]
    [13,  7]   // 2艘目の船 [船の性能, 定員]
  ];

なお、こちらで実際にコードを試してみることもできます。

ソースコード

自分の解答(61)(※1位の方との比較のため変数名は変えています)

j=i=0;for(t of q)t[0]>3&t[1]>3&(k=t[0]/t[1])>i&&(r=j,i=k),j++
  • 3艘の船についてループ処理を行う都度、性能÷定員が最大の船のindexをrに、その船の性能÷定員をiに格納しています。この2つの変数の宣言などが無駄に感じます。

1位の方(rotary-o様)の解答(53)の吟味

for(j=3;a=q[--j];3%a%b<3|a/b<i||(i=a/b,r=j))b=a.pop()
配列要素の取り出し方

まず気が付くのは、私のコードでいt[0],t[1]とかなりの文字数を使っている部分が、a,bと、すっきりした表現にできている点です。単純にやると逆に長くなってしまうこの辺りの処理が、JavaScriptの特性(意外と色々なものが数値として扱える)を活用してかなり短縮して書かれています。

a=t[0],b=t[1]  //単純に代入するケース
b=a.pop()      //rotary-o様の方法
[a,b]=t        //蛇足ですが、EcmaScript6(Firefoxなど)だとこう書けてかなり楽です。
暫定トップを保持する変数(i)の宣言

次に目に付くのは、私のコードでのc=0に相当する処理がrotary-o様のコードには無いことです。
今回の問題では1艘目の船を確定暫定トップにしてしまって良いことと、ユーザ入力部分の外で変数iが宣言のみされていることを考えると、iがnullの場合には暫定トップの更新処理(i=a/b,r=j部分)を行うような処理を行ってしまってよいことが利用できます。
i=nullの場合に更新処理を行いたいがために、rotary-o様のコードでは各種の条件が&や&&でなく|や||で接続されています。

ループの方法

ぱっと見一番大きいのがループの方法の違いです。私はfor ~ ofを使用しているのに対し、rotary-o様は通常のfor文を使用されています。なんとなく前者の方が大体短く出来る気がしており、ほぼ盲目的にこちらを使っていました。
現に、私のコードを単純に通常のfor文に置き換えると1文字増えてしまいます。

// for .. of 文
j=i=0;for(t of q)t[0]>3&t[1]>3&(k=t[0]/t[1])>i&&(r=j,i=k),j++
// 通常のfor文(こっちが1文字長い)
i=0;for(j=3;t=q[--j];)t[0]>3&t[1]>3&(a=t[0]/t[1])>i&&(r=j,i=a)

一方で、rotary-o様のコードの場合は逆にfor ~ ofの方がコードが長くなってしまうようです。

// for .. of 文
j=0;for(a of q)b=a.pop(),3%a%b<3|a/b<i||(i=a/b,r=j),j++
// 通常のfor文(こっちが2文字短い)
for(j=3;a=q[--j];3%a%b<3|a/b<i||(i=a/b,r=j))b=a.pop()

この3文字の差(-1文字vs+2文字)は以下から来ています。

  • 私コードでは、ループごとに実行される処理が1つのみなのに対し、rotary-o様版は2処理に分割できるがために、final-expression(for(xx;xx;ここ))に一方を入れることで1文字節約されています。(逆に言うと、for ~ ofだと余計なカンマが増えてしまいます)
  • 私のコードではfor文の外で変数cを初期化せざるを得ないがために、逆にi=0をfor文の外に出すコストはi=の2文字に過ぎません。一方で、rotary-o様版だとj=0;の4文字が必要となってしまいます。これで2文字の差です。
その他
  • 3%a%b<3部分の書き方も、(文字数は減らないものの)うまい書き方なので吸収したいです。

今後の Code golf に向けた反省

  • 変数の宣言を減らせないか検討すること。(今回でいうi)この際、null変数などが利用出来ないか吟味すること。
  • JavaScriptについては、意外なものが数値(や他の基本型)として扱えることが有るので、入念に検討すること。
  • 処理の形を変える度に、for ~ of通常のfor文のどちらを用いるのが適切か検討すること。
    • ループ内の処理が2式以上の場合や、ループ変数の宣言が高価な場合は通常のfor文を用いた方が良い場合がある。