Rubyでコードゴルフ:ぐるぐる渦巻き【解説】
本稿はCodeIQで2013年5月28日~2013年6月10日に出題された「コードゴルフ:ぐるぐる渦巻き」という問題の解法に関する記事です。
Rubyでコードゴルフ:ぐるぐる渦巻き【解説】
◆注意
本問は「ショートコーディング」・「コードゴルフ」と呼ばれる、ソースコードをできるだけ短く書く遊びの一環として出題されたものですので、一般的なプログラミング解説とは少し異なります。
◆How to ぐるぐる
これぞスクリプト言語という、ぐるぐるメソッドがあります。
・3×3の場合の具体例
まず、1からスタートして、サイズ1の配列を作ります。
[1]
次に、これと同じサイズの行列を作り、中には2を入れます。
[ [2], [1] ]
のような状態を作るということです。これに対してtransposeを使うと、
[ [2, 1] ]
のようになります。なんだよflattenと一緒じゃないかーと言わないでくださいね。もう少し進めば意味は分かります。配列の長さが2になりましたので、今度は長さが2の配列を用意して、3と4を入れます。
[ [3, 4], [2, 1] ]
行列風に書くと、
3 4 2 1
ちょっとぐるっとしました。ここで、Array.transposeを発動します。
[ [3, 2], [4, 1] ]
さらに2つの配列を逆順にすると、
[ [ 4, 1], [3, 2] ] 4 1 3 2
それっぽくなりました。
それぞれの配列は、まだ長さが2のままですので、さらに長さ2の配列を作り、5と6を加えます。
[ [5, 6], [4, 1], [3, 2] ]
これをtransposeして、順序を逆にすれば、
[ [6, 1, 2], [5, 4, 3] ]
6 1 2 5 4 3
のようになります。もう出来上がりが見えてきましたね。ここで配列のサイズが3になりましたので、今度はサイズ3の配列を作り、7と8と9を入れます。
[ [7, 8, 9], [6, 1, 2], [5, 4, 3] ]
これで、目的の形になりました!
7 8 9 6 1 2 5 4 3
transposeとreverseを使いながら、文字通りぐるぐるしていくわけです。
◆上位ショートコーダーの超短いコード
- 1位 Muさん(107B)
n=gets.to_i**2;v,*a=0;a=[a.map{"%#{n.to_s.size}d"%v+=1}]+a.transpose.reverse while v<n;puts a.map{|l|l*' '}
- 2位 tompngさん(108B)
n=gets.to_i/2 a=-n..n a.map{|y|puts a.map{|x|"%#{4-21/(n+6)}d".%2*[2*y*y-y,2*x*x-x-z=(x-y).abs].max-~z}*' '}
- 3位 tomwotさん(111B)
y=[];z=0;(2*n=gets.to_i).times{y=[y.map{z+=1}]+y.transpose.reverse};puts y.map{|w|["%#{z.to_s.size}d"]*n*' '%w}
- 4位 UGさん(113B)
n,*m=eval *$< eval"m=[[*$....$.+=m.size]]+m.transpose.reverse;"*n*2 puts m.map{|r|["%#{"#{n*n}".size}d"]*n*" "%r}
- 5位 antimon2さん(116B)
puts (a=0...n=gets.to_i).map{|y|a.map{|x|d=y-x;"%#{"#{n*n}".size}d"%[x,y].sort.map{|w|1-(m=w*2-n)*~m+d=-d}.max}*' '}
◆全体順位表
1位: Mu (107)B 2位: tompng (108)B 3位: tomwot (111)B 4位: UG (113)B 5位: antimon2 (116)B 6位: UTO, iehn (117)B 7位: hoi (118)B 8位: Azicore (119)B 9位: mad_p (121)B 10位: hogeover30 (122)B ーーーーー 上級の壁(125B) ーーーーー 11位: th (127)B 12位: rotary-o, ayuzak (129)B 13位: autotaker (131)B 14位: siman (132)B 15位: ushsh (133)B 16位: robert, ttakuru88 (137)B 17位: whiteleaf (138)B 18位: uru (139)B 19位: しかく (143)B 20位: saidie, hm001 (147)B ーーーーー 中級の壁(150B) ーーーーー 21位: climpet 22位: hogehoge-codeiq 23位: ciel 24位: nishioi 25位: niwatoriheart 26位: hirokazu1020 27位: じゃい 28位: pavlocat 29位: RLD 30位: ysk_univ 31位: Mahito 32位: tmtms 33位: setaria 34位: れこ 35位: manozo 36位: okura3 37位: masatanish 38位: facil89 39位: わだこ 40位: moneymog 41位: ricca 42位: ぺこ 43位: tokyoster 44位: tossy 45位: TONY0922
※敬称略
◆もっと短くできるか?
今回1位は107バイトでしたが、もっと短くすることは可能です。上位のコードをよくよく見返すだけで、少なくとも104バイトまでは縮められるはずです。もちろん、もっと縮める方法もあるかもしれませんので、色々と研究してみてくださいね。