这个问题是关于如何设计应用程序和布局数据,以表示冒险游戏中的可变状态,其中有玩家可以在的位置,以及可以在这些位置或玩家库存中的项目他们捡起来之后。
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 = ...
每个Location
拥有Item
列表可能没有意义,因为这是可变的,其他一切都是不可变的。同样适用于Player
在这样的游戏中,核心逻辑属于一个名为。
的函数playMove :: Move -> GameState -> ([MoveResult], GameState)
Move
和MoveResult
函数的位置
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
| ...
将用户输入解析为Move
值,并输出MoveResult
,这是IO monad中发生的事情。方向只是North | South | East | West
其中大多数无疑会涉及GameState
捕获
我的问题是
GameState
的良好数据结构。这样的结构应该封装玩家的位置和库存内容,以及可以在世界中找到物品的地方。它应该促进API之类的
moveTo :: GameState -> Direction -> ([MoveResult], GameState)
其中MoveResult
为EnteredLocation
或NoLocationAt
。这又需要像locationAt :: Location -> Direction -> Maybe Location
pickUp :: GameState -> ItemName -> ([MoveResult], GameState)
其中MoveResult
为PickedUpItem
或NoSuchItem
。在这种情况下,如何将ItemName
与Item
useItemWithItem :: GameState -> (ItemName, ItemName) -> ([MoveResult], GameState)
MoveResult
如果有新项目,则为PickedUpItem
,否则为CantUserItems
。这又需要像combineItems :: Item -> Item -> Maybe Item
这样的函数来查看是否可以合并项目。PlayerPosition
Location
类型还是引入一些LocationId来表示PlayerPosition
以及可能的项目位置Location
边缘将原始Location
到目标Direction
的图表映射,要使用的最佳数据结构是什么。我在想Data.Map
(Location, Direction)
到Location
。我知道拉链,以及playMove
适合State
monad的事实。我的问题是如何构造GameState
以捕获此问题的可变和不可变部分。
我确实从这个富有成效的discussion on Reddit中找到了答案。如果其他人发现了这个问题,那个讨论中的/u/achadoseperdidos指出我的问题的答案是由chapter 11 of Learn PureScript by Example提供的,它实际上描述了如何使用RWS monads编写一个冒险游戏 - 完全是答案我在寻找。
答案 0 :(得分:0)
在这种规模下,您无需担心尺寸或效率。只需使用如下记录:
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
}