packages feed

gruff-0.1: Address.hs

module Address where

import Control.Monad (guard)
import Data.Ratio ((%), denominator)
import Fractal.RUFF.Mandelbrot.Address (AngledInternalAddress(Unangled, Angled), Angle, angledFromList, angledToList)

import Utils (safeRead)

parseAngles :: String -> Maybe [Angle]
parseAngles = mapM parseAngle . words

parseAngle :: String -> Maybe Angle
parseAngle s = do
  let (n, d) = break ('/'==) s
  n' <- safeRead (filter (' '/=) n)
  d' <- safeRead (filter (' '/=) (drop 1 d))
  guard (0 < n' && n' < d')
  return $ n' % d'

splitAddress :: AngledInternalAddress -> Maybe (AngledInternalAddress, [Angle])
splitAddress a =
  let (ps0, rs0) = unzip $ angledToList a
      ps1 = reverse ps0
      rs1 = reverse (Nothing : init rs0)
      prs1 = zip ps1 rs1
      f ((p, Just r):qrs@((q, _):_)) acc
        | p == denominator r * q = f qrs (r : acc)
      f prs acc = g prs acc
      g prs acc =
        let (ps2, rs2) = unzip prs
            ps3 = reverse ps2
            rs3 = reverse (Nothing : init rs2)
            prs3 = zip ps3 rs3
            aa = angledFromList prs3
        in  case aa of
          Nothing -> Nothing
          Just aa' -> Just (aa', acc)
  in  f prs1 []

joinAddress :: AngledInternalAddress -> [Angle] -> AngledInternalAddress
joinAddress (Unangled p) [] = Unangled p
joinAddress (Unangled p) (r:rs) = Angled p r (joinAddress (Unangled $ p * denominator r) rs)
joinAddress (Angled p r a) rs = Angled p r (joinAddress a rs)

addressPeriod :: AngledInternalAddress -> Integer
addressPeriod (Unangled p) = p
addressPeriod (Angled _ _ a) = addressPeriod a