configurable sizes
This commit is contained in:
parent
2912fb9488
commit
babd42f838
24
app/Main.hs
24
app/Main.hs
|
@ -3,6 +3,8 @@ module Main (main) where
|
||||||
import Control.Exception ( bracket )
|
import Control.Exception ( bracket )
|
||||||
import Data.List.NonEmpty (NonEmpty(..))
|
import Data.List.NonEmpty (NonEmpty(..))
|
||||||
import Data.List.NonEmpty qualified as NonEmpty
|
import Data.List.NonEmpty qualified as NonEmpty
|
||||||
|
import Data.Char (toUpper)
|
||||||
|
import Data.List (intersperse)
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import Data.Map qualified as Map
|
import Data.Map qualified as Map
|
||||||
import Graphics.Vty
|
import Graphics.Vty
|
||||||
|
@ -13,6 +15,7 @@ import System.FilePath ( (</>), takeBaseName )
|
||||||
import Model
|
import Model
|
||||||
import Rendering ( render )
|
import Rendering ( render )
|
||||||
import Parser (parse)
|
import Parser (parse)
|
||||||
|
import BigFont
|
||||||
|
|
||||||
data Game = Game {
|
data Game = Game {
|
||||||
gameFlat :: Bool,
|
gameFlat :: Bool,
|
||||||
|
@ -98,16 +101,19 @@ renderMenu (w,h) before after =
|
||||||
where
|
where
|
||||||
menu =
|
menu =
|
||||||
case Map.minViewWithKey after of
|
case Map.minViewWithKey after of
|
||||||
Nothing -> string defAttr "empty menu"
|
Nothing -> bigString defAttr "empty menu"
|
||||||
Just ((k,_),after') ->
|
Just ((k,_),after') ->
|
||||||
let len1 = (h-1)`div`2 in
|
let len1 = (h-1)`div`2 `div` 6 in
|
||||||
pad 0 (len1 - Map.size before) 0 0 (vertCat
|
pad 0 (max 0 (6 * (len1 - Map.size before))) 0 0 $
|
||||||
[ string defAttr x
|
vertCat $
|
||||||
|
intersperse (char defAttr ' ') $
|
||||||
|
[ bigString defAttr x
|
||||||
| x <- drop (Map.size before - len1) (Map.keys before)
|
| x <- drop (Map.size before - len1) (Map.keys before)
|
||||||
]) <->
|
] ++
|
||||||
string (defAttr `withBackColor` cyan `withForeColor` white) k
|
[bigString (defAttr `withBackColor` cyan `withForeColor` white) k] ++
|
||||||
<->
|
[ bigString defAttr x
|
||||||
vertCat
|
|
||||||
[ string defAttr x
|
|
||||||
| x <- drop (Map.size after' - h`div`2) (Map.keys after')
|
| x <- drop (Map.size after' - h`div`2) (Map.keys after')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
bigString :: Attr -> String -> Image
|
||||||
|
bigString a = vertCat . map (string a) . bigText . map toUpper
|
||||||
|
|
|
@ -41,7 +41,9 @@ data World = World {
|
||||||
worldBoxes :: Map Char Box,
|
worldBoxes :: Map Char Box,
|
||||||
worldMe :: Char,
|
worldMe :: Char,
|
||||||
worldButtons :: Set Location,
|
worldButtons :: Set Location,
|
||||||
worldHome :: Location
|
worldHome :: Location,
|
||||||
|
worldHeight :: Int,
|
||||||
|
worldWidth :: Int
|
||||||
}
|
}
|
||||||
deriving (Show, Read, Eq)
|
deriving (Show, Read, Eq)
|
||||||
|
|
||||||
|
|
143
app/Parser.hs
143
app/Parser.hs
|
@ -6,70 +6,109 @@ import Graphics.Vty.Attributes
|
||||||
import Data.Array (Array, listArray)
|
import Data.Array (Array, listArray)
|
||||||
import Data.Map qualified as Map
|
import Data.Map qualified as Map
|
||||||
import Data.Set qualified as Set
|
import Data.Set qualified as Set
|
||||||
|
import Text.ParserCombinators.ReadP hiding (many)
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
|
|
||||||
parse :: String -> World
|
parse :: String -> World
|
||||||
parse str = either error id $
|
parse str =
|
||||||
case lines str of
|
case readP_to_S ((,) <$> parseHeader <*> many parseBlock <* eof) str of
|
||||||
x:xs ->
|
[] -> error "world parsing failed"
|
||||||
do h <- parseHeader x
|
(((p,h,w),bs),_):_ ->
|
||||||
bs <- parseBlocks xs
|
do let m = Map.fromListWith (++) [(k,[v]) | (_,_,kvs) <- bs, (k,v) <- kvs]
|
||||||
let m = Map.fromListWith (++) [(k,[v]) | (_,_,kvs) <- bs, (k,v) <- kvs]
|
World
|
||||||
pure $ World
|
|
||||||
(Map.fromList [
|
(Map.fromList [
|
||||||
(n, b { boxLocation = head (m Map.! n)})
|
(n, b { boxLocation = head (m Map.! n)})
|
||||||
| (n,b,_) <- bs
|
| (n,b,_) <- bs
|
||||||
])
|
])
|
||||||
h
|
p
|
||||||
(Set.fromList (Map.findWithDefault [] '-' m))
|
(Set.fromList (Map.findWithDefault [] '-' m))
|
||||||
(head (m Map.! '='))
|
(head (m Map.! '='))
|
||||||
[] -> Left "empty input"
|
h w
|
||||||
|
|
||||||
parseHeader :: String -> Either String Char
|
parseHeader :: ReadP (Char,Int,Int)
|
||||||
parseHeader (words -> ["player", [p]]) = Right p
|
parseHeader =
|
||||||
parseHeader _ = Left "bad header"
|
do "player" <- token
|
||||||
|
[p] <- token
|
||||||
|
h <- option 81
|
||||||
|
do "height" <- token
|
||||||
|
integer
|
||||||
|
w <- option (81*2)
|
||||||
|
do "width" <- token
|
||||||
|
integer
|
||||||
|
pure (p,h,w)
|
||||||
|
|
||||||
parseBlocks :: [String] -> Either String [(Char, Box, [(Char, Location)])]
|
integer :: ReadP Int
|
||||||
parseBlocks [] = Right []
|
integer = readS_to_P reads
|
||||||
parseBlocks (x:xs) =
|
|
||||||
case words x of
|
|
||||||
["block", [name], color, boring] ->
|
|
||||||
do color_ <- parseColor color
|
|
||||||
let (xs1,xs2) = splitWalls xs
|
|
||||||
let locs = findLocs name xs1
|
|
||||||
let b = Box undefined (Original (walls xs1)) color_ (boring == "boring")
|
|
||||||
bs <- parseBlocks xs2
|
|
||||||
pure ((name, b, locs):bs)
|
|
||||||
["link", [name], [target], color] ->
|
|
||||||
do color_ <- parseColor color
|
|
||||||
bs <- parseBlocks xs
|
|
||||||
pure ((name, Box undefined (Link target) color_ True, []):bs)
|
|
||||||
["infinity", [name], [target], color] ->
|
|
||||||
do color_ <- parseColor color
|
|
||||||
bs <- parseBlocks xs
|
|
||||||
pure ((name, Box undefined (Infinity target) color_ True,[]):bs)
|
|
||||||
["epsilon", [name], [target], color] ->
|
|
||||||
do color_ <- parseColor color
|
|
||||||
let (xs1,xs2) = splitWalls xs
|
|
||||||
let locs = findLocs name xs1
|
|
||||||
let b = Box undefined (Epsilon target (walls xs1)) color_ False
|
|
||||||
bs <- parseBlocks xs2
|
|
||||||
pure ((name, b, locs):bs)
|
|
||||||
_ -> Left "bad block"
|
|
||||||
|
|
||||||
splitWalls (x:xs) =
|
parseBoring :: ReadP Bool
|
||||||
case splitAt (length x - 1) xs of
|
parseBoring =
|
||||||
(a,b) -> (x:a, b)
|
do t <- token
|
||||||
|
case t of
|
||||||
|
"boring" -> pure True
|
||||||
|
"interesting" -> pure False
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
parseColor :: String -> Either String Attr
|
parseBlock :: ReadP (Char, Box, [(Char, Location)])
|
||||||
parseColor "white" = Right (withForeColor defAttr white)
|
parseBlock =
|
||||||
parseColor "cyan" = Right (withForeColor defAttr cyan)
|
do cmd <- token
|
||||||
parseColor "blue" = Right (withForeColor defAttr blue)
|
case cmd of
|
||||||
parseColor "red" = Right (withForeColor defAttr red)
|
"block" ->
|
||||||
parseColor "yellow" = Right (withForeColor defAttr yellow)
|
do [name] <- token
|
||||||
parseColor "magenta" = Right (withForeColor defAttr magenta)
|
color <- parseColor
|
||||||
parseColor "black" = Right (withForeColor defAttr black)
|
boring <- parseBoring
|
||||||
parseColor "green" = Right (withForeColor defAttr green)
|
skipMany (satisfy (' '==))
|
||||||
parseColor x = Left ("bad color " ++ x)
|
_ <- char '\n'
|
||||||
|
xs1 <- parseWalls
|
||||||
|
let locs = findLocs name xs1
|
||||||
|
let b = Box undefined (Original (walls xs1)) color boring
|
||||||
|
pure (name, b, locs)
|
||||||
|
"link" ->
|
||||||
|
do [name] <- token
|
||||||
|
[target] <- token
|
||||||
|
color <- parseColor
|
||||||
|
_ <- char '\n'
|
||||||
|
pure (name, Box undefined (Link target) color True, [])
|
||||||
|
"infinity" ->
|
||||||
|
do [name] <- token
|
||||||
|
[target] <- token
|
||||||
|
color <- parseColor
|
||||||
|
_ <- char '\n'
|
||||||
|
pure (name, Box undefined (Infinity target) color True,[])
|
||||||
|
"epsilon" ->
|
||||||
|
do [name] <- token
|
||||||
|
[target] <- token
|
||||||
|
color <- parseColor
|
||||||
|
skipMany (satisfy (' '==))
|
||||||
|
_ <- char '\n'
|
||||||
|
xs1 <- parseWalls
|
||||||
|
let locs = findLocs name xs1
|
||||||
|
let b = Box undefined (Epsilon target (walls xs1)) color False
|
||||||
|
pure (name, b, locs)
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
|
parseWalls :: ReadP [String]
|
||||||
|
parseWalls =
|
||||||
|
do row0 <- munch1 ('\n' /=) <* char '\n'
|
||||||
|
rows <- replicateM (length row0 - 1) (munch1 ('\n' /=) <* char '\n')
|
||||||
|
pure (row0:rows)
|
||||||
|
|
||||||
|
token :: ReadP String
|
||||||
|
token = readS_to_P lex
|
||||||
|
|
||||||
|
parseColor :: ReadP Attr
|
||||||
|
parseColor =
|
||||||
|
do t <- token
|
||||||
|
case t of
|
||||||
|
"white" -> pure (withForeColor defAttr white)
|
||||||
|
"cyan" -> pure (withForeColor defAttr cyan)
|
||||||
|
"blue" -> pure (withForeColor defAttr blue)
|
||||||
|
"red" -> pure (withForeColor defAttr red)
|
||||||
|
"yellow" -> pure (withForeColor defAttr yellow)
|
||||||
|
"magenta" -> pure (withForeColor defAttr magenta)
|
||||||
|
"black" -> pure (withForeColor defAttr black)
|
||||||
|
"green" -> pure (withForeColor defAttr green)
|
||||||
|
_ -> empty
|
||||||
|
|
||||||
walls :: [String] -> Array Coord Bool
|
walls :: [String] -> Array Coord Bool
|
||||||
walls rows = listArray ((ylo,xlo),(yhi,xhi)) (map ('▓'==) (concat rows))
|
walls rows = listArray ((ylo,xlo),(yhi,xhi)) (map ('▓'==) (concat rows))
|
||||||
|
|
|
@ -116,7 +116,7 @@ renderFlat locMap world =
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
borderAttr = defAttr `withForeColor` white `withBackColor` black
|
borderAttr = defAttr `withForeColor` white `withBackColor` black
|
||||||
offset = max 0 ( (2*(81+2*border)+2 - imageWidth baseImage) `div` 2)
|
offset = max 0 ( (worldWidth world + 2*(2*border)+2 - imageWidth baseImage) `div` 2)
|
||||||
baseImage =
|
baseImage =
|
||||||
pad 2 1 2 1 $
|
pad 2 1 2 1 $
|
||||||
horizCat $
|
horizCat $
|
||||||
|
@ -127,11 +127,10 @@ renderFlat locMap world =
|
||||||
|
|
||||||
drawNestedWorld :: Map Location Char -> World -> Image
|
drawNestedWorld :: Map Location Char -> World -> Image
|
||||||
drawNestedWorld locMap world =
|
drawNestedWorld locMap world =
|
||||||
-- (3*81) + 81 + (3*81)
|
cropTop (h + 2*border) $
|
||||||
cropTop (81 + 2*border) $
|
cropLeft (w + 4*border) $
|
||||||
cropLeft (2*(81 + 2*border)) $
|
cropBottom (2*h + border) $
|
||||||
cropBottom (2*81 + border) $
|
cropRight (2*(w + border)) $
|
||||||
cropRight (2*(2*81 + border)) $
|
|
||||||
vertCat $
|
vertCat $
|
||||||
intersperse (char defAttr ' ')
|
intersperse (char defAttr ' ')
|
||||||
[
|
[
|
||||||
|
@ -139,15 +138,17 @@ drawNestedWorld locMap world =
|
||||||
intersperse (char defAttr ' ')
|
intersperse (char defAttr ' ')
|
||||||
[
|
[
|
||||||
case stackedLoc world locMap (Location name1 y_ x_) of
|
case stackedLoc world locMap (Location name1 y_ x_) of
|
||||||
Nothing -> unit (withForeColor defAttr black) 81 162 '?'
|
Nothing -> unit (withForeColor defAttr black) h w '?'
|
||||||
Just (Location n y x) ->
|
Just (Location n y x) ->
|
||||||
let box = worldBoxes world Map.! n in
|
let box = worldBoxes world Map.! n in
|
||||||
renderCell world locMap n box y x 81 (81*2)
|
renderCell world locMap n box y x h w
|
||||||
| x_ <- [x1-1 .. x1+1]
|
| x_ <- [x1-1 .. x1+1]
|
||||||
]
|
]
|
||||||
| y_ <- [y1-1 .. y1+1]
|
| y_ <- [y1-1 .. y1+1]
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
|
h = worldHeight world
|
||||||
|
w = worldWidth world
|
||||||
-- name1 is the box the player is standing in
|
-- name1 is the box the player is standing in
|
||||||
Location name0 _ _ = myLocation world
|
Location name0 _ _ = myLocation world
|
||||||
Location name1 y1 x1 = boxLocation (worldBoxes world Map.! name0)
|
Location name1 y1 x1 = boxLocation (worldBoxes world Map.! name0)
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
player p
|
player p
|
||||||
block t white boring
|
block t white boring
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓t▓a▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓t▓a▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
block a white interesting
|
block a white interesting
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓▓▓▓▓
|
||||||
|
@ -28,8 +24,8 @@ block g green interesting
|
||||||
block x yellow boring
|
block x yellow boring
|
||||||
▓
|
▓
|
||||||
block p magenta boring
|
block p magenta boring
|
||||||
▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓ ▓▓ ▓
|
▓ ▓ ▓
|
||||||
▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
player p
|
player p height 75 width 150
|
||||||
block t red boring
|
block t red boring
|
||||||
▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
|
@ -6,15 +6,11 @@ block t red boring
|
||||||
▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
block r red interesting
|
block r red interesting
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
p y
|
||||||
▓▓ ▓▓
|
|
||||||
▓▓ p y ▓▓
|
b g
|
||||||
▓▓ ▓▓
|
= -
|
||||||
▓▓ b g ▓▓
|
|
||||||
▓▓= -▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
block p magenta boring
|
block p magenta boring
|
||||||
▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓ ▓ ▓
|
▓ ▓ ▓
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
player m
|
player m
|
||||||
block t cyan boring
|
block t cyan boring
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓t▓a▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓t▓a▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
block a cyan interesting
|
block a cyan interesting
|
||||||
▓▓▓G▓▓▓▓▓
|
▓▓▓G▓▓▓▓▓
|
||||||
▓▓▓▓
|
▓▓▓▓
|
||||||
|
@ -20,35 +16,19 @@ block a cyan interesting
|
||||||
▓▓▓▓
|
▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓▓▓▓▓
|
||||||
block m magenta boring
|
block m magenta boring
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓ ▓ ▓
|
||||||
▓▓ ▓▓▓ ▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
▓▓▓▓▓
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
▓▓▓▓▓▓▓▓▓
|
|
||||||
block g green interesting
|
block g green interesting
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
block p red interesting
|
block p red interesting
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
link G g green
|
link G g green
|
||||||
link P p red
|
link P p red
|
||||||
infinity Γ g green
|
infinity Γ g green
|
||||||
|
|
|
@ -19,7 +19,7 @@ common warnings
|
||||||
executable parabox
|
executable parabox
|
||||||
import: warnings
|
import: warnings
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
other-modules: Rendering, Model, Parser
|
other-modules: Rendering, Model, Parser, BigFont
|
||||||
-- other-modules:
|
-- other-modules:
|
||||||
default-extensions: ImportQualifiedPost, BlockArguments, LambdaCase
|
default-extensions: ImportQualifiedPost, BlockArguments, LambdaCase
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user