How Do I Fix a TypeError in My Minimax Base Tic Tac Toe Game in Pygame?

As a hobbyist game developer working with Python and Pygame, I recently decided to take on the classic challenge of building a Tic Tac Toe game. To make it more interesting, I implemented an AI opponent using the Minimax algorithm.

Everything seemed to be working fine the grid was displaying, player clicks were registered, and the AI responded correctly. But then, I hit a wall. My terminal threw this error:

TypeError: cannot unpack non-iterable NoneType object

It was pointing directly to this line in my main game loop:

row, col = comp.evaluation(board)

And just like that, the game froze. So I dug into the code to figure out what went wrong.

Define Error

Here’s the issue in plain terms I was expecting the AI to always return a valid move a tuple like (1, 2) but instead, under certain conditions, it was returning None. And Python doesn’t know how to unpack None into two variables, hence the TypeError.

Root Cause Analysis

The culprit turned out to be inside the MinMax class, particularly this method:

def evaluation(self, main_board):
...
return move

The move was supposed to be a tuple like (row, col), but sometimes, it ended up being None. Why?

It turns out, the issue occurs when the board is full (i.e., the game is a draw), or when the AI logic can’t find a valid move. The minmax method would return None in such cases:

eval, move = self.minmax(main_board, False)
# If no move is possible
return move # move = None

So when the game tried to do this:

row, col = comp.evaluation(board)

Python essentially tried to unpack None, resulting in that TypeError.

Fix for the Error

To fix this, I updated the evaluation() method to never return None directly. Instead, I return a default safe value when no moves are possible.

Update evaluation() method:

def evaluation(self, main_board):
if self.level == 0:
move = self.random_choice(main_board)
eval = 'random'
else:
eval, move = self.minmax(main_board, False)

if move is None:
print("No move possible: Board is full or no valid moves left.")
return -1, -1 # Safe fallback

print(f'Minimax chose: {move} with evaluation {eval}')
return move

Safe unpacking in main():

move = comp.evaluation(board)
if move == (-1, -1):
tictac.run = False
continue

row, col = move

Now, even if the board is full or the AI can’t decide on a move, the game handles it gracefully and avoids crashing.

Additional Feature I Practice and Implement

After solving the error, I decided to expand the project to make it more robust and interesting. Here are some features I added:

Difficulty Levels

  • Level 0 – AI plays randomly.
  • Level 1 – Full Minimax algorithm.
  • Level 2 (new) – Depth-limited Minimax with pruning.

This helped me explore performance optimization and gave players a smoother experience.

Score Tracking

I added a simple score tracker with:

self.scores = {'player': 0, 'computer': 0, 'draw': 0}

Every time a game ends, it checks who won and updates the corresponding score.

Visual Enhancement

I improved the visual feedback by:

  • Highlighting the winning line
  • Adding a short delay before the next game
  • Displaying winner messages

These small changes made the game feel much more polished.

Human vs Human Mode

Previously, the game supported only user vs AI. I added support for two player mode by toggling the game mode:

if self.gamemode == 'user':
self.gamemode = 'computer'
else:
self.gamemode = 'user'

This was a great exercise in managing game state and conditional behavior.

AI Starts First

With a simple keypress (A), I let the computer go first handy for testing and game variety.

Play Again Prompt

After the game ends, players are shown:

“Game Over – Press R to Restart or Q to Quit”

This made replaying quick and intuitive.

Final Thoughts

Building this Tic-Tac-Toe game with Pygame and the Minimax algorithm was a fantastic learning experience. The TypeError was a good reminder that even a smart AI can break things when it has no valid choices and you have to plan for that.

Beyond fixing the bug, the project helped me practice:

  • Handling edge cases
  • Implementing clean game logic
  • Improving user experience with visuals and interactivity

If you’re into Python or game development, I highly recommend trying this out. And when you hit your own TypeErrors just know it’s part of the process.

Related blog posts