Loading content...
In combinatorial game theory, adversarial search algorithms are essential for developing intelligent agents that compete against opponents. One of the most elegant approaches is the minimax strategy, which models decision-making in zero-sum games where one player's gain is exactly the other player's loss.
Consider a two-player, turn-based grid game played on a 3×3 board. Each player places their symbol ('X' or 'O') on empty cells, taking turns until one player achieves three consecutive symbols in a row, column, or diagonal, or all cells are filled (resulting in a draw).
The Adversarial Search Principle: The core idea behind optimal play is to assume that your opponent will always make the best possible move from their perspective. Given this assumption:
Game State Evaluation: At each game state, the algorithm recursively explores all possible future moves, propagating values up the decision tree:
Your Task: Implement an adversarial search function that determines the optimal next move for a given player on a 3×3 grid game board. The function should:
Note: If multiple moves are equally optimal, any one of them is an acceptable answer. Do not use external game-playing libraries.
board = np.array([['X', 'O', 'X'], ['', 'O', ''], ['', '', '']])
current_player = 'X'(2, 1)Analyzing the board state:
X | O | X
---------
| O |
---------
| |
Player 'O' has two symbols in the middle column (positions (0,1) and (1,1)). If 'O' places their symbol at (2,1), they would complete a vertical line and win. Therefore, 'X' must immediately block this threat by playing at position (2, 1). This move prevents the opponent's victory and is the optimal defensive play.
board = np.array([['X', 'X', ''], ['O', 'O', ''], ['', '', 'X']])
current_player = 'O'(0, 2) or (1, 2)Analyzing the board state:
X | X |
---------
O | O |
---------
| | X
Both players have two-in-a-row patterns:
Since it's 'O's turn, they have two equally optimal moves:
Both moves lead to an optimal outcome (option 1 wins immediately, making it slightly preferred, but both are considered correct in terms of game-theoretic value).
board = np.array([['X', '', ''], ['O', 'O', ''], ['X', '', '']])
current_player = 'X'(1, 2)Analyzing the board state:
X | |
---------
O | O |
---------
X | |
Player 'O' has two symbols in the middle row (positions (1,0) and (1,1)). If 'X' doesn't act, 'O' will play at (1, 2) on their next turn and win. The only optimal move for 'X' is to block this immediate threat by playing at position (1, 2). Adversarial search reveals that after this block, 'X' can continue to play optimally and eventually secure at least a draw.
Constraints