Вопрос

Поэтому я работаю над минимаксной реализацией игры, похожей на шашки, чтобы помочь себе лучше изучить Haskell.Функция, с которой у меня возникли проблемы, принимает список состояний игры и генерирует список ближайших состояний игры-преемника.Как и в шашках, если доступен прыжок, игрок должен его совершить.Если их несколько, игрок может выбрать.

По большей части это хорошо работает с монадой списка:перебрать все входные состояния игры, перебрать все шарики, через которые можно перепрыгнуть, перебрать все прыжки этого шарика.Эта списковая монада прекрасно объединяет все списки в простой список состояний в конце.

Хитрость в том, что если для данного состояния игры не найдено никаких переходов, мне нужно вернуть текущее состояние игры, а не пустой список.Код ниже — лучший способ, который я придумал, но мне он кажется очень уродливым.Есть предложения, как его почистить?

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

РЕДАКТИРОВАТЬ:Приведите примеры сигнатур типов для функций *Hex.

Это было полезно?

Решение

Хитрость в том, что если для данного состояния игры не найдено никаких переходов, мне нужно вернуть текущее состояние игры, а не пустой список.

Почему?Я писал минимакс несколько раз и не могу представить себе применение такой функции.Не лучше ли использовать функцию типа

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

или

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

Однако, если вы действительно хотите вернуть «либо список следующих состояний, либо, если этот список пуст, исходное состояние», тогда вам нужен следующий тип:

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

который вы затем сможете достаточно легко сгладить.

Что касается реализации, я рекомендую определить вспомогательную функцию типа

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

и чем вы можете отобразить

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

над результатом, а также различные другие вещи.

Как сказал Фред Брукс (перефразируя), как только вы правильно определите типы, код практически пишется сам.

Другие советы

Не злоупотребляйте нотациями монад для списка, это так тяжело даром. Более того, вы можете использовать понимание списка таким же образом:

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

теперь для «упрощения»

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)

Понимание пустоты в верхнем списке немного беспокоит меня, но, поскольку у меня нет всего кода, я действительно не знаю, как это сделать другим способом. Если вы можете изменить глубже, я предлагаю вам использовать больше комбинаторов (map, foldr, foldl 'и т. Д.), Поскольку они действительно уменьшают размер кода в моем опыте.

Обратите внимание, что код не тестируется и может не скомпилироваться.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top