Skip to content

Commit

Permalink
Transform user input into Game
Browse files Browse the repository at this point in the history
  • Loading branch information
grancalavera committed Feb 15, 2019
1 parent d6e7e91 commit a00d884
Show file tree
Hide file tree
Showing 13 changed files with 393 additions and 92 deletions.
79 changes: 71 additions & 8 deletions lib/Labyrinth/Game.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,84 @@ module Labyrinth.Game
, PlayOrder(..)
, Game(..)
, Configuration
, Position
, defaultGame
)
where

import Lens.Micro.TH ( makeLenses )
import qualified Data.Set as Set
import Data.Set ( Set )
import Linear.V2 ( V2(..) )

import Labyrinth.Game.Position ( Position )
import Labyrinth.Game.Board ( Board )
import Labyrinth.Game.Cell ( TileCell
, GateCell
)
import Labyrinth.Game.Treasure ( TreasureMap )
import Data.Map.Strict ( Map )
import Labyrinth.Game.Direction ( Direction(..) )
import Labyrinth.Game.Player ( Player(..)
, Players
, Color(..)
, PlayOrder(..)
)
import qualified Labyrinth.Game.Treasure as T
import Labyrinth.Game.Configuration ( Configuration )
import Labyrinth.Game.Class ( Game(..) )
import Labyrinth.Game.Class ( Game(..) )
import qualified Labyrinth.Game.Board as Board
import Labyrinth.Game.Board ( Board(..) )
import qualified Labyrinth.Game.Cell as Cell
import Labyrinth.Game.Cell ( Terrain(..)
, GateCell(..)
)
import Labyrinth.Game.NewGame ( HasTreasure
, TileD
, newGame
)

defaultGame :: Players -> IO (Maybe Game)
defaultGame players =
newGame tiles gates players 9 9 T.treasures extraTilePosition positions

gates :: Board GateCell
gates = Board.fromList $ map
(\(p, d) -> (p, Cell.mkCell Gate d (GateCell True)))
[ (V2 0 2, South)
, (V2 0 4, South)
, (V2 0 6, South)
, (V2 2 0, East)
, (V2 4 0, East)
, (V2 6 0, East)
, (V2 2 8, West)
, (V2 4 8, West)
, (V2 6 8, West)
, (V2 8 2, North)
, (V2 8 4, North)
, (V2 8 6, North)
]

tiles :: [TileD HasTreasure PlayOrder]
tiles =
[ (Corner, Just (V2 1 1), Just South, False, Just First)
, (Corner, Just (V2 1 7), Just West , False, Just Second)
, (Corner, Just (V2 7 1), Just East , False, Just Third)
, (Corner, Just (V2 7 7), Just North, False, Just Fourth)
, (Fork , Just (V2 1 3), Just South, True , Nothing)
, (Fork , Just (V2 1 5), Just South, True , Nothing)
, (Fork , Just (V2 3 1), Just East , True , Nothing)
, (Fork , Just (V2 5 1), Just East , True , Nothing)
, (Fork , Just (V2 3 7), Just West , True , Nothing)
, (Fork , Just (V2 5 7), Just West , True , Nothing)
, (Fork , Just (V2 7 3), Just North, True , Nothing)
, (Fork , Just (V2 7 5), Just North, True , Nothing)
, (Fork , Just (V2 3 3), Just East , True , Nothing)
, (Fork , Just (V2 5 3), Just North, True , Nothing)
, (Fork , Just (V2 3 5), Just South, True , Nothing)
, (Fork , Just (V2 5 5), Just West , True , Nothing)
]
<> replicate 12 (Path , Nothing, Nothing, False, Nothing)
<> replicate 6 (Corner, Nothing, Nothing, True , Nothing)
<> replicate 10 (Corner, Nothing, Nothing, False, Nothing)
<> replicate 6 (Fork , Nothing, Nothing, True , Nothing)

positions :: Set Position
positions =
Set.fromList $ extraTilePosition : [ V2 x y | x <- [1 .. 7], y <- [1 .. 7] ]

extraTilePosition :: Position
extraTilePosition = V2 0 2
5 changes: 5 additions & 0 deletions lib/Labyrinth/Game/Board.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
module Labyrinth.Game.Board
( Board(..)
, fromList
)
where

import Data.Map.Strict ( Map )
import qualified Data.Map.Strict as Map
import Labyrinth.Game.Position ( Position )
import Labyrinth.Game.Cell ( Cell )

newtype Board a = Board { toMap :: Map Position (Cell a)} deriving (Show)

fromList :: [(Position, (Cell a))] -> Board a
fromList = Board . Map.fromList
6 changes: 5 additions & 1 deletion lib/Labyrinth/Game/Cell.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Labyrinth.Game.Cell
, TileCell(..)
, GateCell(..)
, CellData(..)
, Terrain
, Terrain(..)
, treasure
, players
, isOpen
Expand All @@ -15,6 +15,7 @@ module Labyrinth.Game.Cell
, randomRotate
, hasExit
, connected
, mkCell
)
where

Expand Down Expand Up @@ -53,6 +54,9 @@ data Cell a = Cell
type Exits = Set Direction
makeLenses ''Cell

mkCell :: Terrain -> Direction -> a -> Cell a
mkCell t dir d = Cell t dir (CellData d)

exits :: Cell a -> Exits
exits t = Set.fromList $ case (t ^. terrain, t ^. direction) of

Expand Down
4 changes: 2 additions & 2 deletions lib/Labyrinth/Game/Configuration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import qualified Data.Set as Set
import qualified Labyrinth.Game.Player as P
import Labyrinth.Game.Player ( Players
, Player
, PlayOrder(First)
, PlayOrder
, Color
)

Expand Down Expand Up @@ -64,4 +64,4 @@ availableColors ps = Set.toList available
taken = Set.fromList $ map (^. P.color) (toList ps)

firstPlayer :: Configuration -> Maybe Player
firstPlayer = (`playerAt` First)
firstPlayer = P.first . (^. players)
147 changes: 113 additions & 34 deletions lib/Labyrinth/Game/NewGame.hs
Original file line number Diff line number Diff line change
@@ -1,61 +1,140 @@
module Labyrinth.Game.NewGame
( NewGame
( TileD
, HasTreasure
, availablePositions
, addPositions
, addPlayers
, chooseDirections
, addTreasures
, newGame
, resolveUnassignedPositions
, resolveDirection
)
where

import Control.Monad ( guard
, forM
)
import Data.List ( partition )
import Data.Set ( Set )
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.Map ( (!?) )
import Data.Maybe ( fromJust
, isJust
)

import Lens.Micro ( _1
, _2
, _3
, _4
, _5
, (^.)
, (.~)
, (?~)
, (&)
)
import qualified Data.Random as Random
import Labyrinth.Game.Board ( Board(..) )
import Labyrinth.Game.Cell ( Terrain
, Cell(..)
, TileCell(..)
, GateCell
, mkCell
)
import Labyrinth.Game.Position ( Position )
import Labyrinth.Game.Treasure ( Treasure )
import qualified Labyrinth.Game.Direction as D
import Labyrinth.Game.Direction ( Direction )
import Labyrinth.Game.Player ( Players )
import Labyrinth.Game.Class ( Game )

type AddTreasure = Bool
type CellD = (Terrain, Maybe Position, Maybe Direction, AddTreasure, Players)
type ResolvedCellD = (Terrain, Position, Direction, Maybe Treasure, Players)
type GateD = (Position, GateCell)

data NewGame = NewGame
{ cells :: [CellD]
, gates :: [GateD]
, players :: Players
, rowCount :: Int
, colCount :: Int
, treasures :: [Treasure]
, extraTile :: Position
, positions :: Set Position
} deriving (Show)
import Labyrinth.Game.Player ( Players
, Player
, PlayOrder(First)
)
import Labyrinth.Game.Class ( Game(..) )

type HasTreasure = Bool
type TileD a b = (Terrain, Maybe Position, Maybe Direction, a, Maybe b)

newGame
:: [CellD]
-> [GateD]
:: [TileD HasTreasure PlayOrder]
-> Board GateCell
-> Players
-> Int
-> Int
-> [Treasure]
-> Position
-> Set Position
-> IO (Maybe Game)
newGame cells gates players rowCount colCount treasures extraTile positions =
undefined
newGame tiles gates players rows cols treasures extraTile positions = do

let aPosList =
availablePositions positions $ Set.fromList $ map (^. _2) tiles

shufPos <- Random.shuffle aPosList
shufTre <- Random.shuffle treasures
tilesWithDirection <- chooseDirections tiles

return
$ addPlayers players tilesWithDirection
>>= addPositions shufPos
>>= addTreasures shufTre
>>= traverse mkTile
>>= \ts -> players !? First >>= \playing -> do
let cellBoard = Board $ Map.fromList ts
Just $ Game { _players = players
, _playing = playing
, _extraTile = extraTile
, _rowCount = rows
, _colCount = cols
, _tiles = cellBoard
, _gates = gates
, _treasures = mempty
}

mkTile :: TileD (Maybe Treasure) Player -> Maybe (Position, Cell TileCell)
mkTile t = do
let terrain = t ^. _1
mTreasure = t ^. _4

position <- t ^. _2
direction <- t ^. _3
player <- t ^. _5

let cellData = TileCell mTreasure (Set.fromList [player])
cell = mkCell terrain direction cellData
return (position, cell)

availablePositions :: Set Position -> Set (Maybe Position) -> [Position]
availablePositions p mp =
Set.toList $ Set.map fromJust $ Set.difference (Set.map Just p) mp

addPlayers :: Players -> [TileD a PlayOrder] -> Maybe [TileD a Player]
addPlayers ps ts = do
guard (sameLength && uniqOrders)
traverse (addPlayer ps) addP >>= Just . (map (_5 .~ Nothing) addNothing <>)
where
(addP, addNothing) = partition (isJust . (^. _5)) ts
sameLength = length addP == Map.size ps
uniqOrders = length addP == Set.size (Set.fromList orders)
orders = map (fromJust . (^. _5)) addP

addPlayer :: Players -> TileD a PlayOrder -> Maybe (TileD a Player)
addPlayer ps t = t ^. _5 >>= (ps !?) >>= Just . (\p -> t & _5 ?~ p)

addPositions :: [Position] -> [TileD a b] -> Maybe [TileD a b]
addPositions ps ts = do
guard (length ps == length needsP)
Just $ hasP <> zipWith (_2 ?~) ps needsP
where (hasP, needsP) = partition (isJust . (^. _2)) ts

chooseDirections :: [TileD a b] -> IO [TileD a b]
chooseDirections ts = forM ts $ \t -> do
d <- chooseDirection (t ^. _3)
return $ t & _3 ?~ d

resolveUnassignedPositions
:: Set Position -> Set (Maybe Position) -> Set Position
resolveUnassignedPositions p mp =
Set.map fromJust $ Set.difference (Set.map Just p) mp
addTreasures
:: [Treasure] -> [TileD HasTreasure b] -> Maybe [TileD (Maybe Treasure) b]
addTreasures trs tls = do
guard (length withT == length trs)
Just $ map (_4 .~ Nothing) noT <> zipWith (_4 ?~) trs withT
where (withT, noT) = partition (^. _4) tls

resolveDirection :: Maybe Direction -> IO Direction
resolveDirection md | isJust md = return $ fromJust md
| otherwise = D.random
chooseDirection :: Maybe Direction -> IO Direction
chooseDirection md | isJust md = return $ fromJust md
| otherwise = D.random
17 changes: 14 additions & 3 deletions lib/Labyrinth/Game/Player.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Labyrinth.Game.Player
module Labyrinth.Game.Player
( Player(..)
, Color(..)
, PlayOrder(..)
Expand All @@ -9,12 +9,17 @@ module Labyrinth.Game.Player
, colors
, count
, toList
, fromList
, first
)
where

import Lens.Micro.TH ( makeLenses )
import Lens.Micro ( (^.) )
import qualified Data.Map.Strict as Map
import Data.Map.Strict ( Map )
import Data.Map.Strict ( (!?)
, Map
)
import Data.Text ( Text )

data Color = Yellow | Red | Blue | Green deriving (Show, Eq, Ord, Enum)
Expand All @@ -25,7 +30,7 @@ data Player = Player
{ _name :: Text
, _color :: Color
, _order :: PlayOrder
} deriving (Show, Eq)
} deriving (Show, Eq, Ord)
makeLenses ''Player

colors :: [Color]
Expand All @@ -36,3 +41,9 @@ count = Map.size

toList :: Players -> [Player]
toList = map snd . Map.toList

fromList :: [Player] -> Players
fromList = Map.fromList . map (\p -> (p ^. order, p))

first :: Players -> Maybe Player
first = (!? First)
1 change: 0 additions & 1 deletion lib/Labyrinth/Game/Treasure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import qualified Data.Set as Set
import Data.Set ( Set )
import Lens.Micro.TH ( makeLenses )
import Lens.Micro ( (^.) )
import qualified Data.Random as Random

data Treasure = TA | TB | TC | TD | TE | TF
| TG | TH | TI | TJ | TK | TL
Expand Down
9 changes: 1 addition & 8 deletions lib/Labyrinth/Store/Event/Modal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import Data.Map.Strict ( Map
, (!?)
)
import Data.Maybe ( fromMaybe )
import Labyrinth.UI ( Name
, ModalCallback
)
import Labyrinth.UI ( Name )
import Labyrinth.UI.Modal ( dialog
, onTrue
, onFalse
Expand Down Expand Up @@ -66,8 +64,3 @@ promptToQuit store _ = showModal store $ mkModal
eventMap :: Ord e => Map (BrickEvent Name e) (GlobalEventHandler e)
eventMap =
Map.fromList [(VtyEvent (V.EvKey (V.KChar 'q') [V.MCtrl]), promptToQuit)]

hideModalAnd :: ModalCallback Store e -> ModalCallback Store e
hideModalAnd f store = f $ store & modals %~ \case
[] -> []
(_ : ms) -> ms
Loading

0 comments on commit a00d884

Please sign in to comment.