Domanda

Quindi sto lavorando a un'implementazione minimax per un gioco simile a una dama per aiutarmi a imparare meglio Haskell. La funzione con cui ho problemi prende un elenco per gli stati di gioco e genera l'elenco degli stati di gioco immediatamente successivi. Come le pedine, se è disponibile un salto, il giocatore deve eseguirlo. Se ce n'è più di uno, il giocatore può scegliere.

Per la maggior parte, funziona perfettamente con la lista monade: passa su tutti gli stati del gioco di input, passa su tutti i marmi che potrebbero essere saltati, passa su tutti i salti di quel marmo. Questa lista monade appiattisce bene tutte le liste in un semplice elenco di stati alla fine.

Il trucco è che, se non si trovano salti per un dato stato del gioco, devo restituire lo stato corrente del gioco, piuttosto che l'elenco vuoto. Il codice qui sotto è il modo migliore in cui mi è venuto in mente di farlo, ma mi sembra davvero brutto. Qualche suggerimento su come ripulirlo?

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: fornisce firme di tipo di esempio per le funzioni * Hex.

È stato utile?

Soluzione

  

Il trucco è che, se non si trovano salti per un dato stato del gioco, devo restituire lo stato corrente del gioco, piuttosto che l'elenco vuoto.

Perché? Ho scritto minimax diverse volte e non riesco a immaginare un uso per tale funzione. Non staresti meglio con una funzione di tipo

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

o

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

Tuttavia, se vuoi davvero restituire " o l'elenco dei prossimi stati, o se tale elenco è vuoto, lo stato originale " ;, allora il tipo che desideri è

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

che puoi quindi appiattire abbastanza facilmente.

Per quanto riguarda come implementare, raccomando di definire una funzione di supporto di tipo

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

e che puoi mappare

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

sul risultato, oltre a varie altre cose.

Come ha detto Fred Brooks (parafrasando), una volta che si ottengono i tipi giusti, il codice praticamente si scrive da solo.

Altri suggerimenti

Non abusare della notazione delle monadi per l'elenco, è così pesante per niente. Inoltre puoi usare la comprensione dell'elenco nello stesso modo:

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

ora per la "semplificazione"

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 comprensione let in the let in list in alto mi disturba un po ', ma dato che non ho tutto il codice, non so davvero come farlo in un altro modo. Se riesci a modificare in modo più approfondito, ti suggerisco di usare più combinatori (map, foldr, foldl 'ecc.) In quanto riducono davvero la dimensione del codice nella mia esperienza.

Nota, il codice non è stato testato e potrebbe non essere compilato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top