AIL 333 AI Algorithm Lab
AIL 333 AI Algorithm Lab
Aim
To write a program to implement the Water Jug Problem.
Algorithm
1. Initialize the root state:
- Start with the state (0, 0) (both jugs empty).
- Push the state (0, 0) to the queue along with an empty list of actions.
- Mark the state (0, 0) as visited.
2. Enter BFS Loop:
- Continue the loop until the queue is empty:
2.1 Pop the front state:
- Pop the front state (jug1, jug2) and its corresponding list of actions from the queue.
2.2 Check if the target is reached:
- If either jug1 == target or jug2 == target, return True and print the sequence of actions.
2.3 Generate and enqueue possible next states:
- For the current state (jug1, jug2), generate all possible next states by performing actions:
- Fill the 4-gallon jug (jug1 becomes full).
- Fill the 3-gallon jug (jug2 becomes full).
- Empty the 4-gallon jug (jug1 becomes empty).
- Empty the 3-gallon jug (jug2 becomes empty).
- Pour water from jug1 into jug2, until jug2 is full or jug1 is empty.
- Pour water from jug2 into jug1, until jug1 is full or jug2 is empty.
2.4. Mark new states as visited:
- For each new state, if it has not been visited:
- Mark the new state as visited.
- Push the new state and the updated list of actions to the queue.
3. Return the result:
- If the queue becomes empty without finding the target amount, return False, indicating that the target
amount cannot be measured.
Program
# BFS loop
while queue:
(current_state, actions) = queue.popleft()
(jug1, jug2) = current_state
return False, []
# Example usage
jug1_capacity = 4
jug2_capacity = 3
target = 2
Output
Is it possible to measure 2 liters? Yes
Sequence of actions to reach the target:
Fill 4-gallon jug
Pour 4 into 3
Empty 3-gallon jug
Pour 4 into 3
Fill 4-gallon jug
Pour 4 into 3
Result
The program is successfully executed and output is verified.
Viva Questions
The water jug problem in AI is a complex problem where it is important to find a way to measure the
amount of water using two jugs of different capacities.
Algorithms like Breadth-First Search, Depth-First Search, Heuristic Search, and Stace-Space Representation
can be used to solve the water jug problem. To solve the water jug problem in AI, Breadth First Search is the
best water jug problem solution.
Experiment No: 2
Depth First Search
Aim
Write a program to implement Depth First Search to find the path between start and goal state.
Algorithm
1. Start at the root node and push it onto the stack.
2. Check for any adjacent nodes of the tree and select one node.
3. Traverse the entire branch of the selected node and push all the nodes into the stack.
4. Upon reaching the end of a branch (no more adjacent nodes) that is the nth leaf node, move back by
a single step and look for adjacent nodes of the n-1th node.
5. If there are adjacent nodes for the n-1th node, traverse those branches and push nodes onto the stack.
Program
def dfs(graph, start, goal):
stack = [(start, [start])] # Stack for DFS with path tracking
visited = set() # Set to track visited nodes
while stack:
(vertex, path) = stack.pop() # Get the current vertex and path
if vertex in visited:
continue
visited.add(vertex)
def main():
# User input to build the graph
graph = {}
print("Enter the graph structure (enter 'done' when finished):")
while True:
node = input("Enter a node (or 'done' to finish): ")
if node == 'done':
break
neighbors = input(f"Enter the neighbors of {node} separated by space: ").split()
graph[node] = neighbors
Output
Enter the graph structure (enter 'done' when finished):
Enter a node (or 'done' to finish): A
Enter the neighbors of A separated by space: B C
Enter a node (or 'done' to finish): B
Enter the neighbors of B separated by space: D E
Enter a node (or 'done' to finish): C
Enter the neighbors of C separated by space: F
Enter a node (or 'done' to finish): D
Enter the neighbors of D separated by space:
Enter a node (or 'done' to finish): E
Enter the neighbors of E separated by space: G
Enter a node (or 'done' to finish): F
Enter the neighbors of F separated by space: H
Enter a node (or 'done' to finish): G
Enter the neighbors of G separated by space:
Enter a node (or 'done' to finish): H
Enter the neighbors of H separated by space:
Enter a node (or 'done' to finish): done
Result
The program is successfully executed and output is verified.
Viva Questions
1. What is the space and time complexity of DFS?
The time complexity of Depth First Search (DFS) is O(V + E), where V is the number of
vertices and E is the number of edges. The space complexity is O(V)
● In DFS, when a path is fully explored (i.e., when there are no more unvisited neighbors),
the algorithm "backs up" to the previous node and tries other unexplored neighbors.
● This approach is essential in solving problems that require trying all possible solutions,
such as puzzle solving (e.g., the N-Queens problem, Sudoku, or maze-solving), where you might
explore a path only to find it's invalid, requiring you to return to previous choices and try
different options.
In DFS, this "backtracking" is achieved by using recursion or a stack. When a path leads to a
dead-end (goal not reached or all neighbors visited), the algorithm backtracks to the previous
node, checking other possible routes.
1. Pathfinding and Maze Solving: DFS can be used to explore possible paths in mazes or
navigation problems, though it may not find the shortest path.
2. Topological Sorting: In a directed acyclic graph (DAG), DFS is used to perform topological
sorting, which is useful in scheduling tasks (e.g., course prerequisite structures or build
dependencies).
3. Solving Backtracking Problems: DFS is inherently used in backtracking algorithms like
solving puzzles (e.g., Sudoku, N-Queens problem).
4. Network Flow Algorithms: DFS is a part of network flow algorithms, such as finding
augmenting paths in the Ford-Fulkerson method.
5. Web Crawling: DFS can be used in web crawlers to traverse web pages by following
hyperlinks.
Experiment No: 3
Breadth First Search
Aim
Write an algorithm to implement Breadth First Search to find the path between start and goal state.
Algorithm
1. Start with a root node and push it to the queue.
2. Mark the root node as visited and print it
3. Continue a loop until the queue is empty:
3.1 Pop the front node from the queue
3.2 . Push the child/neighbour nodes of the front node to the queue
3.3 Mark them as visited and print
Program
def BFS(graph, start, goal):
explored = [] # List to keep track of explored nodes
queue = [[start]] # Initialize the queue with the start node
if start == goal:
print("Start and goal are the same node")
return
while queue:
path = queue.pop(0) # Get the first path from the queue
node = path[-1] # Get the last node in the path
if node not in explored:
neighbours = graph.get(node, []) # Get neighbors of the current node
for neighbour in neighbours:
new_path = list(path) # Create a new path that includes the neighbour
new_path.append(neighbour)
queue.append(new_path) # Add the new path to the queue
if neighbour == goal: # Check if we've reached the goal
print("Shortest path = ", " -> ".join(new_path))
return
explored.append(node) # Mark the node as explored
print("Sorry, but no connecting path exists :(")
return
def main():
graph = {}
# User input to build the graph
print("Enter the graph structure (enter 'done' when finished):")
while True:
node = input("Enter a node (or 'done' to finish): ")
if node == 'done':
break
neighbours = input(f"Enter the neighbors of {node} separated by space: ").split()
graph[node] = neighbours
# User input for start and goal nodes
start = input("Enter the start node: ")
goal = input("Enter the goal node: ")
Output
Enter the graph structure (enter 'done' when finished):
Enter a node (or 'done' to finish): A
Enter the neighbors of A separated by space: B C
Enter a node (or 'done' to finish): B
Enter the neighbors of B separated by space: D E
Enter a node (or 'done' to finish): C
Enter the neighbors of C separated by space: F
Enter a node (or 'done' to finish): D
Enter the neighbors of D separated by space:
Enter a node (or 'done' to finish): E
Enter the neighbors of E separated by space:
Enter a node (or 'done' to finish): F
Enter the neighbors of F separated by space:
Enter a node (or 'done' to finish): done
Enter the start node: A
Enter the goal node: E
Shortest path = A -> B -> E
Result
The Breadth First Search algorithm is successfully executed and output is verified.
Viva Questions
1. What data structure is used in BFS?
Queue
2. What is the space and time complexity of BFS?
Time Complexity: The time complexity of BFS is O(V + E), where V is the number of vertices
(nodes) and E is the number of edges in the graph. This is because each vertex and edge is explored
once.
Space Complexity: The space complexity of BFS is also O(V). This space is required to store the
queue of nodes to be explored and to maintain a record of visited nodes. In the worst case, the queue
may contain all vertices at a particular level.
Informed search algorithms use additional information (heuristics) to guide the search process. They
evaluate possible paths based on a heuristic function that estimates the cost to reach the goal from a
given node. Examples include A* Search and Greedy Best-First Search. These algorithms are
typically more efficient than uninformed search as they can prioritize paths that are more likely to
lead to the goal.
Uninformed Search:
Uninformed search algorithms do not have additional information about the goal's location. They
explore the search space without guidance on which direction to take.Examples include Breadth-First
Search (BFS) and Depth-First Search (DFS). These algorithms systematically explore the search
space but may not be as efficient in finding a solution compared to informed searches, especially in
large search spaces.
4. What are the main drawbacks of BFS when compared to depth-first search in AI applications?
BFS guarantees finding the shortest path in unweighted graphs, but this may not be advantageous in
all scenarios. If the search space is large and the solution is deep, DFS may reach a solution faster,
even if it's not the shortest.
Experiment No: 4
Best First Search
Aim
Write an algorithm to implement Best First Search to find the path between start and goal state.
Algorithm
1. Initialize the Graph: Create a graph data structure to store nodes and their respective edges with
weights.
2. Input Edges:
● Read the number of edges from the user.
● For each edge, read the nodes (u, v) and the weight, then add them to the graph.
3. Input Start and Goal Nodes:
● Read the start node and the goal node from the user.
4. Best-First Search Procedure:
● Initialize a priority queue (open list) and add the start node with an initial cost of 0.
● Create a set to track visited nodes.
● Create a dictionary to store parent nodes for path reconstruction.
5. While Loop (Search Process):
● While the open list is not empty:
○ Remove the node with the lowest cost from the priority queue.
○ If this node has already been visited, skip to the next iteration.
○ Mark the current node as visited.
○ Goal Check:
■ If the current node is the goal, reconstruct the path from the start node to the
goal using the parent dictionary, print the path, and terminate the search.
○ Expand Neighbors:
■ For each neighbor of the current node:
■ If the neighbor has not been visited:
■ Add the neighbor to the open list with its associated cost
(weight).
■ Set the current node as the parent of the neighbor for path
reconstruction.
6. No Path Found:
● If the open list is empty and the goal was not reached, print a message indicating that no path
was found from the start to the goal.
Program
from queue import PriorityQueue
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, u, v, weight):
if u not in self.graph:
self.graph[u] = []
if v not in self.graph:
self.graph[v] = []
self.graph[u].append((v, weight))
self.graph[v].append((u, weight)) # If the graph is undirected
def best_first_search(self, start, goal):
open_list = PriorityQueue()
open_list.put((0, start)) # (cost, node)
visited = set()
parent = {start: None}
while not open_list.empty():
current_cost, current_node = open_list.get()
if current_node in visited:
continue
visited.add(current_node)
if current_node == goal:
path = []
while current_node is not None:
path.append(current_node)
current_node = parent[current_node]
path.reverse()
print("Path found:", " -> ".join(map(str, path)))
return
for neighbor, weight in self.graph.get(current_node, []):
if neighbor not in visited:
# Here you can change the priority based on a heuristic if
needed
open_list.put((weight, neighbor))
parent[neighbor] = current_node
print("No path found from", start, "to", goal)
if __name__ == "__main__":
g = Graph()
# User input for the number of edges
num_edges = int(input("Enter the number of edges: "))
print("Enter edges in the format 'u v weight' (one per line):")
for _ in range(num_edges):
u, v, weight = map(int, input().split())
g.add_edge(u, v, weight)
Output
Enter the number of edges: 5
Enter edges in the format 'u v weight' (one per line):
121
134
242
341
453
Enter the start node: 1
Enter the goal node: 5
Path found: 1 -> 2 -> 4 -> 5
Result
The Best First Search algorithm is successfully executed and output is verified.
Viva Questions
Best-First Search is a search algorithm that explores a graph or tree by selecting the most promising
node based on a specified evaluation function. It uses heuristics to estimate the cost of reaching the
goal from each node, thus guiding the search towards the goal more efficiently than uninformed
search methods. The most common form of Best-First Search is the A* algorithm.
A common heuristic used in pathfinding algorithms, including Best-First Search and A* Search, is
the Euclidean distance or the Manhattan distance:
● Euclidean Distance: Used in a 2D space to estimate the straight-line distance between two
points (x1,y1)and (x2,y2):
● Manhattan Distance: Useful for grid-based pathfinding, it estimates the distance based on
horizontal and vertical moves: h(n)=∣x2−x1∣+∣y2−y1∣
● Pathfinding Problems: Finding the shortest route in navigation systems (like GPS).
● Game Playing: Evaluating moves in board games like chess or checkers.
● Robotics: Navigating robots through environments.
● Puzzle Solving: Solving puzzles like the 8-puzzle or Sudoku.
● Artificial Intelligence: Inference and decision-making tasks where heuristic evaluation
is beneficial.
While both Best-First Search and A* Search use heuristics to guide the search, the main difference
lies in how they evaluate nodes:
● Best-First Search: Only uses the heuristic function h(n)h(n)h(n) to prioritize nodes. It selects nodes
based solely on their estimated cost to the goal.
● A Search*: Combines both the cost from the start to the node g(n) and the heuristic estimate h(n) to
form f(n)=g(n)+h(n). This makes A* more robust and often optimal, as it considers both the path cost
and the estimated cost to the goal.
Experiment No: 5
A* Algorithm
Aim
Write and implement the A* Algorithm to find path between start and goal state.
Algorithm
1. Initialization:
● Create a graph representation using an adjacency list.
● Define the heuristic function h(n), which estimates the cost from node n to the goal.
2. Input:
● Read the number of edges.
● For each edge, read the start_node, end_node, and weight, and construct the
adjacency list. If the graph is undirected, add both directed edges.
● Read the start_node and stop_node (goal).
3. Setup A Search*:
● Initialize the open list as a set containing the start_node.
● Initialize the closed list as an empty set.
● Create a dictionary g to store the cost of the shortest path from start_node to each node,
initialized with g[start_node]=0
● Create a dictionary parents to store the parent of each node for path reconstruction,
initialized with parents[start_node]=start_node
4. Main Loop (While open list is not empty):
● Select Current Node:
○ Find the node n in the open list with the lowest f(n)=g(n)+h(n)value. This is the
current_node.
● Goal Check:
○ If current_node is equal to stop_node (goal):
■ Reconstruct the path by tracing back from stop_node to start_node
using the parents dictionary.
■ Print the path and return it.
● Move Current Node:
○ Remove current_node from the open list and add it to the closed list.
● Process Neighbors:
○ For each neighbor of current_node:
■ If the neighbor is in the closed list, skip it.
■ Calculate the new cost to reach the neighbor:
new_cost=g[current_node]+weight
■ If the neighbor is not in the open list, add it.
■ If new_cost is greater than or equal to the current known cost of the
neighbor, skip it.
■ Update g and parents for the neighbor:
g[neighbor]=new_cost
parents[neighbor]=current_node
5. No Path Found:
● If the open list becomes empty and the goal has not been reached, print "Path does not exist!"
and return None.
Program
class Graph:
def __init__(self, adjacency_list):
# Initialize the graph with an adjacency list
self.adjacency_list = adjacency_list
while open_list:
# Select the node with the lowest f(n) = g(n) + h(n)
current_node = min(open_list, key=lambda n: g[n] + self.h(n))
if current_node == stop_node:
# Reconstruct the path from start_node to stop_node
path = []
while parents[current_node] != current_node:
path.append(current_node)
current_node = parents[current_node]
path.append(start_node)
path.reverse()
print('Path found:', path)
return path
def main():
# User input for the adjacency list
adjacency_list = {}
num_edges = int(input("Enter the number of edges: "))
for _ in range(num_edges):
edge = input("Enter edge in the format 'start_node end_node weight': ")
start_node, end_node, weight = edge.split()
weight = int(weight)
Viva Questions
A* is efficient and guarantees the shortest path in many scenarios. It combines the benefits of
Dijkstra's algorithm (finding the shortest path) and greedy search (using heuristics to guide the
search). A* is adaptable to various problem types due to its flexible heuristic.
A* can be inefficient if the heuristic is not well-designed or if the search space is very large. It also
requires more memory than some other algorithms, such as depth-first search, because it keeps track
of both the open and closed lists.
Experiment No: 6
Backtracking Algorithm for CSP- 4 Queens Problem
Aim
Write and implement the Backtracking Algorithm for CSP- 4 Queens Problem
Algorithm
1) Start in the leftmost column
2) If all queens are placed
return true
3) Try all rows in the current column.
Do the following for every tried row.
a) If the queen can be placed safely in this row then mark this [row, column] as part of the
solution and recursively check if placing queen here leads to a solution.
b) If placing the queen in [row, column] leads to a solution then return true.
c) If placing queen doesn't lead to a solution then unmark this [row, column] (Backtrack) and go to
step (a) to try other rows.
4) If all rows have been tried and nothing worked, return false to trigger backtracking.
Program
# Python program to solve N Queen
# Problem using backtracking
global N
N = 4
def printSolution(board):
for i in range(N):
for j in range(N):
print (board[i][j],end=' ')
print()
return True
if isSafe(board, i, col):
# Place this queen in board[i][col]
board[i][col] = 1
# This function solves the N Queen problem using Backtracking. It mainly uses
#solveNQUtil() to solve the problem. It returns false if queens cannot be placed,
# otherwise return true and placement of queens in the form of 1s.Note that there
# may be more than one solutions, this function prints one of the feasible
# solutions.
def solveNQ():
board = [ [0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
if solveNQUtil(board, 0) == False:
print ("Solution does not exist")
return False
printSolution(board)
return True
Result
The program is successfully executed and output is verified.
Viva Questions
1. What is the concept of CSP?
A Constraint Satisfaction Problem is a mathematical problem where the solution must meet a
number of constraints. In a CSP, the objective is to assign values to variables such that all the
constraints are satisfied.
2. What is the backtracking search for CSPs?
The term backtracking search is used for a depth-first search that chooses values for one variable at a
time and backtracks when a variable has no legal values left to assign.
3. Is backtracking BFS or DFS? DFS
4. What is the structure of a CSP?
An instance of a CSP is a triple (V,D,C) consisting of a set V of variables, a domain D, and a set C of
constraints. The objective is to find an assignment of values from D to the variables such that all
constraints in C are satisfied.
5. Is backtracking a greedy algorithm? No
6. What are the common applications of CSP?
Common applications of CSPs include:
● Scheduling: Assigning resources like employees or equipment while respecting time and
availability constraints.
● Planning: Organizing tasks with specific deadlines or sequences.
● Resource Allocation: Distributing resources efficiently without overuse.
7. What is the difference between backtracking and recursion?
The process in which a function calls itself directly or indirectly is called recursion and the
corresponding function is called a recursive function.
whereas
Backtracking is an algorithmic technique for solving problems recursively by trying to build a
solution incrementally, one piece at a time, removing those solutions that fail to satisfy the
constraints of the problem at any point in time
Experiment No: 7
Backtracking Algorithm for CSP -Map Coloring Problem
Aim
Write and implement the Map coloring Problem
Algorithm
1) Initialization:
● Start with all regions uncolored.
2) Recursive Coloring:
● For each node, try to assign a color.
● Check if the assignment is safe using the is_safe() function.
● If it is safe, recursively attempt to color the next node.
● If successful, propagate success back up.
● If not, backtrack and try the next color.
3) Termination:
● If all nodes are successfully colored, return the coloring.
● If all options are exhausted without a valid coloring, return failure.
Program
# Function to check if the color assignment is safe for the given node
def is_safe(node, color, graph, colors):
for neighbor in graph[node]:
if colors[neighbor] == color: # Check if the neighbor has the same color
return False
return True
return False
# Example usage
if __name__ == "__main__":
# Graph representation using adjacency list
# Here, 0 represents the first region, 1 the second, etc.
# Example: A graph with 4 regions
graph = [
[1, 2, 3], # Region 0 is connected to 1, 2, and 3
[0, 2], # Region 1 is connected to 0 and 2
[0, 1, 3], # Region 2 is connected to 0, 1, and 3
[0, 2] # Region 3 is connected to 0 and 2
]
m = 3 # Number of colors
map_coloring(graph, m)
Output
Solution exists: [1, 2, 3, 2]
Result
The program is successfully executed and output is verified.
Viva Questions
1. What is Map colouring?
Map colouring/Graph coloring refers to the problem of coloring vertices of a graph in such a way
that no two adjacent vertices have the same color. This is also called the vertex coloring problem. If
coloring is done using at most m colors, it is called m-coloring.
2. What is a chromatic number?
The minimum number of colors needed to color a graph is called its chromatic number.
Algorithm
1) Initialization:
● Read the distance matrix and determine the number of cities.
● Set initial values for the shortest path and minimum distance.
2) Generate Permutations:
● Use itertools.permutations to generate all possible routes (permutations) of the cities, starting
from the first city.
3) Calculate Distance:
● For each generated path, calculate the total travel distance.
● Update the shortest path and minimum distance if a new minimum is found.
4) Return Results:
● Once all permutations are evaluated, return the shortest path and the corresponding distance.
Program
import itertools
def traveling_salesman_bruteforce(distance_matrix):
n = len(distance_matrix)
# Generate all permutations of the cities (excluding the starting city)
cities = list(range(n))
shortest_path = None
min_distance = float('inf')
# Example usage
if __name__ == "__main__":
# Distance matrix for 4 cities
distance_matrix = [
[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]
]
Output
Shortest path: [0, 1, 3, 2]
Minimum distance: 80
Result
The program is successfully executed and output is verified.
Viva Questions
1. What is the Travelling Salesman Problem?
In TSP, a "salesman" starts at a home city, visits a list of given cities exactly once, and returns to the
home city, minimizing the total travel distance or cost.
2. What is the difficulty level of TSP?
It is NP-Hard problem- which means that it cannot be solved in polynomial time
3. What is the difference between the symmetric and asymmetric TSP?
Symmetric TSP assumes equal distances in both directions, leading to simpler calculations and
algorithms. Asymmetric TSP accounts for differing distances, requiring more complex approaches
to find optimal solutions.
Experiment No: 9
Min-max Algorithm
Aim
Implement min-max algorithm
Algorithm
1) Prompt User for Input
● Ask the user to enter the total number of scores (must be a power of 2).
● Initialize an empty list scores.
2) Input Scores
3) Calculate Tree Depth
● Calculate the depth of the tree (targetDepth) using the formula: treeDepth=log2(number
of scores)\text{treeDepth} = \log_2(\text{number of scores})treeDepth=log2(number of
scores)
● Convert this value to an integer for use in the Minimax function.
4) Define the Minimax Function
● Base Case: If the curDepth (current depth) equals targetDepth, return the score at
nodeIndex in scores.
● Recursive Case:
○ If it’s the maximizer’s turn (maxTurn is True):
■ Recursively call the minimax function for both child nodes (left and right).
■ Return the maximum of the two recursive calls.
○ If it’s the minimizer’s turn (maxTurn is False):
■ Recursively call the minimax function for both child nodes.
■ Return the minimum of the two recursive calls.
5) Run the Minimax Algorithm
6) Display Output
Program
import math
def minimax(curDepth, nodeIndex, maxTurn, scores, targetDepth):
# Base case: targetDepth reached
if curDepth == targetDepth:
return scores[nodeIndex]
if maxTurn:
# Maximizing player
return max(
minimax(curDepth + 1, nodeIndex * 2, False, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1, False, scores, targetDepth)
)
else:
# Minimizing player
return min(
minimax(curDepth + 1, nodeIndex * 2, True, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1, True, scores, targetDepth)
)
Output
Enter the number of scores (should be a power of 2): 8
Enter the scores:
3
5
2
9
12
5
23
23
The optimal value is: 12
Result
The program is successfully executed and output is verified.
Viva Questions
Minimax works by exploring the game tree recursively. Starting from the root (representing the
current state), it simulates all possible moves until it reaches a certain depth or end state. Each level
alternates between the maximizing player, who tries to pick the maximum score, and the minimizing
player, who tries to pick the minimum score. The process continues up the tree, with each player
choosing the best option until it reaches the top, where the optimal move is selected
A game tree is a graphical representation of all possible moves in a game, branching out to show the
possible outcomes of each move. In the Minimax algorithm, the game tree helps visualize all
potential states the game can reach.
The primary limitation of Minimax is that it becomes computationally expensive as the game tree
grows, making it difficult to apply to games with large search spaces, like chess.
Alpha-beta pruning is an optimization technique for the Minimax algorithm. It "prunes" branches of
the game tree that don't need to be explored because they cannot affect the final decision
In the Minimax algorithm, the "maximizer" is the player who aims to maximize their score,
choosing moves that lead to the highest possible value. The "minimizer" is the opponent, who tries to
minimize the maximizer's score by choosing moves that lead to the lowest possible outcome. These
roles alternate at each level of the game tree, simulating both players' optimal strategies.
The time complexity of the Minimax algorithm is O(b^d), where b is the branching factor (the
average number of moves available at each point) and d is the depth of the tree.
Algorithm
1) Input Leaf Node Values:
2) Initialize Constants:
● Set MAX to a large positive number and MIN to a large negative number, which are
used for alpha-beta pruning.
3) Define minimax Function:
● If at maximum depth, return the value of the current node.
● If maximizing player:
○ Set best to MIN. For each child:
■ Call minimax with updated parameters, toggle to the minimizing
player.
■ Update best and alpha.
■ Prune if beta <= alpha.
○ Return best.
If minimizing player:
Program
import math
if depth == 3:
return values[nodeIndex]
if maximizingPlayer:
best = MIN
# Alpha-Beta Pruning
break
return best
else:
best = MAX
# Alpha-Beta Pruning
break
return best
# Driver Code
if __name__ == "__main__":
# Prompt user to input the number of values (should be a power of 2)
num_values = int(input("Enter the number of leaf nodes (should be a power of 2): "))
else:
values = []
for _ in range(num_values):
value = int(input())
values.append(value)
Output
Enter the number of leaf nodes (should be a power of 2): 8
-1