module Chips.Utils where
import Chips.Imports
import Chips.Globals
import Chips.Types

join elem list = concat $ intersperse elem list

for :: [a] -> (a -> b) -> [b]
for = flip map

count :: Eq a => a -> [a] -> Int
count x list = length $ filter (==x) list

withIndices :: [a] -> [(a, Int)]
withIndices arr = zip arr [0..(length arr - 1)]

(//) :: Integral a => a -> a -> a
a // b = floor $ (fromIntegral a) / (fromIntegral b)

($=) ref val = modifyIORef ref (const val)

setValue :: [a] -> Int -> (a -> a) -> [a]
setValue list index func = (take (index) list) ++ [func (list !! index)] ++ (drop (index+1) list)

idx i = to (\x -> x !! i)

whenM func val action = do
  val_ <- use val
  when (func val_) action

with val action = execState action val

eachTile :: ((Tile, Int) -> GameMonad ()) -> GameMonad ()
eachTile action = do
  gs <- get
  forM_ (withIndices (gs ^. tiles)) action
    

chipsLeft gs = length $ filter isChip (_tiles gs)
  where isChip (Chip _) = True
        isChip _        = False

oof :: GameMonad ()
oof = liftIO $ playSound (soundDir ++ "oof.wav") False

guardGodMode action = do
  gm <- use godMode
  when (not gm) action

win :: GameMonad ()
win = liftIO $ playSound (soundDir ++ "win.wav") False

bummer :: GameMonad ()
bummer = liftIO $ playSound (soundDir ++ "bummer.wav") False

onTick :: GameMonad () -> GameMonad ()
onTick action = whenM fst tick action

  wait 2 ticks before doing this
onDoubleTick :: GameMonad () -> GameMonad ()
onDoubleTick action = whenM (even . snd) tick action

(<||>) :: GameMonad Bool -> GameMonad Bool -> GameMonad Bool
a <||> b = do
  res <- a
  if res
    then return True
    else b

oneOf :: [GameMonad Bool] -> GameMonad Bool
oneOf [] = return False
oneOf (x:[]) = x
oneOf (x:xs) = x <||> (oneOf xs)

once :: GameMonad () -> GameMonad ()
once action = do
    cur  <- liftIO . readIORef $ curLocation
    prev <- liftIO . readIORef $ prevLocation
    when (cur /= prev) action

module Chips.Utils where
import Chips.Imports
import Chips.Globals
import Chips.Types

join elem list = concat $ intersperse elem list

for :: [a] -> (a -> b) -> [b]
for = flip map

count :: Eq a => a -> [a] -> Int
count x list = length $ filter (==x) list

withIndices :: [a] -> [(a, Int)]
withIndices arr = zip arr [0..(length arr - 1)]

(//) :: Integral a => a -> a -> a
a // b = floor $ (fromIntegral a) / (fromIntegral b)

($=) ref val = modifyIORef ref (const val)

setValue :: [a] -> Int -> (a -> a) -> [a]
setValue list index func = (take (index) list) ++ [func (list !! index)] ++ (drop (index+1) list)

idx i = to (\x -> x !! i)

whenM func val action = do
  val_ <- use val
  when (func val_) action

with val action = execState action val

eachTile :: ((Tile, Int) -> GameMonad ()) -> GameMonad ()
eachTile action = do
  gs <- get
  forM_ (withIndices (gs ^. tiles)) action
    

chipsLeft gs = length $ filter isChip (_tiles gs)
  where isChip (Chip _) = True
        isChip _        = False

oof :: GameMonad ()
oof = liftIO $ playSound (soundDir ++ "oof.wav") False

guardGodMode action = do
  gm <- use godMode
  when (not gm) action

win :: GameMonad ()
win = liftIO $ playSound (soundDir ++ "win.wav") False

bummer :: GameMonad ()
bummer = liftIO $ playSound (soundDir ++ "bummer.wav") False

onTick :: GameMonad () -> GameMonad ()
onTick action = whenM fst tick action

  wait 2 ticks before doing this
onDoubleTick :: GameMonad () -> GameMonad ()
onDoubleTick action = whenM (even . snd) tick action

(<||>) :: GameMonad Bool -> GameMonad Bool -> GameMonad Bool
a <||> b = do
  res <- a
  if res
    then return True
    else b

oneOf :: [GameMonad Bool] -> GameMonad Bool
oneOf [] = return False
oneOf (x:[]) = x
oneOf (x:xs) = x <||> (oneOf xs)

once :: GameMonad () -> GameMonad ()
once action = do
    cur  <- liftIO . readIORef $ curLocation
    prev <- liftIO . readIORef $ prevLocation
    when (cur /= prev) action
