こんにちは!面白プロデュース事業部のおばらです。
本記事では JavaScript のコードゴルフ大会『JS体操』の全5問を、作問の裏話とあわせて振り返ってみよう思います!
目次
『JS体操とは』
『JS体操』とはカヤックが主催する JavaScript のコードゴルフ大会です。
もともとは社内の勉強会として始めた施策です。
その詳細は以下のブログ記事を御覧ください!
第1回「波形の整形」
【問題】https://hubspot.kayac.com/js-taiso-001
【解説】https://techblog.kayac.com/js-taiso-001-commentary-vol1
作問の裏話
記念すべき第1弾!
最初の問題を何にするか、とても迷いました。
運営チームでいくつか問題の候補を出して議論し、問題の意図が見た目にもわかりやすい&過去に似たような事例が少ないということで、グラフを描画する問題にしました。
グラフの形状はいろんなものを試しましたが、グラフの形が面白く、かつコードゴルフのしがいがあるもの、という観点でセレクトしました。
最短文字数の回答
なんと44文字まで縮められます!
export default x=>x-(x%=.2)+.2-(.04-x*x)**.5
以下の5名の方がみごと達成されました!
- halwhite さん
- koyama41 さん
- sugyan さん
- tkihira さん
- たつけん さん
面白いコード
ここで tkihira さんのとても面白いアプローチの回答をご紹介します。
let r=0;export default x=>r+=x%.2/(1-(5*x%1)**2)**.5/2e5
どういうロジックか、わかりますか?
円の式を微分して、、、微小なΔx分を足していって、、、
こんなアプローチは全く思いつきませんでした。あっぱれです。
赤い点線からちょっとズレているのが御愛嬌ですね!
王道の回答以外にもいろいろ楽しんでいただけるのは出題者としても嬉しいです!
第2問
【問題】https://hubspot.kayac.com/js-taiso-002
【解説①】https://techblog.kayac.com/js-taiso-002-commentary-vol1
【解説②】https://techblog.kayac.com/js-taiso-002-commentary-vol2
作問の裏話
もともとは「縦横比」のような概念、無次元の概念を導入するとロジックをシンプルにできる!という社内勉強会用のデモでしたが、そこからとんでもないハックが可能な賛否両論の問題になってしまいました。
最短文字数の回答
真面目なアプローチだと66文字!
export default(a,b,f=e=>e.naturalWidth/e.naturalHeight)=>f(a)-f(b)
以下の2名のみなさん、CONGRATULATIONS♪
- 🥇 ぺち さん
- 🥇 halwhite さん
デフォルト引数の仕組みを利用するのがポイントですね!
鬼コード
export default()=>9e9<<length+++9
ハック部門では上記コードも想定していましたが、ちょっとやりすぎました。反省。。
第3問
【問題】https://hubspot.kayac.com/js-taiso-003
【ヒント①】https://techblog.kayac.com/generating-zalgo-text
【ヒント②】https://techblog.kayac.com/unicode-code-point-vs-code-unit
【ヒント③】https://techblog.kayac.com/12-ways-to-convert-sparse-array-to-dense-array-on-the-fly
【ヒント④】https://techblog.kayac.com/22-ways-to-generate-strings-from-code-points
【解説①】https://techblog.kayac.com/js-taiso-003-extension-match-announcement
【解説②】https://techblog.kayac.com/js-taiso-003-commentary-vol1
作問の裏話
Unicode について調べているときに思いついた問題です。こういうテキストを Zalgo Text と呼ぶこともこのとき初めて知りました。
最短文字数の回答
3連覇の halwhite さんのおかげで以下まで短くできることが判明しました!
export default(s,r=Math.random)=>s.replace(/./g,c=>(s=n=>~--n?s(n)+String.fromCharCode(768+r()*112):c)(r()*8))
面白いコード
export default s=>s.replace(/./g,c=>c+eval(`''`+`+eval('"\\\\'+'u{'+(768+s()*112|0).toString(16)+'}"')`.repeat(1+(s=Math.random)()*8)))
社内の QA で生まれた、eval()
を2重に使うトンデモ激重コードです。そして文字数はむしろ長くなってますね。テストに本当にものすごく時間がかかるのでお試しいただく際は要注意。
第4問
【問題】https://hubspot.kayac.com/js-taiso-004
【解説】https://techblog.kayac.com/js-taiso-004-commentary
作問の裏話
社内では、
- 安定ソート版
- 安定じゃないソート版
の2種類のセットで出した問題でした。
それぞれでロジックも変わってくるので面白いです。もし興味のある方はぜひお試しあれ。
最短文字数の回答
1位は ksk1015 さんの109文字でした!予想外のロジック、さすが過ぎます。
export default s=>'くしつのへいうこてとひめりるろんあえかけさすせそちにみもやゆよられわおきたぬねはふまむをなほ'.replace(/./g,c=>[...s.matchAll(c)].join``)
第5問
【問題】https://hubspot.kayac.com/js-taiso-005
【解説】https://techblog.kayac.com/js-taiso-005-commentary
作問の裏話
社内向けのバージョンでは、フリー素材と化している弊社 CBO の写真を AA にする問題でした。
Zalgo Text と AA を組み合わせる案なんてのもありました。薄いピクセルはダイアクリティカルマークを少なく、濃いピクセルはダイアクリティカルマークを多くする、という具合です。
その後、YAPC:Hakodate 2024 開催にあわせた問題にすることが決まり、
- 北海道の地図
- 北海道の特産物の写真
- 「北海道」という漢字
などいろいろ考えた結果 YAPC とカヤックのロゴでいくことにしました。
最短文字数の回答
export default(t,W=128,c=new OffscreenCanvas(W,W).getContext`2d`)=>c.getImageData(~~c.drawImage(t,0,0,W,64),0,W,64).data.reduce((a,p,i)=>a+=i%4?~i%512?'':` `:'#`'[p>>7],'')
面白い回答
いろいろ遊べるようにあえて非同期の処理も可能にしていたのですが、さすが halwhite さん、見逃しませんね笑
とてもスマートな回答です!
export default(b,t=document.createElement`canvas`.getContext`2d`)=>fetch(`test-cases/${t.drawImage(b,0,0),t.getImageData(8,32,1,1).data[0]?'kaya':'yap'}c.txt`).then(r=>r.text()
おまけ
ついでに『JS体操』マスコットキャラクターたちの紹介もしておきます!
お察しの通り、JavaScript で使用する演算子・記号類をキャラクター化したもの。跳び箱などの小物も実は作ってました。笑
3Dモデルは Blender で作成しています!
まとめ
さて、第1問〜第5問までを振り返ってみましたがいかがだったでしょうか?これで『JS体操』の施策は一旦区切りとなります。
問題を作るにあたって JavaScript の言語仕様を学び直したことで私自身とても勉強になりました。オライリーのサイ本第7版を読みながら、あ!これは問題にできそう、みたいなこともありました。業務でハマった経験を問題にすることもありました。そしてなにより挑戦者のみなさんが予想もしていなかったアプローチの回答で想定文字数を超えてくださるのがとても楽しく嬉しかったです。
最近では生の JavaScript を書く機会、細かいロジックを考える機会もなかなか減っているかもしれませんが、こういった形でコードゴルフという形で楽しむのも良いかもしれません。
『JS体操』は一旦終わりですが、社内勉強会用に作った問題は60問以上あるので、いつかまた再開するかもしれません。
なお、過去の問題に関してはいつでも挑戦可能ですので、まだやっていなかったという方は以下よりぜひ!
サポートいただいたたくさんの皆様ありがとうございました!
それではまた!!