### -

Kind of messy and verbose, but good enough

``````import Data.List

-- Note, for the sake of definition, the center point is a 1D ring

-- Given a ring index, returns the max value in that ring
getRingMax :: Int -> Int
getRingMax = (^ 2) . (1 +) . (2 *)

-- Given a ring index, returns the min value in that ring
getRingMin :: Int -> Int
getRingMin 0 = 1
getRingMin n = 1 + (getRingMax \$ n - 1)

-- Given a value, returns the distance from its ring's midpoints to the center
getNormalDistance :: Int -> Int
getNormalDistance n = dist
where mins = map getRingMin [0..]
next = findIndex (\y -> y > n) mins
dist = case next of
Just a  -> a - 1 -- a represents the next rings index, and we want this rings index
Nothing -> error "Oh geeze how did you mess up this bad? This shouldn't be possible"

-- Given a value, returns the midpoints of its ring
getRingMidpoints :: Int -> [Int]
getRingMidpoints n = [bottom, left, top, right]
where dist       = getNormalDistance n
maxRingVal = getRingMax dist
sideLength = 2 * dist + 1
subtrahend = sideLength - 1
bottom     = (-) maxRingVal \$ div subtrahend 2
left       = (-) bottom subtrahend
top        = (-) left subtrahend
right      = (-) top subtrahend

-- Given a value, returns the distance to its ring's nearest midpoint
getTangentDistance n = minDist
where midpoints = getRingMidpoints n
distances = map (abs . (-) n) midpoints
minDist   = minimum distances

-- Given a value, returns the manhattan distance to the center
getDistance :: Int -> Int
getDistance n = getTangentDistance n + getNormalDistance n

main = do