Pregunta

Así que estoy trabajando en una implementación de minimax para un juego tipo damas para ayudarme a aprender mejor a Haskell. La función con la que tengo problemas toma una lista de estados de juego y genera la lista de estados de juego sucesores inmediatos. Al igual que las damas, si hay un salto disponible, el jugador debe tomarlo. Si hay más de uno, el jugador puede elegir.

En su mayor parte, esto funciona muy bien con la lista mónada: recorre todos los estados del juego de entrada, recorre todas las canicas que podrían saltar, recorre todos los saltos de esa canica. Esta lista de mónadas aplana muy bien todas las listas en una simple lista de estados al final.

El truco es que, si no se encuentran saltos para un estado de juego dado, necesito devolver el estado del juego actual, en lugar de la lista vacía. El siguiente código es la mejor forma en que se me ocurre hacer eso, pero me parece realmente feo. ¿Alguna sugerencia sobre cómo limpiarlo?

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 []

EDITAR: proporcione firmas de tipo de ejemplo para las funciones * Hex.

¿Fue útil?

Solución

  

El truco es que, si no se encuentran saltos para un estado de juego determinado, necesito devolver el estado del juego actual, en lugar de la lista vacía.

¿Por qué? He escrito minimax varias veces, y no puedo imaginar un uso para tal función. ¿No estaría mejor con una función de tipo

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

o

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

Sin embargo, si realmente desea devolver " o la lista de estados siguientes, o si esa lista está vacía, el estado original " ;, entonces el tipo que desea es

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

que luego puedes aplanar fácilmente.

En cuanto a cómo implementar, recomiendo definir una función auxiliar de tipo

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

y de lo que puedes mapear

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

sobre el resultado, además de varias otras cosas.

Como dijo Fred Brooks (parafraseando), una vez que obtienes los tipos correctos, el código prácticamente se escribe solo.

Otros consejos

No abuses de la notación de mónadas para la lista, es muy pesado para nada. Además, puede usar la comprensión de listas de la misma manera:

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

ahora para la 'simplificación'

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)

La comprensión de la lista de entrada en la parte superior me molesta un poco, pero como no tengo todo el código, realmente no sé cómo hacerlo de otra manera. Si puede modificar más en profundidad, le sugiero que use más combinadores (map, foldr, foldl ', etc.) ya que en mi experiencia realmente reducen el tamaño del código.

Nota, el código no se prueba y puede no compilarse.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top