How to represent and track mutable state in a text
This question is about how to design an app, and layout data, to represent mutable state in an adventure game where there are locations the player can be in, and items which can either be in those locations, or in the players inventory after they pick them up.
newtype ItemName = ItemName Text
newtype LocationName = LocationName Text
newtype Description = Description Text
new type ItemWeight = ItemWeight Int
data Location = Location LocationName Description [Item]
data Item = Item ItemName [ItemName] Description ItemWeight
data Player = Player PlayerPosition [Item]
data PlayerPosition = ...
It may not make sense for each Location to have a list of Item s, since this is mutable, and everything else is immutable. Likewise for Player
In such a game the core logic falls into a function called.
playMove :: Move -> GameState -> ([MoveResult], GameState)
where the Move and MoveResult functions are
data Move data MoveResult
= MoveTo Direction = EnteredLocation Location
| PickUpItem ItemName | NoLocationAt Direction
| UseItemWithItem ItemName ItemName | PickedUpItem Item
| Examine ItemName | UsedItemWithItem Item
| Quit | CantUseItems Item Item
| NoSuchItem Item
| Description Item
| InventoryFull ItemWeight Item
| GameWon
| ...
Parsing user input into Move values, and outputting the MoveResult s, is something that happens in the IO monad. Direction is just a sum-type over North | South | East | West North | South | East | West
Most of these will no doubt involve a GameState which captures
My question is
GameState . Such a structure should encapsulate the player's position and inventory contents, and where items may be found in the world. It should faciliate an API like moveTo :: GameState -> Direction -> ([MoveResult], GameState) where the MoveResult is either EnteredLocation or NoLocationAt . This in turn requires a function like locationAt :: Location -> Direction -> Maybe Location pickUp :: GameState -> ItemName -> ([MoveResult], GameState) where the MoveResult is PickedUpItem or NoSuchItem . In this case how does one match ItemName to an Item useItemWithItem :: GameState -> (ItemName, ItemName) -> ([MoveResult], GameState) where the MoveResult is either PickedUpItem if a new items results, or CantUserItems otherwise. This in turn requires a function like combineItems :: Item -> Item -> Maybe Item to see if items can be combined. PlayerPosition Location types or introduce some LocationId in representing the PlayerPosition and potentially the items positions Location to destination Location via a Direction edge, what is the best data-structure to use. I was thinking a Data.Map of (Location, Direction) to Location . I am aware of zippers, and the the fact that playMove fits into the State monad. My issue is how to structure GameState to capture the mutable and immutable parts of this problem.
Edit: The Answer
I did find an answer from this productive discussion on Reddit. In case anyone else finds this question, /u/achadoseperdidos in that discussion pointed out that the answer to my question is provided by chapter 11 of Learn PureScript by Example which actually describes how to use the RWS monads to write an adventure game - exactly the answer I was seeking.
At this scale, you need not worry about size or efficiency. Simply use a record like:
import qualified Data.Map as M
data Location = Location
{ locationname :: String
, description :: String
} deriving Ord
data GameStep = GameStep
{ itemsWorld :: M.Map Location [Item]
, inventory :: [Item]
, position :: Location
}
链接地址: http://www.djcxy.com/p/58770.html
上一篇: EJB 3.1依赖注入失败
下一篇: 如何在文本中表示和跟踪可变状态
