haskell - 使用方向移动的文字冒险游戏问题
问题描述
我在 Haskell 的地图上移动时遇到问题。如果玩家的输入是 eg BackOff
,我需要将当前位置更改为新位置,但我还需要检查是否有位置。
我不确定如何编写move
函数。我还想向玩家展示他们可以从当前位置移动到的位置(一次只能移动一个空间。)
我的第一个想法是检查输入是否是TurnLeft
例如,然后减少Direction
以使其达到West
(我假设我将其编程错误)并增加以使其达到East
等等。
如何检查玩家想要旅行的位置是否可用,然后如何更改位置?
location = "Fort Neugrad" -- the player starts in Fort Neugrad first
currentDirection = North -- the player faces north at first
data Direction = North | East | South | West deriving(Show, Eq, Enum)
data Movement = TurnLeft | TurnRight | Advance | BackOff deriving(Show)
type Location = String
type GameMap = [((Location, Direction), Location)] -- First location is the current location, second is the next location where the direction points to(Ive made a map but its to large to post it)
--move :: Movement -> Direction -> Location
--move m = case m of TurnLeft -> pred currentDirection
-- TurnRight -> succ currentDirection
-- Advance ->
-- BackOff ->
filterAccess :: Location -> [Location]
filterAccess l = [ c | ((a,b), c) <- wonderland, a == l ]
解决方案
我在你的设计中看到的第一件事是你有全局常量location
和currentDirection
. 这与 Haskell 的工作方式不兼容:因为 Haskell 是纯函数式的,你永远无法更改location
或currentDirection
. 相反,你需要类似的东西
data Player = Player { location :: Location
, direction :: Direction }
deriving (Eq, Ord, Show, Read)
然后你会想要move
类型
move :: Player -> Movement -> Player
要注意的第二件事是你给出move
了 type Movement -> Direction -> Location
,但实际上你并没有给它一个Movement
和一个Direction
参数——你只给了它一个参数,the Movement
。相反,我们想要类似的东西
move :: Player -> Movement -> Player
move p m = case m of {- ... -}
请注意代码中没有的额外p
参数。
现在,我喜欢使用pred
和succ
用于转动的概念!不幸的是,问题在于,如果它们溢出,而不是环绕pred
,succ
会引发错误,所以我们需要自己编写。
turnRight :: Direction -> Direction
turnRight North = East
turnRight East = South
turnRight South = West
turnRight West = North
turnLeft :: Direction -> Direction
turnLeft North = West
turnLeft East = North
turnLeft South = East
turnLeft West = South
在这里,我使用了“等式风格”,而不是turnLeft d = case d of ...
. 它更常见,但两者是等价的。
所以,在 中move
,我们有
move :: Player -> Movement -> Player
move p m = case m of
TurnLeft -> p{direction = turnLeft $ direction p}
TurnRight -> p{direction = turnRight $ direction p}
Advance -> undefined
BackOff -> undefined
(在这里,我切换回“表情风格”,用case
. 再次,同样的事情!)
现在,为了前进和后退,我假设您正在使用wonderland
类型为GameMap
and的值filterAccess
。 GameMap
有点可疑:如果你想要它,最好使用普通的三元组(Location, Direction, Location)
而不是嵌套对。现在,filterAccess
它有点狡猾,因为它只检查起始位置而忽略方向。但更好的设计可能是使用 real Map
,它可以让您直接按键查找。确保你添加Ord
到你的派生类中Direction
,然后你就可以拥有
import Data.Map (Map)
import qualified Data.Map as M
type GameMap = Map Location (Map Direction Location)
-- Or `Map (Location, Direction) Location`
nextLocation :: Player -> GameMap -> Maybe Direction
nextLocation Player{location = loc, direction = dir} gmap =
case M.lookup loc gmap of
Nothing -> Nothing
Just m' -> M.lookup dir m'
-- Or:
-- nextLocation Player{location = loc, direction = dir} gmap =
-- M.lookup dir =<< M.lookup loc gmap
这应该填补进展中的情况。后退情况类似,您只需要填写“向后方向”逻辑:-)
推荐阅读
- python - discord.py 如何制作 requirements.txt
- javascript - 我需要帮助将 jquery 转换为普通的 javascript
- r - xaringan中的“增量方程”?
- javascript - Dropbox Api 教程“错误:找不到模块”
- java - Java 覆盖泛型方法
- windows - 运行程序时触发程序兼容性助手的原因
- python - TypeError: unhashable type: 'numpy.ndarray' 尝试将两个 numpy.ndarrays 转换为字典时
- javascript - 为来自特定站点的访问者显示特定内容
- html - 我应该总是在
- html - 将 facebook 图标向左移动