packages feed

scroll-1.20151219: World.hs

{-# LANGUAGE RankNTypes #-}

module World where

import Control.Monad.ST
import Control.Monad.State.Strict
import qualified Data.Vector.Mutable as MV
import Control.Applicative
import Prelude

import Types

worldWidth :: M Int
worldWidth = withWorld $ \w ->
	MV.length <$> MV.read w 0

worldHeight :: M Int
worldHeight = withWorld (return . MV.length)

mapWorld :: (Pos -> Char -> M (Maybe Char)) -> M ()
mapWorld f = do
	height <- worldHeight
	width <- worldWidth
	-- Avoid changing the caps of the scroll.
	forM_ [2..height-3] $ \y ->
		forM_ [0..width-1] $ \x -> do
			let pos = (x,y)
			v <- f pos =<< readWorld pos
			case v of
				Just c -> writeWorld pos c
				Nothing -> return ()

-- Writes a Char to a position in the world.
writeWorld :: Pos -> Char -> M ()
writeWorld = writeS withWorld

writeFlipSide :: Pos -> Char -> M ()
writeFlipSide = writeS withFlipSide

-- Reads a Char from a position in the world.
readWorld :: Pos -> M Char
readWorld = readS withWorld

-- Checks bounds.
readWorldSafe :: Pos -> M (Maybe Char)
readWorldSafe pos@(x,y) = do
	maxy <- worldHeight
	maxx <- worldWidth
	if x >= maxx || y >= maxy || x < 0 || y < 0
		then return Nothing
		else Just <$> readWorld pos

readFlipSide :: Pos -> M Char
readFlipSide = readS withFlipSide

withWorld :: (World -> ST RealWorld a) -> M a
withWorld = withS . (. world)

withFlipSide :: (World -> ST RealWorld a) -> M a
withFlipSide = withS . (. flipSide)

withS :: (S -> ST RealWorld a) -> M a
withS a = lift . a =<< get

writeS :: forall a. ((Vec2 a -> ST RealWorld ()) -> M ()) -> Pos -> a -> M ()
writeS m (x, y) v = m $ \yv -> do
	xv <- MV.read yv y
	MV.write xv x v

readS :: forall a. ((Vec2 a -> ST RealWorld a) -> M a) -> Pos -> M a
readS m (x, y) = m $ \yv -> do
	xv <- MV.read yv y
	MV.read xv x