カメヲラボ

主にプログラミングとお勉強全般について書いてます

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バイトまでは縮められるはずです。もちろん、もっと縮める方法もあるかもしれませんので、色々と研究してみてくださいね。