Question

Je travaille donc sur une implémentation minimax pour un jeu de type damier afin de m'aider à mieux apprendre Haskell. La fonction avec laquelle je rencontre des problèmes prend une liste des états de jeu et génère la liste des états de jeu suivants. Comme les pions, si un saut est disponible, le joueur doit le prendre. S'il y en a plus d'un, le joueur peut choisir.

Généralement, cela fonctionne bien avec la liste monad: boucle sur tous les états du jeu en entrée, boucle sur toutes les billes pouvant être sautées, boucle sur tous les sauts de cette bille. Cette liste monade aplatit joliment toutes les listes en une simple liste d’états à la fin.

Le truc, c'est que si aucun saut n'est trouvé pour un état de jeu donné, je dois retourner l'état actuel du jeu plutôt que la liste vide. Le code ci-dessous est la meilleure façon de le faire, mais il me semble vraiment moche. Des suggestions sur la façon de le nettoyer?

eHex :: Coord -> Coord -- Returns the coordinates immediately to the east on the board
nwHex :: Coord -> Coord -- Returns the coordinates immediately to the northwest on the board

generateJumpsIter :: [ZertzState] -> [ZertzState]
generateJumpsIter states = do
    ws <- states
    case children ws of
      [] -> return ws
      n@_ -> n
  where 
    children ws@(ZertzState s1 s2 b p) = do
      (c, color)  <- occupiedCoords ws
      (start, end) <- [(eHex, wHex), (wHex, eHex), (swHex, neHex),
                       (neHex, swHex), (nwHex, seHex), (seHex, nwHex)]
      if (hexOccupied b $ start c) && (hexOpen b $ end c)
        then case p of
          1 -> return $ ZertzState (scoreMarble s1 color) s2
                                   (jumpMarble (start c) c (end c) b) p
          (-1) -> return $ ZertzState s1 (scoreMarble s2 color)
                                      (jumpMarble (start c) c (end c) b) p
        else []

EDIT: fournit des exemples de signatures de type pour les fonctions * Hex.

Était-ce utile?

La solution

  

Le truc, c'est que, si aucun saut n'est trouvé pour un état de jeu donné, je dois retourner l'état actuel du jeu plutôt que la liste vide.

Pourquoi? J'ai écrit minimax plusieurs fois et je ne peux imaginer un usage pour une telle fonction. Ne seriez-vous pas mieux avec une fonction de type

nextStates :: [ZertzState] -> [Maybe [ZertzState]]

ou

nextStates :: [ZertzState] -> [[ZertzState]]

Toutefois, si vous souhaitez vraiment renvoyer " soit la liste des états suivants, soit si cette liste est vide, l'état d'origine ", le type souhaité est

.
nextStates :: [ZertzState] -> [Either ZertzState [ZertzState]]

que vous pouvez ensuite aplatir assez facilement.

En ce qui concerne la mise en oeuvre, je vous recommande de définir une fonction d'assistance de type

[ZertzState] -> [(ZertzState, [ZertzState])]

et que vous pouvez mapper

(\(start, succs) -> if null succs then Left start else Right succs)

sur le résultat, ainsi que diverses autres choses.

Comme Fred Brooks l’a dit (en paraphrasant), une fois que vous avez bien saisi les types, le code s’écrit presque tout seul.

Autres conseils

Ne pas abuser de la notation monads pour la liste, elle est si lourde pour rien. De plus, vous pouvez utiliser la compréhension de liste de la même manière:

do x <- [1..3]
   y <- [2..5]      <=>  [ x + y | x <- [1..3], y <- [2..5] ]
   return x + y

maintenant pour la 'simplification'

listOfHex :: [(Coord -> Coord,Coord -> Coord)]
listOfHex = [ (eHex, wHex), (wHex, eHex), (swHex, neHex)
            , (neHex, swHex), (nwHex, seHex), (seHex, nwHex)]

generateJumpsIter :: [ZertzState] -> [ZertzState]
generateJumpsIter states =
    [if null ws then ws else children ws | ws <- states]
  where -- I named it foo because I don t know what it do....
    foo True   1  = ZertzState (scoreMarble s1 color) s2
                               (jumpMarble (start c) c (end c) b) p
    foo True (-1) = ZertzState s1 (scoreMarble s2 color)
                               (jumpMarble (start c) c (end c) b) p
    foo False  _  = []
    foo _ _ = error "Bleh"

    children ws@(ZertzState s1 s2 b p) =
      [ foo (valid c hex) p | (c, _)  <- occupiedCoords ws, hex <- listOfHex ]
        where valid c (start, end) =
                 (hexOccupied b $ start c) && (hexOpen b $ end c)

L’approche let in de la liste let in en haut me gêne un peu, mais comme je n’ai pas tout le code, je ne sais pas vraiment comment le faire d’une autre manière. Si vous pouvez modifier plus en profondeur, je vous suggère d’utiliser davantage de combinateurs (map, foldr, foldl ', etc.) car ils réduisent réellement la taille du code, selon mon expérience.

Remarque, le code n'est pas testé et ne peut pas être compilé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top