gpt4 book ai didi

Haskell:为 GUI 建模在线游戏状态

转载 作者:行者123 更新时间:2023-12-04 20:55:26 25 4
gpt4 key购买 nike

我正在为在线游戏编写客户端 UI。它的结构是一个表示游戏状态的模型模块和一个 View 模块,它跟踪当前的游戏状态并使用模型转换更新它,即从一种状态到另一种状态的函数。为了利用静态类型检查,我将状态建模为具有表示共同特征的类型类的不同类型:

class Erring s where errors :: s -> [String]
class WithPlayers s where players :: s -> [String]
class Erring s => LoggedIn s

data LoggedOut = LoggedOut [String] deriving (Eq, Show)
instance Erring LoggedOut where errors (LoggedOut es) = es

data Ready = Ready [String] [String] deriving (Eq, Show)
instance Erring Ready where errors (Ready _ es) = es
instance LoggedIn Ready
instance WithPlayers Ready where players (Ready ps _) = ps

data NotReady = NotReady [String] [String] deriving (Eq, Show)
instance Erring NotReady where errors (NotReady _ es) = es
instance LoggedIn NotReady
instance WithPlayers NotReady where players (NotReady ps _) = ps

-- some transitions:

login :: String -> LoggedOut -> Either Ready LoggedOut
login pwd (LoggedOut es) =
if pwd == "password" then Left $ Ready [] es
else Right $ LoggedOut (es ++ ["incorrect password"])

logout :: LoggedIn s => s -> LoggedOut
logout s = LoggedOut $ errors s

当有几十个状态和实例要定义但会产生一个健壮的 API 时,这可能有点乏味。

输入 View 。为了存储我想使用的状态 TMVar ,以便 UI 线程和来自服务器的处理消息的线程都可以执行状态转换。由于每个状态都是不同的类型,我创建了一个可以表示每种可能状态的新类型:
data SessionState = SSLoggedOut LoggedOut
| SSReady Ready
| SSNotReady NotReady

现在可以定义 TMVar SessionState 类型的状态引用.

现在,这感觉不太对劲。我实际上必须将每个状态定义两次,一次作为类型,另一次作为包装此类型的类型构造函数。所以,问题:
  • 以这种方式对游戏状态进行建模是否合理?
  • 将状态值保留在 TMVar 中是否合理?如果需要不同线程的原子更新,还是有更好的方法来跟踪状态?
  • 如果 TMVar是正确的方法,那么是否有必要拥有像 SessionState 这样的东西包装器定义?
  • 最佳答案

    我花了一分钟才明白为什么 LoggedInLoggedOut 时的类是数据,但是...

  • 是的,我认为这是一个合理的模型。
  • 是的,TVar是做到这一点的最好方法。我假设你知道组合子 atomically
  • 是的,阿法克。见下一段。

  • 如果您想要类型检查和同步 TMVar,那么您需要定义类型(用于类型检查)和数据包装器(用于 TMVar)。我看不出有什么办法;据我所知,TMVar 必须保持相同的类型。 (如我错了请纠正我!)

    如果是我,我会放弃类型,而是使用函数和守卫。
    data SessionState = Ready {errors :: [String], players :: [String]}
    | NotReady {errors :: [String], players :: [String]}
    | LoggedOut {errors :: [String]}
    deriving (Eq, Show, Ord)

    loggedIn :: SessionState -> Bool
    loggedIn (LoggedOut _) = False
    loggedIn _ = True

    ready :: SessionState -> Bool
    ready (Ready _ _) = True
    ready _ = False

    addError :: SessionState -> String -> SessionState
    addError s e = s {errors = e:errors s}

    addPlayer :: SessionState -> String -> SessionState
    addPlayer s@(LoggedOut _) p = addError s $ "Can't add " ++ p ++ " when logged out"
    addPlayer s p = s {players = p:players s}

    这里有一些简单的函数,您可以使用它们从一种状态转移到另一种状态。我试图给出使用守卫和使用模式匹配的例子;你可以选择你更喜欢的风格,或者像我一样混合:
    login :: SessionState -> SessionState
    login (LoggedOut es) = NotReady es []
    login s = addError s "Can't log in when already logged in"

    logout :: SessionState -> SessionState
    logout s
    | loggedIn s = LoggedOut $ errors s
    | otherwise = addError s "Can't log out when not logged in"

    enable :: SessionState -> SessionState
    enable (NotReady es ps) = Ready es ps
    enable s@(LoggedOut _) = addError s "Can't enable when logged out"
    enable s@(Ready _ _ ) = addError s "Can't enable when already ready"

    disable :: SessionState -> SessionState
    disable s
    | ready s = NotReady (errors s) (players s)
    | otherwise = addError s "Can't disable when not ready"

    还有一个使用 loggedIn 的愚蠢示例函数功能:
    countPlayers :: SessionState -> (SessionState, Maybe Int)
    countPlayers s
    | loggedIn s = (s, Just . length $ players s)
    | otherwise = (addError s "Can't count players whilst logged out", Nothing)

    这种方法通过编译器的类型安全性较低,但仍然非常可读,并且作为额外的好处是灵活的。这是我在 ghci 中摆弄:
    *Main> LoggedOut []
    LoggedOut {errors = []}
    *Main> login it
    NotReady {errors = [], players = []}
    *Main> enable it
    Ready {errors = [], players = []}
    *Main> addError it "Illegal somethingorother"
    Ready {errors = ["Illegal somethingorother"], players = []}
    *Main> logout it
    LoggedOut {errors = ["Illegal somethingorother"]}
    *Main> disable it
    LoggedOut {errors = ["Can't disable when not ready","Illegal somethingorother"]}

    关于Haskell:为 GUI 建模在线游戏状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5293469/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com