factory-lang/Main.hs

155 lines
4.9 KiB
Haskell
Raw Normal View History

2021-05-19 20:15:40 +00:00
module Main where
2021-05-23 22:03:17 +00:00
-- TODO:
-- arithmetic
-- I/O
2021-05-19 20:15:40 +00:00
import Data.List
2021-05-23 22:03:17 +00:00
import Element
2021-05-19 20:15:40 +00:00
main :: IO ()
main = do
input <- readFile "test.fac"
let internalFactory = stringsToFactory $ lines input
2021-05-23 22:03:17 +00:00
interpretLoop internalFactory [ Element
0
(1 + fst (entryPointLocation internalFactory))
(snd $ entryPointLocation internalFactory)]
-- , Element
-- 1
-- (2 + (fst $ entryPointLocation internalFactory))
-- (snd $ entryPointLocation internalFactory)]
2021-05-19 20:15:40 +00:00
interpretLoop :: Factory -> [Element] -> IO ()
interpretLoop f es = do
let elements = stepInterpret f es
2021-05-23 22:03:17 +00:00
printFactory f elements
2021-05-19 20:15:40 +00:00
a <- getChar
2021-05-23 22:03:17 +00:00
if a == 'q' then return () else interpretLoop f elements
-- printing factory state with elements overlayed
replaceNth :: Int -> a -> [a] -> [a]
replaceNth _ _ [] = []
replaceNth 0 a (first:rest) = a : rest
replaceNth n a (first:rest) = first : replaceNth (n-1) a rest
changeLine :: Element -> (Int, [Char]) -> (Int, [Char])
changeLine e (index, line)
| yPos e == index = (index, replaceNth (xPos e) (head $ show $ value e) line)
| otherwise = (index, line)
changeTiles :: Element -> [(Int, [Char])] -> [(Int, [Char])]
changeTiles e [] = []
changeTiles e cs = map (changeLine e) cs
2021-05-19 20:15:40 +00:00
2021-05-23 22:03:17 +00:00
putElements :: [Element] -> [(Int, [Char])] -> [(Int, [Char])]
putElements [e] cs = changeTiles e cs
putElements (e:es) cs = changeTiles e (putElements es cs)
2021-05-19 20:15:40 +00:00
2021-05-23 22:03:17 +00:00
indexFactory :: Factory -> [(Int, [Tile])]
indexFactory tiles = indexed
where indexed = zip [0..] tiles
indexCharFactory :: Factory -> [(Int, [Char])]
indexCharFactory f = zip [0..] charFactory
where charFactory = showFactory f
showFactory :: Factory -> [[Char]]
showFactory [] = []
showFactory f = map (map (head . show)) f
printFactory :: Factory -> [Element] -> IO ()
printFactory f es = mapM_ (print . snd) lines
where lines = putElements es $ indexCharFactory f
2021-05-19 20:15:40 +00:00
type Entrypoint = Char
data Direction = North | South | East | West
deriving (Eq, Ord)
2021-05-23 22:03:17 +00:00
data ModifierKind = Increment | Decrement
deriving (Eq)
2021-05-19 20:15:40 +00:00
data Tile = Entrypoint
| Track Direction
2021-05-23 22:03:17 +00:00
| Modifier ModifierKind
| Machine Char -- user defined machines
2021-05-19 20:15:40 +00:00
| Ignored
deriving (Eq)
instance Show Tile where
show t = [tileToChar t]
type Factory = [[Tile]]
charToTile :: Char -> Tile
charToTile c = case c of
'E' -> Entrypoint
'>' -> Track East
'<' -> Track West
'v' -> Track South
'^' -> Track North
2021-05-23 22:03:17 +00:00
'+' -> Modifier Increment
'-' -> Modifier Decrement
2021-05-19 20:15:40 +00:00
_ -> Ignored
tileToChar :: Tile -> Char
tileToChar t = case t of
2021-05-23 22:03:17 +00:00
Entrypoint -> 'E'
Track East -> '>'
Track West -> '<'
Track South -> 'v'
Track North -> '^'
Modifier Increment -> '+'
Modifier Decrement -> '-'
_ -> ' '
2021-05-19 20:15:40 +00:00
stringsToFactory :: [[Char]] -> [[Tile]]
2021-05-23 22:03:17 +00:00
stringsToFactory [] = []
stringsToFactory s = map (map charToTile) s
2021-05-19 20:15:40 +00:00
tupAdd :: (Num a, Num b) => (a, b) -> (a, b) -> (a, b)
tupAdd (a, b) (c, d) = (a + c, b + d)
entryPointLocation :: Factory -> (Int, Int)
entryPointLocation [] = error "Couldn't find an entrypoint (E)."
entryPointLocation (l:ls) = case index of
Nothing -> tupAdd (0, 1) (entryPointLocation ls)
Just x -> (x, 0)
where index = elemIndex Entrypoint l
oobCheck :: Factory -> Element -> Bool
oobCheck f e = yPos e >= length f
|| xPos e >= length (f !! yPos e)
-- custom hashmap thingy, but uses lists so it's slow on large things (luckily this is small)
2021-05-23 22:03:17 +00:00
tileActionMap :: Tile -> [(Tile, Element -> Element)] -> (Element -> Element)
2021-05-19 20:15:40 +00:00
tileActionMap _ [] = id
tileActionMap tile (pair:rest)
| tile == fst pair = snd pair
| otherwise = tileActionMap tile rest
2021-05-23 22:03:17 +00:00
-- TODO: make this safe, aka boundary check
spitOut :: Factory -> Element -> Element
spitOut f elem
| (f !! yPos elem) !! (xPos elem + 1) == Track East = incXPos elem
| (f !! (yPos elem + 1)) !! xPos elem == Track South = incYPos elem
| (f !! yPos elem) !! (xPos elem - 1) == Track West = decXPos elem
| (f !! (yPos elem - 1)) !! xPos elem == Track North = decYPos elem
2021-05-19 20:15:40 +00:00
update :: Factory -> Element -> Element
update f e = if oobCheck f e then error "Element out of bounds check failed!"
2021-05-23 22:03:17 +00:00
else tileActionMap t tileActions e
2021-05-19 20:15:40 +00:00
where t = (f !! yPos e) !! xPos e
2021-05-23 22:03:17 +00:00
tileActions = [ (Track East, \e -> Element (value e) (xPos e + 1) (yPos e))
, (Track West, \e -> Element (value e) (xPos e - 1) (yPos e))
, (Track South, \e -> Element (value e) (xPos e) (yPos e + 1))
, (Track North, \e -> Element (value e) (xPos e) (yPos e - 1))
, (Modifier Increment, incVal . spitOut f)
, (Modifier Decrement, decVal . spitOut f)
2021-05-19 20:15:40 +00:00
]
stepInterpret :: Factory -> [Element] -> [Element]
2021-05-23 22:03:17 +00:00
stepInterpret f = map (update f)