首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Haskell的游戏中,我将如何表示级别/场景?

在Haskell的游戏中,我将如何表示级别/场景?
EN

Stack Overflow用户
提问于 2022-07-07 07:40:38
回答 2查看 161关注 0票数 4

问题所在

我正在做一个文字冒险游戏,作为一个业余项目来教自己一些新的Haskell概念。

现在,我遇到了一个挑战,就是如何表示游戏中的各个级别(或“场景”)以及它们之间的各种连接方式。为了让自己保持简单,我把游戏的“地图”想象成一个简单的2d空间,其中的场景通过基本方向(NESW)连接起来:

代码语言:javascript
复制
        Lake
        ⇳
        Forest
        ⇳
Home  ⬄ Field*

*: Starting location

在这里,从湖边往南走会带你到森林,反之亦然;从田野往西走会带你到家。这里的挑战是,--我需要某种方法来编码不仅连接了哪些场景,而且还需要 how 它们是如何连接的E 210,其中'how‘指的是一个基本方向。

到目前为止,我考虑的两个选项是将级别表示为图或使用元组列表,但我对这两种方法并不完全满意。

将场景表示为图

我用图形表示场景及其关联的基本方法如下:

代码语言:javascript
复制
data Scene = InitialField | Forest | House | Lake

-- |`gameScenes` maps scenes to their integer representation, as used in `sceneGraph`.
gameScenes :: Map Int Scene
gameScenes =
    let scenes =
            [ (0, InitialField)
            , (1, Forest)
            , (2, House)
            , (3, Lake)
            ]
    in
        fromList scenes

-- |the `sceneGraph` describes the way different scenes of the game connect to each other.
sceneGraph :: Graph
sceneGraph =
    let
        bounds = (0, 3)
        edges =
            [ (0, 1) -- link initial field to forest
            , (0, 2) -- link initial field to house
            , (1, 3) -- link forest to lake
            ]
    in
        buildG bounds edges

缺点:这里的主要限制是这个图没有编码任何关于基数方向的信息。这是不幸的,因为除了这个限制之外,图似乎是表示场景(顶点)及其连接(边)的完美数据结构。有没有办法编码图中边的‘元数据’(在本例中是基数)?

使用元组列表表示场景

当我遇到上述限制时,我决定尝试一种不同的方法,并将场景之间的链接表示为元组列表:

代码语言:javascript
复制
data Scene = InitialField | Forest | House | Lake
data CardinalDirection = North | East | South | West
type LinkedScene = (CardinalDirection, Scene)

-- |`linkedScenes`, applied to a `Scene`, returns a list of the connected scenes and their cardinal directions.
linkedScenes :: Scene -> [LinkedScene]
linkedScenes InitialField = [(North, Forest)]
linkedScenes Forest = [(South, InitialField), (West, Lake)]
-- The other links are left as an exercise for the reader ;)
linkedScenes _ = []

缺点:这种方法确实允许我们通过将sceneLinks应用到玩家当前所在的Scene中来对不同场景之间的联系进行编码,但它有一个巨大的、丑陋的缺点:它要求我们对场景之间的空间关联进行双端编码。换句话说,如果我们知道森林位于字段的北面,我们需要编写两个函数:一个接受Forest并生成[(South, InitialField)],另一个反函数获取InitialField并生成[(North, Forest)]。这似乎是在乞求bug:如果我想要添加一个场景,或者改变游戏世界的布局,我需要记住要仔细检查来自两端的每一个链接。

总结:要求

理想情况下,我正在寻找一种方法:

  • 允许我使用单个数据点来编码场景之间的双向关系(在第二种方法中没有“双端”编码,因为这是要求bug);
  • 允许我轻松地改变游戏/地图的布局在稍后阶段,没有一个巨大的头痛;
  • 保证在编译时在空间上是一致的,这意味着它不允许无效的空间配置,例如玩家从场上开始,向北到森林,返回南方,突然发现自己在湖里的状态。但是,我不确定如果没有依赖类型,这是可能的。

如果有人能想到这样的方法,一定是Haskell社区的人:)

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-07 12:41:18

从描述一些连接的三元组开始:

代码语言:javascript
复制
data Scene = Field | Forest | House | Lake
data Dir = N | E | S | W
type Edge = (Scene, Dir, Scene)

uniEdges :: [Edge]
uniEdges = [(Field, N, Forest), (Forest, W, Lake)]

通过反转所有元组展开到完整的映射:

代码语言:javascript
复制
class Dual a where dual :: a -> a
instance Dual Dir where
    dual N = S
    dual E = W
    dual S = N
    dual W = E
instance Dual Edge where dual (s, d, s') = (s', dual d, s)
instance Dual a => Dual [a] where dual = map dual

allEdges :: [Edge]
allEdges = uniEdges ++ dual uniEdges

然后将这些插入到您喜欢的任何数据结构中;Map Scene (Dir, Scene)Gr或其他什么。

这种方法的一个很好的特性是:它使您能够在不改变场景图的所有用户的情况下,稍后决定不是所有的边缘都应该自己打开,就像这张带有弯曲路径的地图:

代码语言:javascript
复制
House
  |
   \
    `--Lake
票数 1
EN

Stack Overflow用户

发布于 2022-07-07 10:00:24

我认为有两种选择:

  1. 使用简单的图形,但另外将场景嵌入到一个二维空间中。然后,从任何给定的点,图告诉你哪些其他场景是相邻的,通过向量空间的差异,你可以得到方向。 这很容易可视化和实现。缺点是它引入了一个绝对的参考框架,这意味着您可以将两个本地设计的场景组连接在一起,但首先需要翻译它们以避免重叠。而且,这是一种无聊和排除紧急非欧几里德几何.如果你对这种事感兴趣。 (请注意,通过嵌入到非平坦流形中,仍然可以得到非欧几里德几何。)在这种情况下,您可以将PseudoAffine类用于距离。)
  2. 使用元组列表,但是将其包装在您自己的类似于图形的抽象中。QuickCheck (抽象到死),并且只导出一个自动跟踪相邻节点之间的变化的接口。然后在实际游戏中,只通过抽象界面操纵场景-世界。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72893976

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档