Date: Exp No: Page:
Aim: To write a program to implement DFS and BFS.
Description:
Depth First Search (DFS):
A graph/tree traversal algorithm that explores a path deeply before backtracking.
Uses a stack (recursion or explicit).
Steps:
1. Start from source node.
2. Visit an unvisited neighbor.
3. Repeat until no unvisited neighbors, then backtrack.
Applications: Cycle detection, topological sorting, path finding in puzzles.
Breadth First Search (BFS):
A level-order traversal algorithm that explores neighbors first, then the next level.
Uses a queue.
Steps:
1. Start from source node.
2. Visit all neighbors.
3. Move to next level neighbors.
Applications: Shortest path in unweighted graphs, network broadcasting, peer-to-peer systems.
Program:
from collections import deque, defaultdict
class Graph:
def __init__(self):
self.graph = defaultdict(list)
def add_edge(self, u, v):
self.graph[u].append(v)
def dfs(self, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
print(start, end=' ')
for neighbor in self.graph[start]:
if neighbor not in visited:
self.dfs(neighbor, visited)
def bfs(self, start):
visited = set()
queue = deque([start])
visited.add(start)
while queue:
vertex = queue.popleft()
print(vertex, end=' ')
for neighbor in self.graph[vertex]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
g = Graph()
n = int(input("Enter number of edges: "))
for _ in range(n):
u, v = map(int, input("Enter edge (u v): ").split())
g.add_edge(u, v)
start = int(input("Enter starting node: "))
print("\nDFS Traversal:")
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
g.dfs(start)
print("\nBFS Traversal:")
g.bfs(start)
Output:
Enter number of edges: 4
Enter edge (u v): 0 1
Enter edge (u v): 0 4
Enter edge (u v): 1 3
Enter edge (u v): 2 6
Enter starting node: 1
DFS Traversal:
13
BFS Traversal:
13
Result:
1. Depth First Search (DFS)
Completeness: ❌ Not complete (fails in infinite-depth graphs). ✅ Complete in finite graphs.
Optimality: ❌ Not optimal (may find longer path first).
Time Complexity: O(bm)O(b^m)O(bm) (b = branching factor, m = maximum depth).
Space Complexity: O(bm)O(bm)O(bm) (linear in depth).
2. Breadth First Search (BFS)
Completeness: ✅ Complete (if branching factor is finite).
Optimality: ✅ Optimal for unweighted graphs.
Time Complexity: O(bd)O(b^d)O(bd) (b = branching factor, d = depth of shallowest goal).
Space Complexity: O(bd)O(b^d)O(bd) (stores all nodes in frontier).
Hence, the program to implement BFS and DFS has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a Program to find the solution for traveling salesman Problem.
Description:
Traveling Salesman Problem (TSP)
A combinatorial optimization problem.
Problem: A salesman must visit each city once and return to the starting city with minimum cost.
Nature: NP-hard problem.
Approaches:
o Brute force (check all permutations).
o Dynamic programming (Held-Karp algorithm).
o Approximation algorithms (nearest neighbor, branch and bound).
Applications: Logistics, manufacturing, microchip design.
Program:
import itertools
def tsp(graph, start):
vertices = list(range(len(graph)))
vertices.remove(start)
min_path = float('inf')
best_route = []
for perm in itertools.permutations(vertices):
cost = 0
k = start
for j in perm:
cost += graph[k][j]
k=j
cost += graph[k][start]
if cost < min_path:
min_path = cost
best_route = [start] + list(perm) + [start]
return best_route, min_path
n = int(input("Enter number of cities: "))
graph = []
print("Enter cost matrix (space-separated):")
for i in range(n):
row = list(map(int, input(f"Row {i+1}: ").split()))
graph.append(row)
start = int(input("Enter starting city (0-indexed): "))
route, cost = tsp(graph, start)
print(f"\nBest Route: {route}")
print(f"Minimum Cost: {cost}")
Output:
Enter number of cities: 4
Enter cost matrix (space-separated):
Row 1: 0 15 10 20
Row 2: 25 0 10 15
Row 3: 35 30 0 10
Row 4: 10 20 25 0
Enter starting city (0-indexed): 0
Best Route: [0, 1, 2, 3, 0]
Minimum Cost: 45
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Result:
Completeness: ✅ Complete (if using exact algorithms like DP/Brute force).
Optimality: ✅ Optimal with exact algorithms, ❌ not guaranteed with approximations.
Time Complexity:
Brute force: O(n!)O(n!)O(n!).
DP (Held-Karp): O(n22n)O(n^2 2^n)O(n22n).
Space Complexity:
Brute force: O(n)O(n)O(n).
DP: O(n2n)O(n 2^n)O(n2n).
Hence, the program to implement the travelling sales person problem has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement Simulated Annealing Algorithm.
Description:
Simulated Annealing Algorithm
A probabilistic optimization algorithm inspired by metal annealing.
Idea:
o Start with high temperature → explore widely (accept even worse solutions).
o Gradually reduce temperature → search stabilizes to optimal/near-optimal solution.
Key Feature: Accepts worse solutions with probability exp(-ΔE/T).
Applications: TSP, job scheduling, circuit design, machine learning model tuning.
Program:
import math
import random
def objective_function(x):
return x**2+ 10 * math.sin(x)
def simulated_annealing(start, temp, cooling):
current = start
T = temp
while T > 0.1:
new = current + random.uniform(-1, 1)
delta = objective_function(new) - objective_function(current)
if delta < 0 or math.exp(-delta / T) > random.random():
current = new
T *= cooling
return current, objective_function(current)
start = float(input("Enter starting point: "))
temp = float(input("Enter initial temperature (e.g., 1000): "))
cooling = float(input("Enter cooling rate (e.g., 0.95): "))
result, value = simulated_annealing(start, temp, cooling)
print(f"\nApproximate Minimum at x = {result:.4f}, f(x) = {value:.4f}")
output:
Enter starting point: 0
Enter initial temperature (e.g., 1000): 3000
Enter cooling rate (e.g., 0.95): 0.7
Approximate Minimum at x = -1.3134, f(x) = -7.9455
Result:
Completeness: ❌ Not complete (may fail if cooling schedule is poor).
Optimality: ❌ Not optimal (gives near-optimal solutions).
Time Complexity: Depends on schedule; often O(k)O(k)O(k), where kkk is iterations.
Space Complexity: O(1)O(1)O(1).
Hence, the program to implement Simulated Annealing Algorithm has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to find the solution for the wumpus world problem.
Description:
Wumpus World Problem
A knowledge-based AI environment.
Environment: A grid cave with pits, a Wumpus (monster), and gold.
Percepts:
o Breeze → pit nearby.
o Stench → Wumpus nearby.
o Glitter → gold in current cell.
Goal: Agent must grab gold and exit safely without falling into pit or being eaten.
AI Concept: Uses logical reasoning (propositional logic, inference rules) to act safely.
Program:
class WumpusWorld:
def __init__(self, grid, agent_pos):
self.grid = grid
self.rows = len(grid)
self.cols = len(grid[0])
self.agent_pos = agent_pos
def perceive(self, pos):
x, y = pos
tile = self.grid[x][y]
if tile == 'W':
return "Wumpus! Danger!"
elif tile == 'P':
return "Pit! Danger!"
elif tile == 'G':
return "Gold! You win!"
else:
return "Safe"
def move_agent(self, new_pos):
self.agent_pos = new_pos
return self.perceive(new_pos)
rows = int(input("Enter number of rows: "))
cols = int(input("Enter number of columns: "))
print(f"\nEnter the {rows}x{cols} Wumpus World grid row by row.")
print("Use symbols: '.' = empty, 'W' = Wumpus, 'P' = Pit, 'G' = Gold, 'A' = Agent")
grid = []
agent_pos = None
for i in range(rows):
while True:
row = input(f"Row {i+1} (space separated): ").split()
if len(row) != cols:
print(f"Please enter exactly {cols} values.")
continue
grid.append(row)
for j, val in enumerate(row):
if val == 'A':
agent_pos = (i, j)
break
if agent_pos is None:
print("No agent 'A' found! Please restart and enter again.")
exit()
world = WumpusWorld(grid, agent_pos)
print("\nEnter moves in format 'x y' (0-based index). Type 'exit' to quit.")
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
while True:
move = input("Move to: ")
if move.lower() == 'exit':
break
try:
x, y = map(int, move.split())
if 0 <= x < rows and 0 <= y < cols:
print(f"Perception: {world.move_agent((x, y))}")
else:
print("Invalid move. Out of bounds.")
except:
print("Invalid format. Enter as: x y")
Output:
Enter number of rows: 3
Enter number of columns: 3
Enter the 3x3 Wumpus World grid row by row.
Use symbols: '.' = empty, 'W' = Wumpus, 'P' = Pit, 'G' = Gold, 'A' = Agent
Row 1 (space separated): . . W
Row 2 (space separated): A . .
Row 3 (space separated): P . G
Enter moves in format 'x y' (0-based index). Type 'exit' to quit.
Move to: 1 2
Perception: Safe
Move to: 2 2
Perception: Gold! You win!
Move to: exit
Result:
Completeness: ✅ Complete (if reasoning rules cover all cases).
Optimality: ✅ Optimal if logical inference is correct.
Time Complexity: Exponential in worst case (logical inference = NP-hard).
Space Complexity: Exponential (needs to store knowledge base).
Hence, the program to find the solution for the wumpus world problem has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement N-queen problem.
Description:
N-Queen Problem
Definition:
A constraint satisfaction problem (CSP) where 8 queens must be placed on a chessboard (8×8) so
that no two queens attack each other.
Constraints:
o No two queens in the same row.
o No two queens in the same column.
o No two queens in the same diagonal.
Approaches:
o Backtracking Algorithm: Place queens row by row; if conflict occurs, backtrack.
o Hill Climbing / Simulated Annealing: Local search methods.
o Genetic Algorithm: Evolutionary approach.
Applications:
o Demonstrates backtracking and search algorithms.
o Used in testing constraint satisfaction techniques.
o Extensible to N-Queen problem for larger boards.
Program:
def print_board(solution, N):
board = []
for row in range(N):
line = ""
for col in range(N):
if solution[row] == col:
line += "Q "
else:
line += ". "
board.append(line.strip())
return "\n".join(board)
def is_safe(position, row, col):
for i in range(row):
if position[i] == col or \
position[i] - i == col - row or \
position[i] + i == col + row:
return False
return True
def solve_n_queens(N):
solutions = []
def backtrack(row, position):
if row == N:
solutions.append(position[:])
return
for col in range(N):
if is_safe(position, row, col):
position[row] = col
backtrack(row + 1, position)
position = [-1] * N
backtrack(0, position)
return solutions
N = int(input("Enter the number of queens (N): "))
solutions = solve_n_queens(N)
print(f"\nTotal solutions for {N}-Queens: {len(solutions)}\n")
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
for idx, solution in enumerate(solutions, 1):
print(f"Solution {idx}:\n{print_board(solution, N)}\n")
Output:
Enter the number of queens (N): 4
Total solutions for 4-Queens: 2
Solution 1:
.Q..
...Q
Q...
..Q.
Solution 2:
..Q.
Q...
...Q
.Q..
Result:
Completeness: ✅ Complete (backtracking always finds solution).
Optimality: ✅ Optimal (finds valid arrangement).
Time Complexity: O(N!)O(N!)O(N!) for brute force; backtracking reduces it but still exponential.
Space Complexity: O(N)O(N)O(N) (stack depth for recursion).
Hence, the program to implement N-Queen problem has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement 8 puzzle problem.
Description:
8 Puzzle Problem
A sliding puzzle with tiles numbered 1–8 and one blank space on a 3×3 grid.
Goal: Arrange tiles in a predefined goal state (usually ascending order).
Moves: Slide an adjacent tile into the blank space.
Solution Approaches:
o BFS/DFS for small depth.
o A* algorithm with heuristics:
Misplaced tiles.
Manhattan distance.
Applications: Demonstrates state space search and heuristic problem solving.
Program:
import heapq
GOAL = [[1, 2, 3],
[4, 5, 6],
[7, 8, 0]]
MOVES = [("Up", -1, 0), ("Down", 1, 0), ("Left", 0, -1), ("Right", 0, 1)]
def manhattan_distance(state):
distance = 0
for i in range(3):
for j in range(3):
val = state[i][j]
if val != 0: # Ignore blank
goal_x, goal_y = divmod(val - 1, 3)
distance += abs(goal_x - i) + abs(goal_y - j)
return distance
def get_blank_position(state):
for i in range(3):
for j in range(3):
if state[i][j] == 0:
return i, j
def is_goal(state):
return state == GOAL
def state_to_tuple(state):
return tuple(tuple(row) for row in state)
def clone_state(state):
return [row[:] for row in state]
def print_state(state):
for row in state:
print(" ".join(str(x) if x != 0 else "." for x in row))
print()
def make_move(state, move):
x, y = get_blank_position(state)
dx, dy = 0, 0
for name, mx, my in MOVES:
if name == move:
dx, dy = mx, my
break
new_x, new_y = x + dx, y + dy
new_state = clone_state(state)
new_state[x][y], new_state[new_x][new_y] = new_state[new_x][new_y], new_state[x][y]
return new_state
def is_solvable(state):
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
flat = [num for row in state for num in row if num != 0]
inversions = 0
for i in range(len(flat)):
for j in range(i + 1, len(flat)):
if flat[i] > flat[j]:
inversions += 1
return inversions % 2 == 0
def a_star(initial_state):
open_list = []
heapq.heappush(open_list, (manhattan_distance(initial_state), 0, initial_state, []))
visited = set()
while open_list:
f, g, current, path = heapq.heappop(open_list)
if is_goal(current):
print("\nReached Goal State in", g, "moves!\n")
print("Solution Path:")
state = initial_state
print_state(state) # Show initial
for step, move in enumerate(path, 1):
print(f"Move {step}: {move}")
state = make_move(state, move)
print_state(state)
return
visited.add(state_to_tuple(current))
x, y = get_blank_position(current)
for move_name, dx, dy in MOVES:
new_x, new_y = x + dx, y + dy
new_state = clone_state(current)
new_state[x][y], new_state[new_x][new_y] = new_state[new_x][new_y], new_state[x][y]
if state_to_tuple(new_state) not in visited:
new_path = path + [move_name]
h = manhattan_distance(new_state)
heapq.heappush(open_list, (g + 1 + h, g + 1, new_state, new_path))
print("No solution found.")
print("Enter the initial 8-puzzle state row by row (use 0 for blank):")
initial_state = []
for _ in range(3):
row = list(map(int, input().split()))
initial_state.append(row)
print("\nInitial State:")
print_state(initial_state)
if is_solvable(initial_state):
a_star(initial_state)
else:
print("This puzzle configuration is unsolvable.")
Output:
Enter the initial 8-puzzle state row by row (use 0 for blank):
123
456
780
Initial State:
123
456
78.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Reached Goal State in 0 moves!
Solution Path:
123
456
78.
Result:
Completeness: ✅ Complete with BFS, A*.
Optimality: ✅ Optimal with A* (admissible heuristic), ❌ not with DFS.
Time Complexity:
o BFS: O(bd)O(b^d)O(bd).
o A*: O(bd)O(b^d)O(bd), but faster with heuristics.
Space Complexity:
o BFS: O(bd)O(b^d)O(bd).
o A*: O(bd)O(b^d)O(bd).
Hence, the program to implement 8 puzzle problem has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement Towers of Hanoi problem.
Description:
Towers of Hanoi Problem
A mathematical puzzle with 3 rods and N disks of different sizes.
Rules:
1. Only one disk moved at a time.
2. Larger disk cannot be placed on smaller disk.
Solution: Recursive method:
o Move (N-1) disks → auxiliary rod.
o Move largest disk → target rod.
o Move (N-1) disks → target rod.
Applications: Teaching recursion, algorithm analysis.
Program:
def towers_of_hanoi(n, source, auxiliary, destination):
if n == 1:
print(f"Move disk 1 from {source} to {destination}")
return
towers_of_hanoi(n - 1, source, destination, auxiliary)
print(f"Move disk {n} from {source} to {destination}")
towers_of_hanoi(n - 1, auxiliary, source, destination)
try:
n = int(input("Enter number of disks: "))
print(f"\nTowers of Hanoi solution for {n} disks:\n")
towers_of_hanoi(n, 'A', 'B', 'C')
print(f"\nTotal moves required: {2**n - 1}")
except ValueError:
print("Please enter a valid integer.")
Output:
Enter number of disks: 3
Towers of Hanoi solution for 3 disks:
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
Total moves required: 7
Result:
Completeness: ✅ Complete.
Optimality: ✅ Optimal (always solves in minimum moves).
Time Complexity: O(2n)O(2^n)O(2n).
Space Complexity: O(n)O(n)O(n) (recursive call stack).
Hence, the program to implement Towers of Hanoi problem has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement best first search algorithm.
Description:
Best First Search (BFS – Informed Search)
Definition:
Best First Search is an informed search algorithm that uses heuristic information to decide which
node to explore first.
Working Principle:
o It evaluates nodes using a heuristic function h(n) (estimated cost from node n to goal).
o Always selects the node with the lowest h(n) value.
o Uses a priority queue to store nodes.
Steps:
1. Start from the initial node.
2. Put neighbors into a priority queue, ordered by heuristic value.
3. Expand the most promising node (lowest h(n)).
4. Continue until the goal is found or queue is empty.
Properties:
o Not guaranteed to find the shortest path (greedy).
o Faster than uninformed methods like DFS/BFS.
Applications:
o Pathfinding in AI (games, maps).
o Network routing.
o Solving puzzles (8-puzzle, 8-queen, etc.).
Program:
import heapq
def best_first_search(graph, heuristics, start, goal):
pq = []
heapq.heappush(pq, (heuristics[start], start)) # (heuristic, node)
visited = set()
while pq:
_, current = heapq.heappop(pq)
if current in visited:
continue
print(current, end=" -> ")
visited.add(current)
if current == goal:
print("Goal reached!")
return
for neighbor in graph.get(current, []):
if neighbor not in visited:
heapq.heappush(pq, (heuristics[neighbor], neighbor))
print("Goal not found!")
graph = {}
n = int(input("Enter number of nodes: ").strip())
for _ in range(n):
node = input("Node name: ").strip()
neighbors_input = input(f"Neighbors of {node} (comma-separated, leave blank if none): ").strip()
if neighbors_input:
graph[node] = [x.strip() for x in neighbors_input.split(",")]
else:
graph[node] = []
heuristics = {}
for node in graph:
heuristics[node] = int(input(f"Heuristic for {node}: ").strip())
start_node = input("Enter start node: ").strip()
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
goal_node = input("Enter goal node: ").strip()
print("\n--- Best First Search Path ---")
best_first_search(graph, heuristics, start_node, goal_node)
Output:
Enter number of nodes: 2
Node name: S
Neighbors of S (comma-separated, leave blank if none): A
Node name: A
Neighbors of A (comma-separated, leave blank if none):
Heuristic for S: 1
Heuristic for A: 0
Enter start node: S
Enter goal node: A
--- Best First Search Path ---
S -> A -> Goal reached!
Result:
Completeness: ❌ Not complete (can get stuck in loops). ✅ Complete if cycle-checking is added.
Optimality: ❌ Not optimal (greedy by h(n)).
Time Complexity: O(bm)O(b^m)O(bm) (m = maximum depth).
Space Complexity: O(bm)O(b^m)O(bm).
Hence, the program to implement best first search has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement A* algorithm.
Description:
A* Algorithm
An informed search algorithm.
Evaluation Function:
f(n)=g(n)+h(n)
f(n) = g(n) + h(n)
f(n)=g(n)+h(n)
o g(n) = cost so far.
o h(n) = heuristic (estimated cost to goal).
Properties:
o Complete (finds a solution if exists).
o Optimal (if h(n) is admissible).
Applications: Shortest path in GPS, robotics, AI games.
Program:
from queue import PriorityQueue
def astar_search(graph, heuristics, start, goal):
open_set = PriorityQueue()
open_set.put((0, start))
came_from = {}
g_score = {node: float('inf') for node in graph}
g_score[start] = 0
f_score = {node: float('inf') for node in graph}
f_score[start] = heuristics[start]
while not open_set.empty():
_, current = open_set.get()
if current == goal:
return reconstruct_path(came_from, current)
for neighbor, cost in graph[current]:
tentative_g = g_score[current] + cost
if tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + heuristics[neighbor]
open_set.put((f_score[neighbor], neighbor))
return None
def reconstruct_path(came_from, current):
path = [current]
while current in came_from:
current = came_from[current]
path.append(current)
path.reverse()
return path
graph = {}
n = int(input("Enter number of nodes: "))
print("Enter graph edges and costs (format: neighbor cost), type 'done' to stop for a node.")
for i in range(n):
node = input(f"Enter node name {i+1}: ")
graph[node] = []
while True:
edge = input(f" Neighbor and cost from {node} (or 'done'): ")
if edge.lower() == "done":
break
neighbor, cost = edge.split()
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
graph[node].append((neighbor, int(cost)))
heuristics = {}
print("\nEnter heuristic values for each node:")
for node in graph:
heuristics[node] = int(input(f"Heuristic for {node}: "))
start = input("\nEnter start node: ")
goal = input("Enter goal node: ")
path = astar_search(graph, heuristics, start, goal)
print("\n--- A* Search Result ---")
if path:
print("Path found:", " -> ".join(path))
else:
print("No path found!")
Output:
Enter number of nodes: 3
Enter graph edges and costs (format: neighbor cost), type 'done' to stop for a node.
Enter node name 1: S
Neighbor and cost from S (or 'done'): A 1
Neighbor and cost from S (or 'done'): B 4
Neighbor and cost from S (or 'done'): done
Enter node name 2: A
Neighbor and cost from A (or 'done'): done
Enter node name 3: B
Neighbor and cost from B (or 'done'): done
Enter heuristic values for each node:
Heuristic for S: 2
Heuristic for A: 1
Heuristic for B: 0
Enter start node: S
Enter goal node: B
--- A* Search Result ---
Path found: S -> B
Result:
Completeness: ✅ Complete (if branching factor finite and h(n) admissible).
Optimality: ✅ Optimal with admissible heuristic.
Time Complexity: O(bd)O(b^d)O(bd) worst case.
Space Complexity: O(bd)O(b^d)O(bd) (keeps all generated nodes in memory).
Hence, the program to implement A* algorithm has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
Aim: To write a program to implement AO* Algorithm.
Description:
AO Algorithm*
An algorithm for searching AND-OR graphs.
Graph Structure:
o OR node: Choose one child (alternative solutions).
o AND node: Must solve all children (subproblems).
Working:
o Uses heuristics.
o Expands nodes, updates costs, backtracks if needed.
Applications:
o Problem reduction in AI.
o Planning systems.
o Game playing with multiple strategies.
Program:
class Graph:
def __init__(self, graph, heuristics, start):
self.graph = graph
self.H = heuristics
self.start = start
self.status = {}
self.solution_graph = {}
def get_neighbors(self, node):
return self.graph.get(node, [])
def get_status(self, node):
return self.status.get(node, 0)
def set_status(self, node, value):
self.status[node] = value
def ao_star(self, node):
print(f"Expanding node: {node}")
if self.get_status(node) == -1:
return
neighbors = self.get_neighbors(node)
if not neighbors:
self.set_status(node, -1)
return
min_cost = float('inf')
best_path = None
for option in neighbors:
cost = 0
for child in option:
cost += self.H[child] + 1 # edge cost = 1
if cost < min_cost:
min_cost = cost
best_path = option
self.H[node] = min_cost
self.solution_graph[node] = best_path
solved = True
for child in best_path:
if self.get_status(child) != -1:
solved = False
break
if solved:
self.set_status(node, -1)
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
for child in best_path:
self.ao_star(child)
def get_solution(self):
return self.solution_graph
def take_input():
graph = {}
heuristics = {}
n = int(input("Enter number of nodes: "))
for i in range(n):
node = input(f"Enter node name {i+1}: ")
graph[node] = []
while True:
option = input(f" Enter AND/OR option for {node} (space separated nodes, or 'done'): ")
if option.lower() == "done":
break
graph[node].append(option.split())
print("\nEnter heuristic values for each node:")
for node in graph:
heuristics[node] = int(input(f"Heuristic for {node}: "))
start_node = input("\nEnter start node: ")
return graph, heuristics, start_node
if __name__ == "__main__":
graph, heuristics, start_node = take_input()
ao = Graph(graph, heuristics, start_node)
ao.ao_star(start_node)
print("\n--- Solution Graph ---")
for key, val in ao.get_solution().items():
print(f"{key} -> {val}")
Output:
Enter number of nodes: 4
Enter node name 1: S
Enter AND/OR option for S (space separated nodes, or 'done'): AB
Enter AND/OR option for S (space separated nodes, or 'done'): done
Enter node name 2: A
Enter AND/OR option for A (space separated nodes, or 'done'): C
Enter AND/OR option for A (space separated nodes, or 'done'): done
Enter node name 3: B
Enter AND/OR option for B (space separated nodes, or 'done'): done
Enter node name 4: C
Enter AND/OR option for C (space separated nodes, or 'done'): done
Enter heuristic values for each node:
Heuristic for S: 3
Heuristic for A: 2
Heuristic for B: 1
Heuristic for C: 0
Enter start node: S
Expanding node: S
Expanding node: A
Expanding node: C
Expanding node: B
CSE Dept. ARTIFICIAL INTELLIGENCE LAB
Date: Exp No: Page:
--- Solution Graph ---
S -> ['A', 'B']
A -> ['C']
Result:
Completeness: ✅ Complete (for AND-OR graphs if heuristics consistent).
Optimality: ✅ Optimal with admissible heuristics.
Time Complexity: Exponential in worst case.
Space Complexity: Exponential (stores graph + partial expansions).
Hence, the program to implement AO* algorithm has been executed successfully.
CSE Dept. ARTIFICIAL INTELLIGENCE LAB