GOTO M.

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

『第8回デスマコロシアム』答案

CodeIQ『第8回デスマコロシアム』(※)に参戦しました。
※以下を特徴とするコードゴルフ大会です。

  • ideoneで使用可能な言語なら何でもOK。
  • 有利な言語に偏りすぎないよう、参戦人数の多い言語にはハンディあり。
  • バイト数でなく、文字数で競う。
  • import文は文字数カウント対象外、ideoneの自動生成部分もカウント対象外。(本稿のコードも、自動生成部分は略記しています)

第7回出題テーマは、以下の文字マトリクスの標準出力への出力です。(最終行後の改行は有っても無くても可)

BAAAAAAAAAAAAAAAAAAAAAAAA
ACAAAAAAAAAAAAAAAAAAAAAAA
AADAAAAAAAAAAAAAAAAAAAAAA
AAAEAAAAAAAAAAAAAAAAAAAAA
        ~中略~
AAAAAAAAAAAAAAAAAAAAAAAYA
AAAAAAAAAAAAAAAAAAAAAAAAZ

せっかくなので、これまで自分がデスマコロシアムでは使わなかった言語縛りで挑戦してみました。最終結果の最短とタイor短縮できているもののみ以下に挙げます。
前回(第7回)も色々な言語で挑戦しましたが、まだまだ残っていますね…第9回はどうしよう)

Factor(107)

USING: sequences.repeating sequences strings math.ranges grouping ; !出題規則によりこの行は文字数のカウント外
66 90 [a,b] [ "" 1sequence ] map [ 65 ] 25 repeated join 25 group [ 10 ] join [ 1string ] map "" join print
  • 「連鎖性プログラミング言語」と呼ばれるやや特殊な言語です。関数の入出力は全てスタックに格納され、全体的にいわゆる逆ポーランド記法っぽいプログラミングとなります。
  • ざっくりコードの説明をすると以下の通りです。
    1. 66 90 [a,b] までで、66~90('B'~'Z'のASCIIコード)の配列を準備します。
    2. [ "" 1sequence ] map で、上記配列の各要素を、1要素ずつ更に配列に包みます。(こうしないとstep.4でエラーとなるので手探りで…きっともっと良い方法が有るのだと思います)
    3. 一方 [ 65 ] 25 repeated で65('A'のASCIIコード)を25回繰り返した配列をスタックに積んでおきます。
    4. 現在スタックに 2と3の結果が乗っているので join により、2の配列の各要素の間に3の配列を挟み込みます。(Pythonなどの普通の"join"のイメージ)
    5. 25 group で、配列を25要素ずつに区切ったうえで更に [ 10 ] join 10(改行のASCIIコード)を挟み込みます。
    6. [ 1string ] map が他の言語で言う"char()"のような操作です。整数値の配列をそれぞれASCIIコードとして解釈して、文字の配列に変換します。
    7. 最後にまた "" join で文字の配列を1つの文字列に結合し、 print で標準出力に吐き出します。
  • "matrices"というボキャブラリも存在するようなのですが、普通に検索で出てくくるリファレンスとideoneのバージョンが違うのかうまく動かず断念。格好悪いコードになってしまいました。。。

Java7(60)(※これだけ、新挑戦言語ではない)

import static java.lang.System.out; #出題規則によりこの行は文字数のカウント外
for(int i=0;i<651;)out.write(i++%27<1?66+i/27:i%26<1?10:65);
  • 最短も60文字ということなので、同じようなコードに辿りついているのかな。気になります。

JavaScript(SpiderMonkey)(76)

r="";for(i=649;i;)r+=String.fromCharCode(i--%26?i%27?65:90-i/27:10);print(r)
  • 標準出力に吐くたびに改行が入ってしまうため変数に結果全体を格納することとなり、1文字ずつ出力のこの方針とは相性が悪い言語ですね。

Pike(55)

import Stdio.stdout; #出題規則によりこの行は文字数のカウント外
for(int i=649;i;)write("%c",i--%26?i%27?65:90-i/27:10);
  • コードは普通にコードゴルフっぽく、1文字1文字をうまいこと出力してやる方針です。
  • Java/javascriptと似た構文で少し短く書ける一方で、Scala/Groovyよりマイナーな言語なので重複ペナルティも避けられてよいかも。ただしjavaでいう"System.out.write"のように、整数値をそのまま文字として出力できるメソッドが無い(見付けられてないだけ?)点が惜しいです。

R(39)

cat(intToUtf8(rbind(diag(1:25)+65,10)))
  • ざっくりコードの説明をすると以下の通りです。
    1. diag(1:25)+65 までで、対角成分が'B'~'Z'、その他成分が'A'(のASCIIコード)となる配列を作成します。
    2. rbind( ... ,10) までで、上記の行列の各行に10(=改行のASCIIコード)を結合します。
    3. intToUtf8 によりASCIIコード行列を文字列に変換しますが、そのままだとクォーテーションなどまで表示されてしまうので、cat で表示しています。
  • Octaveと異なり行列の出力時に自動的に行ごとの改行が入らないので、手動で改行を入れてやる必要があります。またOctaveなら"char"で済むところ"intToUtf8"を使う必要があり歯痒い感じです。