CodeIQで、「Minority's hello, world」という問題が出題されて、それに回答してみました。
問題
「hello, world」と出力するプログラムを提出して下さい。
提出されたプログラムで使われている文字を、全挑戦者について集計します。
各文字には「(その文字を利用した挑戦者の人数)の2乗」というポイントが割り当てられます。
提出されたプログラムのポイントは、そのプログラムで使われている文字のポイントの合計となります。
提出コードのポイントが少ない順に順位をつけます。最小ポイントの方が優勝です。
詳細
細かいレギュレーションとして、
*コードに書ける文字はASCIIの32〜126のみ、改行やタブ、漢字などは使用不可
*出力は標準出力へ、エラー出力は不可
*出力は「hello, world」もしくは「hello, world(改行)」のどちらか(表記ゆれ、間違いに注意)
というようなことがありました。
自分の回答
自分は、Rubyで回答してみることにしました。戦略としては、多くの人が使いそうな文字を避ける、ということが重要になるので、その辺りを考えて書くことにしました。
1回め
%@4`1`8`8`B`5K`58`J`B`E`8`0@.split(?`).map{|q|putc(q.to_i(36)+100)}
まずは、二重引用符や角カッコを避けるために、文字列を%記法で表現して、しかも区切り文字には他の言語でも現れなさそうな@を使っています。そして、これまた出番の少なそうなバッククオートでsplitすることで、36進法の文字列配列を生成します。ここでも?+1文字という、あまり見慣れない文字列リテラルとして引用符を避けています。
あとは配列ごとに36進法から10進法に戻して、ASCIIコード指定でputc
させるだけですが、eを使わないためにeach
ではなくmap
としています(何かが生成されますが、出力されないので無視できます)。
とりあえずはこれでそこそこ上に来たのですが、しばらくすると半分を超えるほど順位が低迷して来ました。で、やはり長いということに気づいて、コードの短さも意識して再作成してみることにしました。
2回め(最終形)
$><<%W@68656C6C6F2C20776F726C64@.pack(%@H*@)
だいぶ長さが縮みました。まずは$>
が標準出力で、それに<<
することで出力を行います。その次はまたも%記法ですが、%W@...@
では、中身を文字列にした配列を生成します。この状況で変数展開は不要なのですが、wは出力文字列中にあるので回避して大文字としています。
で、お題の文字列を16進で表した文字列1つの入った配列ができますが、それをpackでデコードします(この関数自体が暗号みたいですね)。これまたしつこく%記法で引用符を回避しています。
全体にコードは短くなって、英小文字もpackの4つだけになりました。
結果発表
途中経過も追いかけていたのですが、最終結果としては11位(Rubyトップ)となりました。トップに来た戦略の「文字列のxor」は薄々思いついてはいたのですが、Rubyでできないために放置していました。
他の人が繰り出す技で気になったものが、
- PHPの関数名は大文字小文字を問わないのを利用
- PHPに入らず、そのまま
hello, world
だけ書く - どう考えても、この勝負に向かなさそうなJavaであえて挑戦する姿勢
などです。