今更ながら、ランレングスCarelyちゃんに挑戦してみた | Dev Driven 開発・デザインチーム 今更ながら、ランレングスCarelyちゃんに挑戦してみた | 働くひとと組織の健康を創る iCARE

BLOG

今更ながら、ランレングスCarelyちゃんに挑戦してみた

2023/06/22

みなさんこんばんは、iCAREの高橋です!
突然ですが、iCAREブログを見返していたら面白い記事を見つけました。
iCARE Dev Advent Calendar 2022の第1レーン3日目
VPoEのクドウさん(@masaya_dev)が出したお題のランレングスCarelyちゃんです。

参加したいと思っていましたが、長らく忘れていたので今回勢いで始めて行こうと思います。
おぎじゅんさんが書いた記事より短くする挑戦です。

puts %w(0v 12 0un 0m 1k 0ln 0i 1s 0hn 0f 1y 0en 0d 1z 13 0cn 0b 1z 17 0an 09 1e 0i 1e 08n 07 1d 0o 1c 07n 06 1c 0s 1c 05n 05 1b 0w 1b 04n 04 1a 0z 01 1a 03n 03 1a 09 13 0e 13 0a 19 02n 03 19 0a 14 0c 14 0ln 02 19 0c 11 0g 11 0mn 01 19 0z 0in 01 19 0z 0in 01 19 0z 0in 01 18 0d 12 0g 11 0mn 01 18 0f 13 0a 12 0on 01 18 0j 17 0sn 01 18 0z 0jn 01 19 0z 02 11 0fn 01 19 0v 1e 08n 02 19 0r 1j 06n 02 19 0p 1n 04n 03 19 0n 1p 03n 03 1a 0l 1r 02n 04 1a 0k 1s 01n 05 1b 0i 1s 01n 06 1c 0g 1s 01n 06 1e 0e 1r 02n 06 1i 0b 1q 02n 05 1r 04 1n 04n 05 1s 05 1l 04n 04 1a 01 1k 05 1k 03n 03 16 09 1i 0a 14 04 17 02n 03 12 0i 1g 0k 12 02n 0z 0s).map{_1[0]*_1[1].to_i(36)+(_1[2]=='n'? "\n":'')}.join
これで一気に685byteまで縮まりました。
というわけで、いくつかのRubyの書き方を追及することにより700byteを切ることが出来ました。次なる挑戦者を求む!

ではさっそく
ふむ...685byteですか、これ以上ランレングス圧縮で短くするにはスペース無くすしかないですよね...

puts "0v120un10m1k0ln10i1s0hn10f1y0en10d1z130cn10b1z170an1091e0i1e08n1071d0o1c07n1061c0s1c05n1051b0w1b04n1041a0z011a03n1031a09130e130a1902n103190a140c140ln102190c110g110mn101190z0in101190z0in101190z0in101180d120g110mn101180f130a120on101180j170sn101180z0jn101190z02110fn101190v1e08n102190r1j06n102190p1n04n103190n1p03n1031a0l1r02n1041a0k1s01n1051b0i1s01n1061c0g1s01n1061e0e1r02n1061i0b1q02n1051r041n04n1051s051l04n1041a011k051k03n10316091i0a14041702n103120i1g0k1202n10z0s".scan(/../).map{_1=='n1'? "\n":_1[0]*_1[1].to_i(36)}.join

ということで、配列から文字列に変更し、改行コードはn1と表現して正規表現で2桁ずつ分割してスペースをなくしてみました。
これで528byteです。
157byteの削減ですが、500byte切りたい...

現状carelyちゃんが38行で表現されているので改行で使用する文字列の数は37*2で74文字使っています。
改行の文字列を削ってうまく処理させたいですね。

puts "0v120u0m1k0l0i1s0h0f1y0e0d1z130c0b1z170a091e0i1e08071d0o1c07061c0s1c05051b0w1b04041a0z011a03031a09130e130a190203190a140c140l02190c110g110m01190z0i01190z0i01190z0i01180d120g110m01180f130a120o01180j170s01180z0j01190z02110f01190v1e0802190r1j0602190p1n0403190n1p03031a0l1r02041a0k1s01051b0i1s01061c0g1s01061e0e1r02061i0b1q02051r041n04051s051l04041a011k051k030316091i0a1404170203120i1g0k12020z0s".scan(/../).map{_1[0]*_1[1].to_i(36)}.join.scan(/.{1,63}/).map{_1+"\n"}

carelyちゃんは64文字統一で表現されているの正規表現で64文字ごとに分割し、改行コードを捩じ込む力技です。
468byte!!!なんとか500byte切ることができました。
全体で217byteの削減です。

興味と勢いでやってみましたが、思っている以上に難しい挑戦でした。
ただ、Rubyリファレンスマニュアルを読み直す良い機会になりましたし、先人たちのコードを読んでとても勉強になりました。
ぜひ、ランレングス圧縮以外でも良いと思うので次なる挑戦者を求めます!!
(誰もいなければ、おぎじゅんさん添削お待ちしております)

気になる方々はぜひ先人たちの記事も読んでみてください。