문제

그래서 저는 Haskell을 더 잘 배우도록 돕기 위해 Checkers와 같은 게임을위한 Minimax 구현 작업을하고 있습니다. 내가 문제가있는 기능은 게임 상태 목록을 가져 와서 즉각적인 후속 게임 상태 목록을 생성합니다. Checkers와 마찬가지로 점프를 사용할 수 있으면 플레이어가 가져와야합니다. 둘 이상이 있으면 플레이어가 선택할 수 있습니다.

대부분의 경우, 이것은 List Monad : 모든 입력 게임 상태에 대한 루프, 점프 할 수있는 모든 대리석을 루프하고, 그 대리석의 모든 점프를 통해 루프합니다. 이 목록은 Monad가 모든 목록을 끝에 간단한 상태 목록으로 멋지게 평평하게합니다.

속임수는 주어진 게임 상태에 대한 점프가 없으면 빈 목록이 아닌 현재 게임 상태를 반환해야한다는 것입니다. 아래 코드는 제가 그렇게하는 가장 좋은 방법이지만, 나에게 정말 추악한 것 같습니다. 청소 방법에 대한 제안이 있습니까?

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

편집 : *16 진수에 대한 예제 유형 서명을 제공합니다.

도움이 되었습니까?

해결책

속임수는 주어진 게임 상태에 대한 점프가 없으면 빈 목록이 아닌 현재 게임 상태를 반환해야한다는 것입니다.

왜요? 나는 Minimax를 여러 번 작성했으며 그러한 기능을 사용하는 것을 상상할 수 없습니다. 유형의 함수로 더 나아지지 않겠습니까?

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)

결과에 걸쳐 다양한 다른 것들.

프레드 브룩스 (Fred Brooks)가 말했듯이 (역설), 일단 유형을 올바르게 얻으면 코드는 실제로 자체적으로 기록됩니다.

다른 팁

목록에 대한 모나드 표기법을 남용하지 마십시오. 아무것도 너무 무겁습니다. 또한 동일한 방식으로 목록 이해력을 사용할 수 있습니다.

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)

상단에있는 Let In List의 상식은 저를 조금 귀찮게하지만, 모든 코드가 없으므로 다른 방식으로 어떻게 해야하는지 모르겠습니다. 더 깊이를 수정할 수 있다면 내 경험에서 코드 크기를 실제로 줄일 때 더 많은 콤비네이터 (Map, Foldr, Foldl '등)를 사용하는 것이 좋습니다.

코드는 테스트되지 않았으며 컴파일되지 않을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top