content: import System
  infinity = 1/0
  delta = sqrt e where e = encodeFloat (floatRadix e) (-floatDigits e)
  infixl 7 .*, *|
  data Vector = V !Double !Double !Double deriving (Show, Eq)
  s *| V x y z = V (s * x) (s * y) (s * z)
  instance Num Vector where
      V x y z + V x' y' z' = V (x + x') (y + y') (z + z')
      V x y z - V x' y' z' = V (x - x') (y - y') (z - z')
      fromInteger i = V x x x where x = fromInteger i
  V x y z .* V x' y' z' = x * x' + y * y' + z * z'
  vlength r = sqrt (r .* r)
  unitise r = 1 / vlength r *| r
  
  data Scene
      = Sphere !Vector !Double
      | Group !Vector !Double Scene Scene Scene Scene Scene
      deriving (Show)
  
  ray_sphere (V dx dy dz) (V vx vy vz) r =
    let disc = vx * vx + vy * vy + vz * vz - r * r
    in  if disc < 0 then infinity else
        let b = vx * dx + vy * dy + vz * dz
            b2 = b * b
        in  if b2 < disc then infinity else
            let disk = sqrt(b2 - disc)
                t1 = b - disk
            in  if t1 > 0 then t1 else b + disk
  
  ray_sphere' (V ox oy oz) (V dx dy dz) (V cx cy cz) r =
    let vx = cx - ox; vy = cy - oy; vz = cz - oz
        vv = vx * vx + vy * vy + vz * vz
        b = vx * dx + vy * dy + vz * dz
        disc = b * b - vv + r * r
    in  disc >= 0 && b + sqrt disc >= 0
  
  data Hit = H {l :: !Double, nv :: Vector }
  
  intersect dir@(V dx dy dz) hit s = case s of
      Sphere center@(V cx cy cz) radius ->
        let l' = ray_sphere dir center radius in
        if l' >= l hit then hit else
  	let x = l' * dx - cx
  	    y = l' * dy - cy
  	    z = l' * dz - cz
  	    il = 1 / sqrt(x * x + y * y + z * z)
  	in  H {l = l', nv = V (il * x) (il * y) (il * z) }
      Group center radius a b c d e ->
        let l' = ray_sphere dir center radius in
        if l' >= l hit then hit else
  	let f h s = intersect dir h s in
  	f (f (f (f (f hit a) b) c) d) e
  
  intersect' orig dir s = case s of
      Sphere center radius -> ray_sphere' orig dir center radius
      Group center radius a b c d e ->
        let f s = intersect' orig dir s in
        ray_sphere' orig dir center radius && (f a || f b || f c || f d || f e)
  
  neg_light = unitise (V 1 3 (-2))
  
  ray_trace dir scene =
    let hit = intersect dir (H infinity 0) scene in
    if l hit == infinity then 0 else
      let n = nv hit in
      let g = n .* neg_light in
      if g < 0 then 0 else
        if intersect' (l hit *| dir + delta *| n) neg_light scene then 0 else g
  
  fold5 f x a b c d e = f (f (f (f (f x a) b) c) d) e
  
  create level c r =
    let obj = Sphere c r in
    if level == 1 then obj else
      let a = 3 * r / sqrt 12 in
      let bound (c, r) s = case s of
  	 Sphere c' r' -> (c, max r (vlength (c - c') + r'))
           Group _ _ v w x y z -> fold5 bound (c, r) v w x y z in
      let aux x' z' = create (level - 1 :: Int) (c + V x' a z') (0.5 * r) in
      let w = aux (-a) (-a); x = aux a (-a) in
      let y = aux (-a) a; z = aux a a in
      let (c1, r1) = fold5 bound (c + V 0 r 0, 0) obj w x y z in
      Group c1 r1 obj w x y z
  
  ss = 4
  pixel_vals n scene y x = sum
    [ let f a da = a - n / 2 + da / ss; d = unitise (V (f x dx) (f y dy) n)
      in  ray_trace d scene | dx <- [0..ss-1], dy <- [0..ss-1] ]
  main = do 
      [level,ni] <- fmap (map read) getArgs
      let n = fromIntegral ni
  	scene = create level (V 0 (-1) 4) 1  
  	scale x = 0.5 + 255 * x / (ss*ss)
  	picture = [ toEnum $ truncate $ scale $ pixel_vals n scene y x | y <- [n-1,n-2..0], x <- [0..n-1]]
      putStrLn $ "P5\n" ++ show ni ++ " " ++ show ni ++ "\n255\n" ++ picture
  