2012-09-09 2 views
4

안녕하세요!체스 네가 맥스 기능

체스 엔진에 대해 네가 막스 검색 알고리즘을 쓰려고하는데, 제대로 작동하지 않는 것 같습니다. 예를 들어 wikipedias pseudocode를 사용하고 있지만 어떻게 든 예상 결과가 나오지 않습니다. 내가 2의 플라이와 함께 그것을 실행하면, 그것은하지 않아야하지만, 내 보드 데이터 구조를 변경합니다. 플라이 2로 실행이 끝난 후, 모든 흰색 (또는 검은 색은 플레이어가 어떤 기능을 호출하는지에 달려 있습니다.) 폰은 시작 위치에서 2 칸 앞으로 이동합니다.

내 make와 unmake 이동 함수는 최대 5-ply까지 검색하는 비 재귀 함수를 사용하여 완벽하게 작동합니다. 그런 다음 완벽하게 작동했습니다. 내 negamax 구현에 문제가있을 것입니다.

도움 주셔서 감사합니다.

def negaMax(self, board, rules, ply, player): 
     """ Implements a minimax algorithm. """ 
     if ply == 0: 
      return self.positionEvaluation() 

     self.max_eval = float('-infinity') 

     self.move_list = board.generateMoves(rules, player) 
     for self.move in self.move_list: 
      board.makeMove(self.move, player) 
      self.eval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player)) 
      board.unmakeMove(self.move, player) 

      if self.eval > self.max_eval: 
       self.max_eval = self.eval 

     return self.max_eval 
+0

재귀 알고리즘을 사용할 때는 객체 변수 (또는 정적 변수)를 사용하지 않는 것이 좋습니다. 나는 그가 로컬 변수만을 사용하도록 알고리즘을 변환하려고 시도하고 디버깅하려고 시도했다. 나는 최소한 디버깅이 더 쉬울 것이라고 확신 할 수 있습니다. – amit

+0

이유를 설명해 주시겠습니까? – geekkid

+0

예. 객체 변수는 모든 재귀 적 호출에 공통적입니다. 사람이 그것을 바꿀 때 - 모두 봅니다. 코드를 훨씬 더 복잡하게 만드는 결과를 낳기는 커녕, 로컬 변수만을 사용하는 재귀 코드는 매우 자체적으로 포함되어 있으며 디버깅하기가 훨씬 쉽고 이해하기 쉽습니다. – amit

답변

3

여기서 중요한 문제는 로컬 변수 대신 객체 변수를 사용하는 것입니다.

self.move개체 변수, 당신이 그것을 변경할 때마다 - 재귀의 모든 수준이 "인식"일반적으로 재귀 알고리즘에 대한 나쁜 일이 변경.

재귀 알고리즘은 자체 포함되어 있어야하며 호출 환경이 변경되면 최소한으로 수행해야합니다. 알고리즘의 흐름을 훨씬 쉽게 수행 할 수 있습니다. 이 코드에서 볼

두 가지 주요 문제는 다음과 같습니다

  1. self.move지역 변수 (move로 선언)이어야한다. 나중에 할 때 : board.unmakeMove(self.move, player) - 나는 이사회가 당신이 의도 한 것이 아닌 재귀 트리에서 더 깊게 설정된 다른 이동을 취소하고 있다고 생각합니다. 로컬 변수를 사용하면 이러한 바람직하지 않은 동작이 제거됩니다.
  2. 재귀 호출의 각 레벨은 self.max_eval = float('-infinity')으로 설정되어 있으므로 사용자가 원하는 것은 아니지만 지속적으로 변경합니다.

이 솔루션은 그런 일해야한다 :

def negaMax(self, board, rules, ply, player): 
     """ Implements a minimax algorithm. """ 
     if ply == 0: 
      return self.positionEvaluation() 

     max_eval = float('-infinity') 

     move_list = board.generateMoves(rules, player) 
     for move in move_list: 
      board.makeMove(move, player) 
      currentEval = -self.negaMax(board, rules, ply - 1, board.getOtherPlayer(player)) 
      board.unmakeMove(move, player) 

      if currentEval > max_eval: 
       max_eval = currentEval 
     return max_eval 

나는 나는 100 %는 참으로 (그러나 그것의 일부를 해결할 것입니다)하지만 100 % 확신 해요 코드에서 모든 것을 해결할 특정 객체 변수를 사용하지 않으면 코드를 훨씬 쉽게 이해하고 디버그 할 수 있습니다.

+1

+1로이 토론을 마무리하겠습니다. 그러나 변수 이름에'eval'을 사용하면 안됩니다. –

+0

의견을 보내 주셔서 감사합니다.이 변수의 이름을 변경했습니다. 나는 파이썬 전문가가 아니기 때문에이 문제에 익숙하지 않다. – amit

+0

고맙습니다. 이사회 데이터 구조가 변경되었다는 문제가 해결되었습니다. 나는 알고리즘이 어떤 방식 으로든 잘못되었다고 생각합니다. 모든 플라이와 마찬가지로, 그것은 출력 0을 생성합니다. 그러나 나는 내일 이것을 알아 내려고 노력할 것입니다.

하지만 개체 변수를 사용해야하는시기와 지역 변수를 사용해야하는시기를 설명해주십시오. 나는 이전에 클래스 안에서 변수를 decleare 할 때, 나는 'self'를 넣어야한다고 생각했다. 그것 앞에 : d. 다시 한번 고마워요.

geekkid