Adversarial Search Algorithms in Artificial Intelligence (AI) - GeeksforGeeks
Adversarial Search Algorithms in Artificial Intelligence (AI) - GeeksforGeeks
Table of Content
What is an Adversarial search?
Adversarial search algorithms
Minimax algorithm
Alpha-beta pruning
Adversarial search algorithm Implementations using Connect-4 Game
Applications of adversarial search algorithms
Conclusion
FAQ’s on Adversarial search algorithms
Minimax algorithm
The Minimax algorithm is claimed to be a recursive or backtracking algorithm that is
responsible for choosing the best optimal move in the conflicting environment. The
Minimax algorithm operates on a tree structure known as the game tree, which is the
collection of all the possible moves in the corresponding game states in a given game.
The game tree’s leaf node accommodates all the possible moves. The game state
denotes the current board condition. With every single move, the game state changes
and the game tree gets updated height-wise. When visualized, this game tree often
resembles an inverted tree, with the root representing the current game state and the
branches representing possible moves.
This algorithm simply works by proceeding down to the tree until it reaches the leaf
node and then it backs up the minimax values through the tree as the recursion
unwinds. The prime motive of the Minimax algorithm is to maximize the chance of
winning for the maximizer. In the game tree, every node is assigned weights that
influence the chances of winning, the higher the weights, the higher the chances of
winning.
Minimax Tree: A tree structure shows all possible moves and game states in a
game, used by Minimax to find the best move.
MAX (Maximizer) - Maximizer seeks favorable outcomes in games by maximizing
chances of winning for themselves as players.
MIN (Minimizer) - Minimizer reduces winning chances, making moves leading to
least favorable outcome for the Maximizer in games.
Initial state - Starting state of game board, representing the configuration at the
beginning of the game.
Terminal state -Terminal states are the final outcomes of a game board, resulting in
either a win, loss, or draw.
Heuristic Evaluation Function: Function evaluates game states for maximizer,
assigning numerical values to each game state based on piece positions, material
advantage, and board control.
Terminal state: The Minimax value of each state in the game tree can be used to
determine the optimal strategy. The MINIMAX(s) refers to the utility of being in that
state that assumes both players play optimally from there to the end of the game.
Non-terminal state: In the case of the non-terminal state, when MAX's turn arrives
at the game, MAX aims to move which leads to a state of maximum value,
conversely MIN prefers to choose the move that leads to a state of minimum value.
It can be formulated as below:
⎧ U T ILIT Y (s, MAX) → if IS_TERM IN AL(s),
M IN IM AX(S) = ⎨ maxa∈Actions(s) M IN IM AX(RESULT (s, a)) → if TO_MOV E(s) = MAX,
⎩
findBestMove(board):
bestValue = -INFINITY
bestMove = NULL
for each possible move in board:
if move is valid:
make the move on the board
value = MINIMAX(board, depth, FALSE)
undo the move on the board
if value > bestValue:
bestValue = value
bestMove = move
return bestMove
The diagram below represents the binary tree that holds the possible game states and
moves in a game, with each leaf node representing a final game state.
figure(a) Example of Minimax algorithm that holds the possible game states
Traversal to the Right: The maximizer then traverses to the right side of the game
tree and encounters another set of decision nodes. Eventually, it reaches another
minimizer node where the minimizer again selects the optimal minimal value 1
among its options.
Recursive process: The process continues recursively where each player makes
decisions based on whether they are maximizer or minimizer and the objective of
maximizing or minimizing the score respectively.
Comparison and outcome: The maximizer node (root node) already holds the value
of 2, when the player earns another optimal value that is 1 while traversing in the
right path, it is then compared to get the final optimal value. The maximizer earns
the optimal value 2 based on the decisions made by both players.
Time complexity
The minimax algorithm explores the complete game tree using a depth-first search
approach that considers all possible moves at each level. The time complexity of the
minimax algorithm can be written as,
O(bm)
b - denotes the legal moves available at each point,
m - denotes the maximum depth of the tree.
This complexity arises because, at each level of the tree, the minimax algorithm must
consider all b legal moves and this process repeats recursively for m levels until a
terminal state is reached.
Space complexity
The space complexity of the minimax algorithm relies on how the algorithm generates
and stores the actions. In the case, where if all the possible actions are generated and
stored simultaneously, the space complexity can be written as
O(bm)
This arises because the algorithm needs to store all the possible actions at each level
of the game tree which leads to exponential growth in space requirements with the
depth of the tree.
However, if the actions are generated and processed one at a time, the space
complexity reduces to O(m).
Alpha-beta pruning
Alpha-beta pruning is an optimization technique for a minimax algorithm. It reduces
computation time by a huge factor, allowing the user to traverse faster and deeper into
the tree. It stops evaluating when at least one possibility has been found that typically
proves the move to be worse than the previously examined move. The minimax search
is based on depth-first search which considers the nodes along a single path in a tree.
But Alph-Beta pruning bonds with two major parameters in MAX-VALUE(state, alpha,
beta), representing Alpha plays a maximizer role, whereas Beta plays a minimizer role.
Branch elimination: The Alpha-beta pruning algorithm relies on the branches of the
game tree that can be eliminated which promotes the more promising subtree by
limiting the search time.
Branch and bound: Alpha-beta pruning is based on the branch and bound method
which offers a way to solve the optimization problem by dividing them into sub-
problems. It allows the algorithm to effectively remove the branches that did not
yield the optimal solution.
Heuristic improvements: To limit the computation time, the heuristic Alpha-beta
tree search cuts off the search early and applies the heuristic evaluation function to
states that treat the non-terminal nodes as if they were terminal nodes.
Game trees can hold abounding branches that can lead to different game states and
implementing alpha-beta pruning in such game trees can help to prune away the
branches if there already exists a better move. This makes the algorithm
computationally efficient since there is no need to search the other branches if there
already exists a better move in the game tree.
At any node in the game tree, the maximizing player is used to store the maximum
score in the alpha which assures that the max node contains only the maximum scores.
Similarly, the minimizing player is assured of a minimum value which is stored by the
beta. These two values of alpha and beta are updated and maintained by the
algorithm.
Take a look at the below example, initially both players begin with the worst possible
values they can score, therefore the alpha is assigned with the value of minus infinity,
whereas the beta is assigned with the value of plus infinity. We have a condition to
prune the branches, if the alpha is greater than or equal to the beta value then we can
prune the branch.
Note: alpha is the maximizer and beta is the minimizer.
Initially, the maximizer node A sets alpha to negative infinity and beta to positive
infinity. Assuming that node A selects node B which inherits these values. Node B
which is also a maximizer picks node D. At D, the maximizer chooses the max value (4)
and then updates its alpha. Upon returning to B (minimizer), it compares its current
beta with D’s alpha value. If D’s alpha is smaller, B’s beta value gets updated. In our
example, B’s beta gets updated since D’s alpha value is smaller.
Now, node B selects node E and passes down its current alpha and beta values to
node E. Node E inherits the alpha value of negative infinity and beta value of 4. As a
maximizer, E explores its left leaf node that holds a value of 5. Since 5 is greater than
negative infinity, E’s alpha gets updated. Given that alpha is greater than beta, the
other leaf node in E is unnecessary to explore so it gets pruned.
At node B, it compares its beta value with node E’s alpha, if E’s alpha value is lesser
than B’s beta updates with E’s alpha. However, if E’s alpha is greater than B’s beta, B’s
beta remains unchanged. In our example, since B’s beta is not greater than E’s alpha,
so B’s beta value remains the same. Returning to node A, its alpha value updates with
B’s beta value because B’s beta is greater than A’s alpha.
The maximizer yields the value 4
The Maximizer still holds the max value 4 and branch G gets pruned.
Connect-4 game where the player O should make the optimal move to win the game
def is_moves_left(board):
for row in board:
for cell in row:
if cell == '':
return True
return False
def evaluate(b):
for row in range(6):
for col in range(4):
if b[row][col] == b[row][col+1] == b[row][col+2] == b[row][col+3] == 'o':
return 10
for col in range(7):
for row in range(3):
if b[row][col] == b[row+1][col] == b[row+2][col] == b[row+3][col] == 'o':
return 10
for row in range(3):
for col in range(4):
if b[row][col] == b[row+1][col+1] == b[row+2][col+2] == b[row+3][col+3] ==
'o':
return 10
for row in range(3, 6):
for col in range(3):
if b[row][col] == b[row - 1][col+1] == b[row-2][col+2] == b[row - 3][col+3]
== 'o':
return 10
return 0
if score == 10:
return score - depth
if not is_moves_left(board):
return 0
if is_max:
best_value = -float('inf')
for col in range(7):
for row in range(5, -1, -1):
if board[row][col] == '':
board[row][col] = 'x'
best_val = max(best_val, minimax(
board, depth+1, not is_max))
board[row][col] = ''
break
return best_val
else:
best_value = float('inf')
for col in range(7):
for row in range(5, -1, -1):
if board[row][col] == '':
board[row][col] = 'o'
best_val = max(best_val, minimax(
board, depth+1, not is_max))
board[row][col] = ''
break
return best_val
def find_optimal_move(board):
best_move = None
best_val = -float('inf')
board = [
['x', 'x', 'o', '', '', '', 'x'],
['o', 'o', 'o', 'x', '', '', 'x'],
['x', 'o', '', '', '', '', ''],
['x', 'o', 'o', '', '', '', ''],
['x', 'x', 'x', 'o', '', '', ''],
['o', 'o', 'x', 'o', 'x', '', '']
]
optimal_move = find_optimal_move(board)
if optimal_move:
print("The optimal move for player O to win is:", optimal_move)
else:
print("Player O cannot win with the current board confguration")
Complete code
def is_moves_left(board):
for row in board:
for cell in row:
if cell == '':
return True
return False
def evaluate(b):
for row in range(6):
for col in range(4):
if b[row][col] == b[row][col+1] == b[row][col+2] == b[row][col+3] == 'o':
return 10
for col in range(7):
for row in range(3):
if b[row][col] == b[row+1][col] == b[row+2][col] == b[row+3][col] == 'o':
return 10
for row in range(3):
for col in range(4):
if b[row][col] == b[row+1][col+1] == b[row+2][col+2] == b[row+3][col+3] ==
'o':
return 10
for row in range(3, 6):
for col in range(3):
if b[row][col] == b[row - 1][col+1] == b[row-2][col+2] == b[row - 3][col+3]
== 'o':
return 10
return 0
if score == 10:
return score - depth
if not is_moves_left(board):
return 0
if is_max:
best_value = -float('inf')
for col in range(7):
for row in range(5, -1, -1):
if board[row][col] == '':
board[row][col] = 'x'
best_val = max(best_val, minimax(
board, depth+1, not is_max))
board[row][col] = ''
break
return best_val
else:
best_value = float('inf')
for col in range(7):
for row in range(5, -1, -1):
if board[row][col] == '':
board[row][col] = 'o'
best_val = max(best_val, minimax(
board, depth+1, not is_max))
board[row][col] = ''
break
return best_val
def find_optimal_move(board):
best_move = None
best_val = -float('inf')
board = [
['x', 'x', 'o', '', '', '', 'x'],
['o', 'o', 'o', 'x', '', '', 'x'],
['x', 'o', '', '', '', '', ''],
['x', 'o', 'o', '', '', '', ''],
['x', 'x', 'x', 'o', '', '', ''],
['o', 'o', 'x', 'o', 'x', '', '']
]
optimal_move = find_optimal_move(board)
if optimal_move:
print("The optimal move for player O to win is:", optimal_move)
else:
print("Player O cannot win with the current board confguration")
Output:
Output Explanation
Output of Connect-4 where the player O wins
Take a look at the above output illustration, the player O won when he chose the
optimal move such as (2,2). It's important to note that there are multiple possible
moves that player O could have made to potentially win the game. However, in the
given illustration only seven states of the game board are shown to demonstrate the
process of finding the optimal move using the minimax algorithm.
Conclusion
Adversarial search algorithms have emerged as a powerful tool with diverse
applications across numerous domains. From mastering complex board games to
enhancing cybersecurity, robotics, and automated negotiation systems, these
algorithms facilitate strategic decision-making in dynamic competitive environments.
While adversarial search algorithms aim to find optimal strategies based on the
set of rules and the current state information where the actions of human
opponents or unpredictable elements in some environments can introduce some
level of uncertainty. As a result, these algorithms strive to make informed
decisions and their outcomes may not always be deterministic.
Get IBM Certification and a 90% fee refund on completing 90% course in 90 days!
Take the Three 90 Challenge today.
Master Machine Learning, Data Science & AI with this complete program and also
get a 90% refund. What more motivation do you need? Start the challenge right
away!
Comment More info Advertise with us Next Article
Constraint Satisfaction Problems (CSP) in
Artificial Intelligence
Similar Reads
Alpha-Beta pruning in Adversarial Search Algorithms
In artificial intelligence, particularly in game playing and decision-making, adversarial
search algorithms are used to model and solve problems where two or more players…
6 min read
10 min read
6 min read
3 min read
5 min read
7 min read
Explain the role of minimax algorithm in adversarial search for optimal decision-…
In the realm of artificial intelligence (AI), particularly in game theory and decision-making
scenarios involving competition, the ability to predict and counteract an opponent's mov…
11 min read
14 min read
13 min read
Registered Address:
K 061, Tower K, Gulshan Vivante
Apartment, Sector 137, Noida, Gautam
Buddh Nagar, Uttar Pradesh, 201305
Advertise with us
Company Explore
About Us Job-A-Thon Hiring Challenge
Legal Hack-A-Thon
Privacy Policy GfG Weekly Contest
Careers Offline Classes (Delhi/NCR)
In Media DSA in JAVA/C++
Contact Us Master System Design
GfG Corporate Solution Master CP
Placement Training Program GeeksforGeeks Videos
Geeks Community
Languages DSA
Python Data Structures
Java Algorithms
C++ DSA for Beginners
PHP Basic DSA Problems
GoLang DSA Roadmap
SQL DSA Interview Questions
R Language Competitive Programming
Android Tutorial
DSA/Placements Development/Testing
DSA - Self Paced Course JavaScript Full Course
DSA in JavaScript - Self Paced Course React JS Course
DSA in Python - Self Paced React Native Course
C Programming Course Online - Learn C with Data Structures Django Web Development Course
Complete Interview Preparation Complete Bootstrap Course
Master Competitive Programming Full Stack Development - [LIVE]
Core CS Subject for Interview Preparation JAVA Backend Development - [LIVE]
Mastering System Design: LLD to HLD Complete Software Testing Course [LIVE]
Tech Interview 101 - From DSA to System Design [LIVE] Android Mastery with Kotlin [LIVE]
DSA to Development [HYBRID]
Placement Preparation Crash Course [LIVE]