packages feed

accelerate-examples-1.3.0.0: examples/smoothlife/Random/Splat.hs

{-# LANGUAGE TypeOperators #-}

module Random.Splat
  where

import Config

import Control.Monad
import System.Random.MWC
import Data.Array.Accelerate                            ( DIM2, Z(..), (:.)(..) )
import Data.Array.Accelerate.System.Random.MWC          ( (:~>) )


-- Generate a random point on the grid by checking which circles it overlaps.
--
splat :: [(DIM2, R, Bool)] -> DIM2 :~> R
splat circles ix _ =
  let overlaps          = filter (inside ix) circles
      negative (_,_,s)  = s
  in
  return $ case overlaps of
                []  -> 0
                xs  -> if negative (last xs) then 0 else 1


-- Generate some random circles with centre position somewhere inside the grid
-- and some maximum radius. The boolean represents whether life should be
-- created or destroyed inside this region.
--
randomCircles :: DIM2 -> R -> R -> IO [(DIM2, R, Bool)]
randomCircles (Z :. height :. width) radiusMin radiusMax =
  withSystemRandom . asGenIO $ \gen ->
    let
        circle  = do
          a     <- uniform gen
          r     <- uniformR (radiusMin, radiusMax) gen
          y     <- uniformR (0, height-1) gen
          x     <- uniformR (0, width-1)  gen
          return $ (Z:.y:.x, r, a)

        n       = 1 `max` round ( fromIntegral (width * height) / (radiusMax * radiusMax) )
    in
    replicateM n circle


-- Test if a point is inside the given circle, given by centre coordinate and
-- radius.
--
inside :: DIM2 -> (DIM2, R, Bool) -> Bool
inside (Z:.y:.x) (Z:.cy:.cx, r, _) =
  let
      dx        = fromIntegral $ cx - x
      dy        = fromIntegral $ cy - y
  in
  dx*dx + dy*dy <= r*r