AIML Lab Programs1-9
AIML Lab Programs1-9
Algorithm:
Step 1: Initialization:
Queue: Initialize a queue and add the starting node to it. This queue will help in exploring
nodes level by level.
Visited Set: Create a set to keep track of visited nodes to avoid processing the same
node multiple times.
For each neighbor of the current node, if it has not been visited, mark it as visited and
enqueue it. Also, keep track of the path by storing the parent of each node or the path
taken to reach the node.
Step 4: Repeat steps 2 and 3 until the queue is empty or the target node is found.
graph = {
'1': ['2', '3'],
'2': ['4', '5'],
'3': ['6', '7'],
'4': [],
'5': [],
'6': [],
'7': []
}
# BFS implementation
visited = [] # List for visited nodes.
queue = [] # Initialize a queue
while queue:
m = queue.pop(0) # Pop the first element from the queue
print(m, end=" ")
# Calling the BFS function starting from node '5' and searching
for goal state '8'
ALGORITHM:
Step 1: Initialization:
Stack: Initialize a stack and push the starting node onto it. This stack will help in
exploring nodes depth-first.
Visited Set: Create a set to keep track of visited nodes to avoid processing the same
node multiple times.
For each neighbor of the current node, if it has not been visited, mark it as visited and
push it onto the stack. Also, keep track of the path by storing the parent of each node or
the path taken to reach the node.
Step 4: Repeat steps 2 and 3 until the stack is empty or the target node is found. Step 5: Return
the Result:
If the target node is found, return the path or node.
If the stack becomes empty without finding the target node, return a failure
Program 2:
OUTPUT:
Path found: ['1', '2', '5']
Algorithm:
Step 1: Understand the Problem:
You have two jugs with capacities liters and b liters.
Your goal is to measure exactly liters of water.
Operations allowed:
(1) Fill a jug completely.
(2) Empty a jug completely.
(3) Pour water from one jug to another until one of the jugs is either full or
empty.
If the BFS completes without finding a state where one of the jugs contains exactly
litres, return False (failure)
Program 3:
while queue:
current_state = queue.popleft()
jug1, jug2, steps = current_state
visited.add((jug1, jug2))
#Fill jug1
queue.append((capacity_jug1, jug2, steps + [(jug1, jug2,
f"Fill jug 1 ({capacity_jug1}, {jug2})")]))
# Fill jug2
queue.append((jug1, capacity_jug2, steps + [(jug1, jug2,
f"Fill jug 2 ({jug1},{capacity_jug2})")]))
# Empty jug1
queue.append((0, jug2, steps + [(jug1, jug2, f"Empty jug 1 (0,
{jug2})")]))
# Empty jug2
queue.append((jug1, 0, steps + [(jug1, jug2, f"Empty jug 2
({jug1}, 0)")]))
# Example usage
capacity_jug1 = 4
capacity_jug2 = 3
target_amount = 2
solution = water_jug_problem(capacity_jug1, capacity_jug2,
target_amount)
if solution:
print("Steps to reach the desired state:")
for step in solution:
print(step)
else:
print("No solution found.")
Output:
Algorithm:
If the goal node is reached, return the path and the total cost.
If the priority queue is empty and the goal node has not been reached, return failure (no
path exists).
Program 4:
import heapq
def ucs(graph, start, goal):
queue = [(0, start, [])] # Initialize the priority queue
with the start node
while queue:
cost, node, path = heapq.heappop(queue) # Get the node
with the lowest cost
if node == goal:
return cost, path + [node] # Return the total cost
and path if goal is reached
if cost != float("inf"):
print(f"Cost: {cost}")
print(f"Path: {' -> '.join(path)}")
else:
print("Goal node not found")
Output:
5. Write a Python program to implement Depth Limited Search
Algorithm:
Step 1: Initialization:
Stack: Initialize a stack and push the starting node onto it along with its depth
(usually starting at 0).
Visited Set: Optionally, create a set to keep track of visited nodes to avoid processing
the same node multiple times within the same depth.
Pop the top node from the stack along with its depth.
If this node is the target node, return the path or the node as the solution.
If the current depth is equal to the depth limit, do not expand this node further.
Otherwise, explore all adjacent nodes (neighbors) of the popped node.
Step 3: For each neighbor of the current node, if it has not been visited and the depth is within
the limit, mark it as visited (if using a visited set) and push it onto the stack along with its depth
(current depth + 1).
Step 4: Repeat steps 2 and 3 until the stack is empty or the target node is found. Step 5:Return
the Result:
while stack:
node, path = stack.pop()
if node == goal:
return path
if path:
print("Path found:", path)
else:
print(f"No path found within depth limit
{depth_limit}.")
Output
6. Write a Python program to implement Iterative Deepening Depth First Search
Algorithm:
Iterative Deepening:
Step 3: Repeat
Continue increasing the depth limit and performing DLS until the target node is
found or there are no more nodes to explore within the new depth limit.
Program 6:
while True:
result, path = depth_limited_search(start, goal, depth, get_children,
[], 0)
if node == goal:
return node, path
elif depth_limit == 0:
path.pop() # Remove current node from the path before backtracking
return None, path
else:
for child in get_children(node):
result, child_path = depth_limited_search(child, goal,
depth_limit - 1, get_children, path, level + 1)
if result is not None:
return result, child_path
path.pop() # Remove current node from the path before
backtracking
return None, path
if __name__ == "__main__":
# Define the tree as an adjacency list
tree = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': ['G'],
'E': [],
'F': [],
'G': []
}
def get_children(node):
return tree.get(node, [])
# Perform Iterative Deepening Search to find 'G'
start_node = 'A'
goal_node = 'G'
result, path, level = iterative_deepening_search(start_node, goal_node,
get_children)
if result:
print(f"Goal node found: {result}")
print(f"Path: {' -> '.join(path)}")
print(f"Level: {level}")
else:
print("Goal node not found")
Output:
7. Write a Python program to implement A* Search.
Algorithm
Step 1:Initialize:
a. Current Node:
Remove the node with the lowest f value from openList and call it currentNode.
Add currentNode to closedList.
b. Goal Test:
If currentNode is the goal node, construct the path from the start node to the goal node by
tracing back through the parent nodes and return it.
c. Generate Successors:
For each neighbor of currentNode:
Set g to be the g value of currentNode plus the cost to move from currentNode
to the neighbor.
Calculate h, the heuristic estimate of the cost from the neighbor to the goal.
Calculate f = g + h.
If the neighbor is not in openList, add it with the calculated f, g, and h values,
and set its parent to currentNode.
If the neighbor is in openList but the new g value is lower than the existing g
value, update the neighbor's g value, f value, and parent.
start = 'S'
dest = 'G'
# Run the A* algorithm
distances, parent = a_star(graph, start, dest, heuristic)
path = generate_path_from_parents(parent, start, dest)
# Calculate total path cost
total_cost = distances[dest]
print('Distances:', distances)
print('Parents:', parent)
print('Optimal Path:', path)
print('Total Path Cost:', total_cost)
Output:
Algorithm:
The children of a node represent possible game states resulting from the next move.
Step 2: Scoring:
Each leaf node (end game state) has a score representing the outcome of the game from the
perspective of the maximizing player.
Positive scores indicate a win for the maximizing player, negative scores indicate a win for
the minimizing player, and zero indicates a draw.
Step 4: Base Case: If the game is over (leaf node), return the score of the game state.
Step 5: Recursive Case: Evaluate the scores of the child nodes and choose the optimal score for the
current player.
Program 8:
import math
def minimax(curDepth, nodeIndex, maxTurn, scores, targetDepth):
# Base case: targetDepth reached
if curDepth == targetDepth:
return scores[nodeIndex]
if maxTurn:
return max(
minimax(curDepth + 1, nodeIndex * 2, False, scores,
targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1, False, scores,
targetDepth)
)
else:
return min(
minimax(curDepth + 1, nodeIndex * 2, True, scores,
targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1, True, scores,
targetDepth)
)
scores = [-1, 4, 2, 6, -3, -5, 0, 7]
treeDepth = math.log(len(scores), 2)
Output:
The optimal value is : 4
9. Write a Program to implement Alpha-Beta Pruning using Python.
Algorithm:
Alpha: The best value that the maximizing player can guarantee at that level or above.
Beta: The best value that the minimizing player can guarantee at that level or above.
At each node, the algorithm keeps track of the two values, alpha and beta, which represent the
minimum score that the maximizing player is assured and the maximum score that the minimizing
player is assured, respectively.
These values are updated as the algorithm progresses and are used to prune branches that cannot
affect the final decision.
If at any point the algorithm finds a move that proves to be worse than a previously examined
move, it stops evaluating that branch (prunes it).
If the game is over (leaf node), return the score of the game state.
Evaluate the scores of the child nodes while updating alpha and beta, and prune branches
when possible.
Program 9:
if maximizingPlayer:
best = MIN
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i,
False, values, alpha, beta)
best = max(best, val)
alpha = max(alpha, best)
if beta <= alpha:
break
return best
else:
best = MAX
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i,
True, values, alpha, beta)
best = min(best, val)
beta = min(beta, best)
if beta <= alpha:
break
return best
if __name__ == "__main__":
values = []
num_nodes = int(input("Enter the number of nodes: "))
for i in range(num_nodes):
value = int(input(f"Enter value for node {i}: "))
values.append(value)
print("The optimal value is:", minimax(0, 0, True, values,
MIN, MAX))
Output:
Enter the number of nodes: 8
Enter value for node 0: -1
Enter value for node 1: 4
Enter value for node 2: 2
Enter value for node 3: 6
Enter value for node 4: -3
Enter value for node 5: -5
Enter value for node 6: 0
Enter value for node 7: 7
The optimal value is: 4