Pergunta

Então, eu estou trabalhando em uma implementação minimax por damas-como o jogo para me ajudar aprender Haskell melhor. A função que eu estou tendo problemas com recebe uma lista de estados de jogo, e gera a lista de estados de jogo sucessor imediato. Como damas, se um salto está disponível, o jogador deve tomá-lo. Se houver mais de um, o jogador pode escolher.

Para a maior parte, isso funciona muito bem com a lista mônada: loop sobre todos os estados do jogo de entrada, um loop sobre todos os mármores que poderia ser um salto, laço sobre todos os saltos de que o mármore. Esta lista mônada bem achata todas as listas fora em uma simples lista de estados no final.

O truque é que, se há saltos são encontrados para um determinado estado do jogo, eu preciso voltar o estado do jogo atual, em vez de uma lista vazia. O código abaixo é a melhor maneira que eu vim acima com de fazer isso, mas parece realmente feio para mim. Todas as sugestões sobre como limpá-lo?

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:. Fornecer assinaturas exemplo de tipo para as funções * Hex

Foi útil?

Solução

O truque é que, se há saltos são encontrados para um determinado estado do jogo, eu preciso voltar o estado do jogo atual, em vez de uma lista vazia.

Por quê? Eu escrevi minimax várias vezes, e eu não posso imaginar um uso para tal função a. você não seria melhor fora com uma função do tipo

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

ou

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

No entanto, se você realmente quer retorno "ou a lista de próximos estados, ou se essa lista estiver vazia, o estado original", em seguida, o tipo que você quer é

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

que você pode então achatar com bastante facilidade.

Quanto à forma de implementar, eu recomendo a definição de uma função auxiliar do tipo

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

e do que você pode mapear

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

sobre o resultado, além de várias outras coisas.

Como Fred Brooks disse (parafraseando), uma vez que você obter os tipos de direito, o código praticamente se escreve.

Outras dicas

Não abuse monads notação para lista, é tão pesado para nada. Além disso, você pode usar compreensão da lista da mesma forma:

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

Agora, para a 'simplificação'

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)

O deixar entrar a deixar na lista commprehension no topo me incomoda um pouco, mas como eu não tenho todo o código, eu realmente não sei como fazê-lo em uma outra maneira. Se você pode modificar mais em profundidade, eu sugiro que você use mais combinadores (mapa, foldr, foldl' etc) como elas realmente reduzir o tamanho do código na minha experiência.

Note, o código não é testado, e pode não ser compilado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top