module Main where import Data.Map qualified as Map import Graphics.Vty import Control.Exception ( bracket ) import Data.List.NonEmpty (NonEmpty(..)) import Data.List.NonEmpty qualified as NonEmpty import Data.Set qualified as Set import System.Environment ( getArgs ) import Data.Map (Map) import Data.Map qualified as Map import Model import Rendering ( render ) import Parser (parse) data Game = Game { gameFlat :: Bool, gameMode :: GameMode, gameSelect :: Int } data GameMode = MenuMode | PlayMode (NonEmpty World) main :: IO () main = do args <- getArgs bracket (mkVty =<< userConfig) shutdown \vty -> case args of x:_ | Just w <- Map.lookup x worldList -> loop vty Game { gameMode = PlayMode (pure w), gameFlat = True, gameSelect = Map.findIndex x worldList } _ -> loop vty Game { gameMode = MenuMode, gameFlat = True, gameSelect = 0 } loop :: Vty -> Game -> IO () loop vty game = case gameMode game of MenuMode -> do let (a,b) = Map.splitAt (gameSelect game) worldList bnds <- displayBounds (outputIface vty) update vty (picForImage (renderMenu bnds a b)) ev <- nextEvent vty case ev of EvKey key _modifier -> case key of KEsc -> pure () KUp | gameSelect game > 0 -> loop vty game{ gameSelect = gameSelect game - 1 } KDown | gameSelect game + 1 < Map.size worldList -> loop vty game{ gameSelect = gameSelect game + 1 } KEnter | Just (world,_) <- Map.minView b -> loop vty game{ gameMode = PlayMode (pure world) } _ -> loop vty game _ -> loop vty game PlayMode worlds -> do let world = NonEmpty.head worlds update vty (render (gameFlat game) (NonEmpty.head worlds)) ev <- nextEvent vty case ev of EvKey key _modifier -> case key of KUp -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (-1,0)) worlds) } KDown -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (1,0) ) worlds) } KLeft -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (0,-1)) worlds) } KRight -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (0,1) ) worlds) } KChar 'm' -> loop vty game { gameMode = MenuMode } KChar 'r' -> loop vty game{ gameMode = PlayMode (pure (NonEmpty.last worlds)) } KChar 'z' | Just worlds' <- NonEmpty.nonEmpty (NonEmpty.tail worlds) -> loop vty game{ gameMode = PlayMode worlds' } KEsc -> pure () KChar 'f' -> loop vty game{ gameFlat = not (gameFlat game) } _ -> loop vty game _ -> loop vty game renderMenu :: DisplayRegion -> Map String World -> Map String World -> Image renderMenu (w,h) before after = pad ((w - imageWidth menu) `div` 2) 0 0 0 menu where menu = case Map.minViewWithKey after of Nothing -> string defAttr "empty menu" Just ((k,_),after') -> let len1 = (h-1)`div`2 in pad 0 (len1 - Map.size before) 0 0 (vertCat [ string defAttr x | x <- drop (Map.size before - len1) (Map.keys before) ]) <-> string (defAttr `withBackColor` cyan `withForeColor` white) k <-> vertCat [ string defAttr x | x <- drop (Map.size after' - h`div`2) (Map.keys after') ] worldList :: Map.Map String World worldList = Map.fromList [ ("world0", world0) , ("small", smallWorld) , ("center8", center8) , ("center13", center13) , ("clone11", clone11) , ("transfer14", transfer14) , ("transfer20", transfer20) , ("transfer26", transfer26) , ("transfer27", transfer27) , ("open4", open4) , ("cycle10", cycle10) , ("player10", player10) , ("player11", player11) , ("player18", player18) , ("infiniteExit5", infiniteExit5) , ("infiniteExit15", infiniteExit15) , ("infiniteEnter17", infiniteEnter17) , ("infiniteEnter19", infiniteEnter19) , ("infiniteEnter20", infiniteEnter20) , ("multiInfinite5", multiInfinite5) , ("multiInfinite8", multiInfinite8) ] smallWorld :: World smallWorld = World (Map.fromList [('a', Box (Location 'a' 0 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓ ▓ ▓", "▓ ▓ ▓", "▓▓▓▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr black) False), ('1', Box (Location 'a' (-3) (-3)) (Original (makeWalls (replicate 9 (replicate 9 ' ')))) (withForeColor defAttr yellow) False), ('2', Box (Location 'a' (-3) (-2)) (Original (makeWalls (replicate 9 (replicate 9 ' ')))) (withForeColor defAttr magenta) False), ('3', Box (Location 'a' (-2) (-3)) (Original (makeWalls (replicate 9 (replicate 9 ' ')))) (withForeColor defAttr blue) False), ('4', Box (Location 'a' (-2) (-2)) (Original (makeWalls (replicate 9 (replicate 9 ' ')))) (withForeColor defAttr green) False), ('b', Box (Location '1' 0 0) (Original (solid 9)) (withForeColor defAttr red) True) ]) 'b' Set.empty (Location 'b' 0 0) center8 :: World center8 = parse "player p\n\ \block t white boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓a▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block a white interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓\n\ \▓▓ p ▓▓\n\ \▓ g ▓▓\n\ \▓ ▓▓\n\ \▓▓▓▓ ▓▓▓▓\n\ \▓▓▓▓- =▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block g green interesting\n\ \ x ▓▓\n\ \ ▓▓▓▓▓\n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \block x yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ ▓▓▓ ▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" center13 :: World center13 = parse "player p\n\ \block t cyan boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓a▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block a cyan interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ p =▓\n\ \▓ ▓\n\ \▓ x g ▓\n\ \▓ ▓\n\ \▓ ▓▓▓ ▓▓\n\ \▓ ▓-▓ ▓▓\n\ \▓ ▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block g green interesting\n\ \ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ ▓▓▓▓▓▓▓ \n\ \ \n\ \block x yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ ▓▓▓ ▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" clone11 :: World clone11 = parse "player p\n\ \block a green boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓= ▓ ▓\n\ \▓- ▓ a ▓\n\ \▓- ▓ ▓\n\ \ p ▓ A \n\ \▓ ▓ ▓\n\ \▓ ▓ ▓\n\ \▓▓▓ ▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \link A a green\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ ▓▓▓ ▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" transfer14 :: World transfer14 = World (Map.fromList [('a', Box (Location 'a' 1 1) (Original (makeWalls [ " ", " ", " ", " ", " ▓ ", " ", " ", " ", " " ])) (withForeColor defAttr cyan) False), ('g', Box (Location 'a' (-1) (-1)) (Original (makeWalls [ " ▓▓▓ ", " ▓ ▓ ", " ", " ▓ ", "▓▓ ▓ ▓▓", " ▓ ", " ", " ", " ▓ " ])) (withForeColor defAttr green) False), ('x', Box (Location 'g' 3 (-3)) (Original (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ", " " ])) (withForeColor defAttr magenta) False), ('b', Box (Location 'a' 1 (-1)) (Original (solid 9)) (withForeColor defAttr red) True) ]) 'b' (Set.fromList [Location 'g' (-2) 0]) (Location 'g' (-3) 0) open4 :: World open4 = World (Map.fromList [('a', Box (Location 'a' 0 (-1)) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓▓▓", "▓▓ ▓", "▓ ▓", "▓▓ ▓", "▓▓ ▓", "▓▓ ▓", "▓▓ ▓", "▓▓ ▓" ])) (withForeColor defAttr cyan) False), ('g', Box (Location 'a' 2 (-1)) (Original (makeWalls [ "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓" ])) (withForeColor defAttr green) False), ('y', Box (Location 'a' 2 1) (Original (makeWalls [ "▓▓▓▓▓▓ ▓▓", "▓▓▓▓▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr yellow) False), ('b', Box (Location 'a' 0 1) (Original (solid 9)) (withForeColor defAttr red) True) ]) 'b' Set.empty (Location 'y' (-3) 2) world0 :: World world0 = World { worldButtons = Set.empty, worldHome = Location '2' 0 0, worldMe = 'b', worldBoxes = Map.fromList [('1', Box { boxColor = withForeColor defAttr green, boxLocation = Location '1' (-1) 0, boxType = Original $ makeWalls [ "▓▓ ▓▓", "▓ ▓", "▓ ▓", "▓ ▓", " ▓", "▓ ▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓▓▓▓▓ ▓" ], boxBoring = False }), ('2', Box { boxColor = withForeColor defAttr cyan, boxLocation = Location '1' 1 1, boxType = Original $ makeWalls [ "▓ ▓▓ ▓▓ ▓", " ", " ▓", " ▓", " ", "▓ ▓", "▓ ▓", " ", "▓ ▓▓ ▓▓ ▓" ], boxBoring = False }), ('₂', Box { boxColor = withForeColor defAttr cyan, boxLocation = Location '1' 2 (-1), boxType = Link '2', boxBoring = True }), ('3', Box { boxColor = withForeColor defAttr blue, boxLocation = Location '2' 1 1, boxType = Original $ makeWalls [ "▓▓▓▓▓▓▓▓▓", " ", "▓▓▓▓▓▓▓▓ ", "▓▓ ▓▓▓ ", "▓▓ ▓▓▓ ", "▓▓▓▓ ▓▓▓ ", "▓▓ ▓▓▓▓", "▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓" ], boxBoring = False }), ('4', Box { boxColor = withForeColor defAttr black, boxLocation = Location 'b' (-3) 0, boxType = Original $ makeWalls [ "▓▓▓ ▓▓▓", "▓ ▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓▓▓▓ ▓▓▓▓" ], boxBoring = False }), ('b', Box { boxColor = withForeColor defAttr red, boxLocation = Location '1' 0 1, boxType = Original $ makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓ ▓", "▓ ▓", "▓ ▓ ▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓ ▓", "▓▓▓▓▓▓▓▓▓" ], boxBoring = True }), ('x', Box { boxColor = withForeColor defAttr yellow, boxLocation = Location '1' 0 (-1), boxType = Original $ makeWalls [ "▓▓ ▓ ", " ", " ▓ ▓▓▓ ", " ▓ ", "▓ ▓▓▓▓", " ▓▓▓ ", " ▓ ▓▓▓ ", " ", "▓ ▓ ▓"], boxBoring = False }), ('y', Box { boxColor = withForeColor defAttr magenta, boxLocation = Location '1' 0 (-2), boxType = Original $ makeWalls [ "▓▓ ▓ ", " ", "▓▓ ▓▓▓ ", "▓▓ ", " ▓▓▓▓", "▓▓▓▓ ", "▓▓ ▓▓▓ ", " ", "▓ ▓ ▓"], boxBoring = False }), ('i', Box { boxColor = withForeColor defAttr black, boxLocation = Location 'b' 0 (-2), boxType = Original $ solid 9, boxBoring = True }), ('j', Box { boxColor = withForeColor defAttr black, boxLocation = Location 'b' 0 (-1), boxType = Original $ solid 9, boxBoring = True }), ('k', Box { boxColor = withForeColor defAttr black, boxLocation = Location 'b' 0 0, boxType = Original $ solid 9, boxBoring = True }), ('l', Box { boxColor = withForeColor defAttr black, boxLocation = Location 'b' 0 1, boxType = Original $ solid 9, boxBoring = True }), ('₁', Box { boxColor = withForeColor defAttr green, boxLocation = Location '1' 2 1, boxType = Link '1', boxBoring = True }) ] } cycle10 :: World cycle10 = World (Map.fromList [('g', Box (Location 'g' 3 3) (Original (makeWalls [ "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓ ▓▓▓", "▓ ▓▓▓", "▓ ▓▓▓", "▓ ▓▓▓", "▓ ▓ ▓", "▓ ▓ ▓" ])) (withForeColor defAttr green) False), ('G', Box (Location 'g' 0 (-2)) (Link 'g') (withForeColor defAttr green) True), ('p', Box (Location 'g' 0 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) True), ('y', Box (Location 'g' (-4) 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓ ", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr yellow) False), ('1', Box (Location 'g' (-2) 0) (Original (solid 9)) (withForeColor defAttr red) True), ('2', Box (Location 'g' 2 0) (Original (solid 9)) (withForeColor defAttr red) True), ('3', Box (Location 'g' 2 (-2)) (Original (solid 9)) (withForeColor defAttr red) True) ]) 'p' Set.empty (Location 'y' 0 3) player10 :: World player10 = World (Map.fromList [('a', Box (Location 'a' 3 3) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ▓▓▓▓▓▓", "▓▓ ▓▓▓", "▓▓ ▓ ▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr cyan) False), ('p', Box (Location 'a' (-2) 0) (Link 'c') (withForeColor defAttr magenta) True), ('C', Box (Location 'a' 0 2) (Link 'c') (withForeColor defAttr magenta) True), ('c', Box (Location 'a' (-1) 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓ ", "▓▓▓▓▓ ", "▓▓▓▓▓ ", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) False), ('1', Box (Location 'a' (-3) 2) (Original (solid 9)) (withForeColor defAttr blue) True) ]) 'p' (Set.singleton (Location 'a' 2 1)) (Location 'a' 3 1) player11 :: World player11 = World (Map.fromList [('_', Box (Location '_' 3 3) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓ ▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr cyan) True), ('a', Box (Location '_' 0 0) (Original (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ", " " ])) (withForeColor defAttr magenta) True), ('A', Box (Location 'a' 0 0) (Link 'a') (withForeColor defAttr brightMagenta) True), ('b', Box (Location 'a' (-1) (-4)) (Original (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ", " " ])) (withForeColor defAttr yellow) False), ('1', Box (Location 'a' 0 4) (Original (solid 9)) (withForeColor defAttr blue) True) ]) 'A' (Set.fromList [Location 'a' 1 4, Location 'a' (-1) 4]) (Location 'a' 1 (-4)) player18 :: World player18 = World (Map.fromList [('c', Box (Location 'c' (-1) (-1)) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr yellow) False), ('u', Box (Location 'c' 0 0) (Original (makeWalls [ "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) False), ('1', Box (Location 'c' (-1) 1) (Original (solid 9)) (withForeColor defAttr blue) True), ('2', Box (Location 'c' 1 (-1)) (Original (solid 9)) (withForeColor defAttr blue) True), ('3', Box (Location 'c' 1 1) (Original (solid 9)) (withForeColor defAttr blue) True) ]) 'u' (Set.singleton (Location 'u' (-1) 2)) (Location 'u' 1 (-2)) infiniteExit5 :: World infiniteExit5 = World (Map.fromList [('a', Box (Location 'a' 3 (-1)) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓ ", "▓ ", "▓ ", "▓ ", "▓ ", "▓ ", "▓ ", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr yellow) False), ('∞', Box (Location 'a' (-2) (-3)) (Infinity 'a') (withForeColor defAttr yellow) True), ('p', Box (Location 'a' 0 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) True) ]) 'p' (Set.singleton (Location 'a' 0 1)) (Location 'a' (-1) 1) infiniteExit15 :: World infiniteExit15 = parse "player m\n\ \block t cyan boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓a▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block a cyan interesting\n\ \▓▓▓G▓▓▓▓▓\n\ \ ▓▓▓▓\n\ \ P ▓▓-=\n\ \ ▓--▓\n\ \ p g -▓▓\n\ \ m ▓▓▓▓\n\ \ Π Γ ▓▓▓▓\n\ \ ▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block m magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block g green interesting\n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \block p red interesting\n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \ \n\ \link G g green\n\ \link P p red\n\ \infinity Γ g green\n\ \infinity Π p red\n" infiniteEnter17 :: World infiniteEnter17 = World (Map.fromList [('g', Box (Location 'g' 2 (-2)) (Original (makeWalls [ " ▓▓", " ▓▓", " ▓▓", " ▓▓", " ▓ ▓", " ▓▓", " ▓▓▓", "▓▓▓▓ ▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr green) False), ('∞', Box (Location 'g' 0 3) (Infinity 'g') (withForeColor defAttr green) False), ('G', Box (Location 'g' 1 2) (Link 'g') (withForeColor defAttr green) True), ('ε', Box (Location 'g' 3 0) (Epsilon 'g' (makeWalls [ "▓▓▓▓▓▓ ▓▓", " ", " ", " ", " ", " ", " ", " ", " "])) (withForeColor defAttr green) False), ('1', Box (Location 'ε' 0 0) (Original (solid 9)) (withForeColor defAttr blue) True), ('p', Box (Location 'g' 0 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) True) ]) 'p' (Set.fromList [Location 'g' (-2) (-1), Location 'g' (-2) (-2)]) (Location 'g' (-2) 0) infiniteEnter19 :: World infiniteEnter19 = World (Map.fromList [('w', Box (Location 'w' 3 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓▓ ▓▓", "▓ ▓ ▓ ▓", "▓ ▓", "▓ ▓▓▓▓▓ ▓", "▓ ▓▓ ▓▓ ▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr white) False), ('g', Box (Location 'w' (-3) (-1)) (Original (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ▓ ", " " ])) (withForeColor defAttr green) False), ('∞', Box (Location 'w' 2 (-3)) (Infinity 'g') (withForeColor defAttr green) False), ('G', Box (Location 'w' (-3) 1) (Link 'g') (withForeColor defAttr green) True), ('ε', Box (Location 'w' 2 3) (Epsilon 'g' (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ", " "])) (withForeColor defAttr green) False), ('p', Box (Location 'w' (-1) 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓ ▓▓▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr magenta) True) ]) 'p' (Set.fromList [Location 'w' 0 (-3), Location 'w' 0 (3)]) (Location 'w' 0 0) infiniteEnter20 :: World infiniteEnter20 = World (Map.fromList [('_', Box (Location '_' 0 0) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓ ▓ ▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓", "▓▓▓▓▓▓▓▓▓"])) (withForeColor defAttr white) True), ('w', Box (Location '_' 0 2) (Original (makeWalls [ "▓▓▓▓▓▓▓▓▓", "▓ ▓▓ ▓", "▓ ▓▓ ▓", "▓ ▓▓▓▓", "▓ ▓ ▓", "▓▓ ▓▓ ▓", "▓ ▓", "▓ ▓▓ ▓", "▓▓▓▓▓▓▓▓▓" ])) (withForeColor defAttr white) False), ('r', Box (Location 'w' 2 0) (Original (makeWalls [ " ", " ", " ", " ▓▓▓ ", " ▓▓▓ ", " ▓▓▓ ", " ", " ", " " ])) (withForeColor defAttr red) False), ('a', Box (Location 'w' 1 3) (Link 'r') (withForeColor defAttr red) True), ('b', Box (Location 'w' 2 3) (Link 'r') (withForeColor defAttr red) True), ('ε', Box (Location 'w' (-2) 3) (Epsilon 'r' (makeWalls [ " ", " ", " ", " ", " ", " ", " ", " ", " "])) (withForeColor defAttr red) False), ('1', Box (Location 'w' (-3) (-3)) (Original (solid 9)) (withForeColor defAttr blue) True), ('2', Box (Location 'w' (-3) (-1)) (Original (solid 9)) (withForeColor defAttr blue) True), ('3', Box (Location 'w' (-1) (-3)) (Original (solid 9)) (withForeColor defAttr blue) True), ('4', Box (Location 'w' (-1) 0) (Original (solid 9)) (withForeColor defAttr blue) True), ('5', Box (Location 'w' 2 (-3)) (Original (solid 9)) (withForeColor defAttr blue) True) ]) 'r' Set.empty (Location 'w' (-3) 3) multiInfinite5 :: World multiInfinite5 = parse "player p\n\ \block b blue interesting\n\ \▓▓▓ ▓\n\ \▓▓▓ ▓\n\ \▓▓▓ b 1 ▓\n\ \▓=▓ p ▓\n\ \▓-▓ 3 2 ▓\n\ \▓-▓ ▓\n\ \▓-▓ ▓\n\ \▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \infinity 1 b blue\n\ \infinity 2 1 blue\n\ \infinity 3 2 blue\n" multiInfinite8 :: World multiInfinite8 = parse "player p\n\ \block b blue interesting\n\ \▓ ▓\n\ \▓ ▓ ▓\n\ \▓▓ ▓\n\ \▓1 p A ▓\n\ \▓▓ ▓\n\ \▓2 ▓\n\ \▓▓ ▓\n\ \▓3 b▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \link A b blue\n\ \link B b blue\n\ \link C b blue\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \epsilon 1 b blue\n\ \ \n\ \ ▓ \n\ \ \n\ \ ▓▓\n\ \ B ▓ \n\ \ ▓▓\n\ \ \n\ \ \n\ \ \n\ \epsilon 2 1 blue\n\ \ \n\ \ \n\ \ ▓ \n\ \ ▓▓\n\ \ ▓ \n\ \ ▓▓\n\ \ \n\ \ \n\ \ C x \n\ \epsilon 3 2 blue\n\ \ \n\ \ \n\ \ \n\ \ ▓▓\n\ \ = ▓ \n\ \ ▓▓\n\ \ \n\ \ \n\ \ \n\ \block x yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" transfer20 :: World transfer20 = parse "player p\n\ \block t blue boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓a▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block a blue interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ ▓ ▓\n\ \▓ ▓\n\ \▓ ABC ▓\n\ \▓ p ▓\n\ \▓ XYZ ▓\n\ \▓ ▓\n\ \▓ ▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \link A C cyan\n\ \link B C cyan\n\ \block C cyan interesting\n\ \▓▓▓▓▓ ▓ ▓\n\ \▓▓▓▓▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \ ▓▓▓▓▓▓▓\n\ \▓ ▓▓▓▓▓▓▓\n\ \▓ ▓▓▓▓▓▓▓\n\ \▓ ▓▓▓▓▓=▓\n\ \▓ ▓▓▓▓▓ ▓\n\ \link X Z green\n\ \link Y Z green\n\ \block Z green interesting\n\ \▓ ▓ ▓▓▓▓▓\n\ \▓ ▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓ ▓▓▓\n\ \▓▓▓ ▓ ▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" transfer26 :: World transfer26 = parse "player p\n\ \block t blue boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓a▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block a blue interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓\n\ \▓ ▓\n\ \▓ T x 1 ▓\n\ \▓ ▓\n\ \▓ p 3 2 ▓\n\ \▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block x yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block 1 cyan interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓ ▓▓\n\ \ ▓▓ ▓▓\n\ \ ▓▓ ▓▓\n\ \ ▓▓ ▓▓\n\ \▓▓▓▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block 2 cyan interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓ ▓\n\ \ ▓▓▓ ▓\n\ \ ▓▓▓ ▓\n\ \ ▓▓ ▓▓\n\ \▓▓▓▓▓▓ ▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block 3 cyan interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓ ▓▓▓▓▓▓\n\ \▓▓ ▓▓ \n\ \▓ ▓▓ \n\ \▓▓ ▓▓ \n\ \▓ ▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block T green interesting\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \ \n\ \▓▓▓ = ▓▓▓\n\ \▓▓▓ ▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n" transfer27 :: World transfer27 = parse "player p\n\ \block t white boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓t▓ab▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \link A a blue\n\ \block a blue interesting\n\ \▓▓ y \n\ \▓▓ \n\ \▓▓ \n\ \▓ \n\ \▓B p \n\ \▓ \n\ \▓▓ \n\ \▓▓ \n\ \▓▓ x \n\ \link B b red\n\ \block b red interesting\n\ \ ▓▓\n\ \ ▓▓\n\ \ ▓▓\n\ \ ▓\n\ \ =-- A▓\n\ \ ▓\n\ \ ▓▓\n\ \ ▓▓\n\ \ ▓▓\n\ \block x yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block y yellow boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \block p magenta boring\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓ ▓▓▓ ▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n\ \▓▓▓▓▓▓▓▓▓\n"