pythonminmax

MinMax algorithm not Running past depth 1


I am trying to implement a simple minimax algorithm for chess. I have a seemingly working algorithm now, but there may be an error in logic somewhere.

#minimax algorithm
def minimax(BOARD, DEPTH, MAXIMIZE, counter):
  #create a list of legal moves
  moves = list(BOARD.legal_moves)
  score = []
  counter = counter + len(moves)
  if MAXIMIZE:
      if not moves:
        return None
      #find the best move for the AI
      #go through every legal move
      for i in moves:

        #make copy of the board and push the next legal move
        b = deepcopy(BOARD)
        b.push(i)
        if DEPTH > 1:
          #recursively call minimax to go down the tree
          temp_move = minimax(b, DEPTH-1, True, counter)
          #if the minimax function returns a value
          if temp_move is not None:
            b.push(temp_move[0])
        #evaluate board position at every point 
        score.append(evals(b, PIECE_VALUE))
        #counter = evals(b, PIECE_VALUE, counter)[1]
      #select a move with the max board position score
      best_move = moves[score.index(min(score))]
      return best_move, counter
  else:
      if not moves:
        return None
      #find the best move for the human
      for i in moves:

        #make copy of the board and push the next legal move
        b = deepcopy(BOARD)
        b.push(i)
        if DEPTH > 1:
          #recursively call minimax to go down the tree
          temp_move = minimax(b, DEPTH-1, False, counter)
          if temp_move is not None:
            b.push(temp_move[0])
          #evaluate board position at every point 
        score.append(evals(b, PIECE_VALUE))
        #counter = evals(b, PIECE_VALUE, counter)[1]
      #select a move with the min board position score
      best_move = moves[score.index(max(score))]
      return best_move, counter

I have a counter int that should count the number of nodes in the tree whenever the 'minimax' function is called, but at any depth I set it returns a value between 15 and 20. Does my function fail to run past depth 1? At depth 3 or 5 it should have hundreds of nodes, but counter always returns ~20.

Full code for reference:

# importing required libraries
import chess
import chess.polyglot
import math
from copy import deepcopy
import random

#initialise chess board
B = chess.Board()

#define search depth 
DEPTH = 2

PIECE_VALUE = {
 'p':-1,
 'r':-5,
 'n':-3,
 'b':-3,
 'k':0,
 'q':-9,
 'P':1,
 'R':5,
 'N':3,
 'B':3,
 'K':0,
 'Q':9
}

#genereate a random move from a list of legal moves
def random_ai(BOARD, PIECE_VALUE):
  #move = random.choice(list(BOARD.legal_moves))
  #print ("selecting a random move")
  print ("selecting the best move")
  move = select(BOARD, PIECE_VALUE)

  return move

#evaluation function
def evals(BOARD, PIECE_VALUE):
  score = 0
  #iterate over the board and add up all the pieces
  for i in range (64):
    if BOARD.piece_at(i) is not None:
      score = score + PIECE_VALUE[BOARD.piece_at(i).symbol()]

  return score
  
#selection function with minimax and alpha beta pruning
def select(BOARD, PIECE_VALUE):
  counter = 0
  result = minimax(BOARD, DEPTH, True, counter)
  if result is not None:
    counter = result[1]
    print ("Counter ", counter)
    move = result[0]
    return move

#minimax algorithm
def minimax(BOARD, DEPTH, MAXIMIZE, counter):
  #create a list of legal moves
  moves = list(BOARD.legal_moves)
  score = []
  counter = counter + len(moves)
  if MAXIMIZE:
      if not moves:
        return None
      #find the best move for the AI
      #go through every legal move
      for i in moves:

        #make copy of the board and push the next legal move
        b = deepcopy(BOARD)
        b.push(i)
        if DEPTH > 1:
          #recursively call minimax to go down the tree
          temp_move = minimax(b, DEPTH-1, True, counter)
          #if the minimax function returns a value
          if temp_move is not None:
            b.push(temp_move[0])
        #evaluate board position at every point 
        score.append(evals(b, PIECE_VALUE))
        #counter = evals(b, PIECE_VALUE, counter)[1]
      #select a move with the max board position score
      best_move = moves[score.index(min(score))]
      return best_move, counter
  else:
      if not moves:
        return None
      #find the best move for the human
      for i in moves:

        #make copy of the board and push the next legal move
        b = deepcopy(BOARD)
        b.push(i)
        if DEPTH > 1:
          #recursively call minimax to go down the tree
          temp_move = minimax(b, DEPTH-1, False, counter)
          if temp_move is not None:
            b.push(temp_move[0])
          #evaluate board position at every point 
        score.append(evals(b, PIECE_VALUE))
        #counter = evals(b, PIECE_VALUE, counter)[1]
      #select a move with the min board position score
      best_move = moves[score.index(max(score))]
      return best_move, counter

Solution

  • Your code doesn't do anything with the count that is returned from a recursive call. You should use it to update your local counter.

    So change the two occurrences of this code:

          if temp_move is not None:
            b.push(temp_move[0])
    

    to:

          if temp_move is not None:
            b.push(temp_move[0])
            counter = temp_move[1]