Connect Four minimax function error

I’m using a connect four class I wrote a while back:

class ConnectFour():

        turn = 0
        evanorodd = 0
        gameover = False
        xwin = 0
        owin = 0

        def __init__(self):
                self.board = [[" " for column in range(15)] for row in range(6)]
                for row_index, row in enumerate(self.board):
                        for col_index, item in enumerate(row):
                                if col_index % 2 == 0:
                                        self.board[row_index][col_index] = "|"


        def printer(self):
                if self.gameover == True:
                        print("\nThe final board state:")
                else:
                        print("\nTurn {turn}.".format(turn=ConnectFour.turn))
                print("\n  1   2   3   4   5   6   7")
                for row in self.board:
                        for item in row:
                                print(item, end = " ")
                        print()
        def available_moves(self):
                moves = []
                for i in range(1, 14, 1):
                        if self.board[0][i] == " ":
                                moves.append(i)
                return moves
                moves.clear()

        def inputter(self, col_index):
                self.turn += 1
                self.evanorodd += 1
                num = col_index * 2 - 1
                if num >=1 and num <= 13 and num % 2 != 0:
                        if self.board[0][num] == " ":
                                for i in range(5, -1, -1):
                                        if self.board[i][num] == " ":
                                                if self.evanorodd % 2 != 0:
                                                        self.board[i][num] = "X"
                                                        break
                                                else:
                                                        self.board[i][num] = "O"
                                                        break
                        else:
                                self.evanorodd -= 1
                                print("\nI'm afraid that column is full. Choose another one.")
                else:
                        self.evanorodd -= 1
                        print("\nYou need to give a column number from one to seven.")

        def checker(self):
                # checks vertical
                for row in range(5, 2, -1):
                        for column in range(1, 14, 2):
                                if self.board[row][column] == self.board[row-1][column] and self.board[row][column] == self.board[row-2][column] and self.board[row][column] == self.board[row-3][column]:
                                        if self.board[row][column] == "X":
                                                print("\nThe game is over! Crosses win with a vertical connect four!")
                                                self.gameover = True
                                                self.xwin = 1
                                        elif self.board[row][column] == "O":
                                                print("\nThe game is over! Naughts win with a vertical connect four!")
                                                self.gameover = True
                                                self.owin = -1
                # checks horizontal
                for row in range(5, -1, -1):
                        for column in range(1, 8, 2):
                                if self.board[row][column] == self.board[row][column+2] and self.board[row][column] == self.board[row][column+4] and self.board[row][column] == self.board[row][column+6]:
                                        if self.board[row][column] == "X":
                                                print("\nThe game is over! Crosses win with a horizontal connect four!")
                                                self.gameover = True
                                                self.xwin = 1
                                        elif self.board[row][column] == "O":
                                                print("\nThe game is over! Naughts win with a horizontal connect four!")
                                                self.gameover = True
                                                self.owin = -1
                # checks diagonal going from left to right
                for row in range(5, 2, -1):
                        for column in range(1, 8, 2):
                                if self.board[row][column] == self.board[row-1][column+2] and self.board[row][column] == self.board[row-2][column+4] and self.board[row][column] == self.board[row-3][column+6]:
                                        if self.board[row][column] == "X":
                                                print("\nThe game is over! Crosses win along a positive diagonal!")
                                                self.gameover = True
                                                self.xwin = 1
                                        elif self.board[row][column] == "O":
                                                print("\nThe game is over! Naughts win along a positive diagonal!")
                                                ConnectFour.gameover = True
                                                ConnectFour.owin = -1
                # checks diagonal going from right to left
                for row in range(5, 2, -1):
                        for column in range(13, 6, -2):
                                if self.board[row][column] == self.board[row-1][column-2] and self.board[row][column] == self.board[row-2][column-4] and self.board[row][column] == self.board[row-3][column-6]:
                                        if self.board[row][column] == "X":
                                                print("\nThe game is over! Crosses win along a negative diagonal!")
                                                self.gameover = True
                                                self.xwin = 1
                                        elif self.board[row][column] == "O":
                                                print("The game is over! Naughts win along a negative diagonal!")
                                                self.gameover = True
                                                self.owin = -1

play = ConnectFour()

play.inputter(3)

def evaluate_board(play):
        if ConnectFour.gameover == True:
                if play.xwin == 1:
                        return float("Inf")
                elif play.owin == -1:
                        return -float("Inf")
                else:
                        num_top_x = 0
                        num_top_o = 0
                        if play.board[5][5] == "X":
                                num_top_x += 1
                return num_top_x - num_top_o

def minimax(play, is_maximizing, depth, alpha, beta, evaluate_board):
        if ConnectFour.gameover or depth == 0:
                return [evaluate_board(play), ""]
        if is_maximizing == True:
                best_value = -float("Inf")
                moves = play.available_moves()
                random.shuffle(moves)
                best_move = moves[0]
                for move in moves:
                        copied = copy.deepcopy(play)
                        copied.inputter(move)
                        hypothetical_value = minimax(copied, False, depth - 1, alpha, beta, evaluate_board)[0]
                        if hypothetical_value > best_value:
                                best_value = hypothetical_value
                                best_move = move
                        alpha = max(alpha, best_value)
                        if alpha >= beta:
                                break
                return [best_value, best_move]
        else:
                best_value = float("Inf")
                moves = play.available_moves()
                random.shuffle(moves)
                best_move = moves[0]
                for move in moves:
                        copied = copy.deepcopy(play)
                        copied.inputter(move)
                        hypothetical_value = minimax(copied, True, depth -1, alpha, beta, evaluate_board)[0]
                        if hypothetical_value < best_value:
                                best_value = hypothetical_value
                                best_move = move
                        beta = min(beta, best_move)
                        if alpha >= beta:
                                break
                return [best_value, best_move]







print(minimax(play, True, 4, -float("Inf"), float("Inf"), evaluate_board))


ai = input("Would you like to play against an AI? Y or N?: ")

while ai.lower() != "y" and ai.lower() != "n":
        ai = input("Please enter either Y for yes or N for no: ")
if ai.lower() == "n":
        while ConnectFour.evanorodd < 43:
                play.printer()
                try:
                        columnnumber = int(input("Enter a column number from one to seven: "))
                except ValueError:
                        columnnumber = int(input("\nPlease give an integer!: "))
                play.inputter(columnnumber)
                play.checker()
                if ConnectFour.gameover == True:
                        play.printer()
                        break
                if ConnectFour.evanorodd == 42:
                        ConnectFour.gameover = True
                        print("\nThe game is drawn!")
                        play.printer()
                        break
elif ai.lower() == "y":
        print("eee")

When I run the code, I get this error:

Traceback (most recent call last):
  File "connect4.py", line 166, in <module>
    print(minimax(play, True, 4, -float("Inf"), float("Inf"), evaluate_board))
  File "connect4.py", line 135, in minimax
    hypothetical_value = minimax(copied, False, depth - 1, alpha, beta, evaluate_board)[0]
  File "connect4.py", line 151, in minimax
    hypothetical_value = minimax(copied, True, depth -1, alpha, beta, evaluate_board)[0]
  File "connect4.py", line 135, in minimax
    hypothetical_value = minimax(copied, False, depth - 1, alpha, beta, evaluate_board)[0]
  File "connect4.py", line 152, in minimax
    if hypothetical_value < best_value:
TypeError: '<' not supported between instances of 'NoneType' and 'float'

I guess this error means that hypothetical_value currently equals “NoneType” rather than a number like a float or integer etc. Been playing around with this for a while, but this error persists.

I originally had my own code for the minimax function, but ended up using the one from this project to see what I was doing wrong (modified though as I used a class):

https://www.codecademy.com/courses/machine-learning/projects/minimax-connect-four

That did not help. I kind of realise the error must be something to do with how I’m using the ConnectFour class, but I don’t think I know enough about OOP to understand what I’m doing wrong.

I realise this might be quite the ask. I’d appreciate any help at all.

You can sanitize the input so that if it’s None it gets converted to some unused number (you can use infinity or negative infinity, depending on what you’re trying to do). This might be nice if you can’t avoid have it be None. This is assuming the code logic works to begin with (if it doesn’t, then None is not the big problem).

The more slippery slope is using a try/except block.

1 Like

Just realised my evaluation function as it is will currently return none as the game is not over. Gonna work on fixing that, will get back to you if there’s any more problems :slight_smile: