格子点の列挙(Ruby)

格子点の列挙 - みずぴー日記
ここの問題で遊んでみました。

問題を再掲しておきます。

二次元平面上の格子点(X,Y座標がともに整数の点)を、原点から近い順に列挙してください。

同じ距離の点はどういう順番でも構いませんが、可能であればX軸に一番近い第一象限の点から原点を中心として反時計回りの順に列挙してください。 列挙の方法は、1行に一つの点の、X,Y座標を出力することとします。

http://d.hatena.ne.jp/mzp/20071006/lattice

 
結果の例(括弧をつけた出力にしました)。

( 3, -2)
(-6,  1)
(-5,  4)
( 4, -5)
( 5, -7)
(-9, -2)
(-2, -9)
( 7,  7)
(-8,  8)
( 8, -9)

 
コード。

class Complex
  include Comparable
  
  def <=>(a)
    f = ->(θ) {(θ < 0) ? 2 * Math::PI + θ : θ}
    
    l1, l2 = abs2, a.abs2
    θ1, θ2 = f.(angle), f.(a.angle)
    
    if    l1 > l2 then  1
    elsif l1 < l2 then -1
    elsif θ1 > θ2 then  1
    elsif θ1 < θ2 then -1
    else 0
    end
  end
  
  def to_s
    sprintf "(% 2d, % 2d)", real, imaginary
  end
end

ar = 10.times.with_object([]) {|_, x| x << Complex(rand(-9..9), rand(-9..9))}
puts ar.sort

いわゆる「宇宙船演算子」(<=>というやつ)を Complex クラスに定義して解いてみました。並べ替えはふつうに Array#sort でやっています。

ちょっとトリッキーですかね。