# 1.
Using BFS search on simple grid
BFS Algorithm for Grid (Shortest Path)
Input:
Grid with cells (free or blocked)
Start position (sx, sy)
Goal position (gx, gy)
📌 Algorithm Steps
1. Initialize:
o Create an empty queue Q
o Create a visited set
o Create a parent map (to store path)
2. Insert Start Node:
o Enqueue (sx, sy) into Q
o Mark (sx, sy) as visited
3. Loop until queue is empty:
While Q is not empty:
1. Dequeue a node (x, y) from Q
2. Check Goal:
If (x, y) == (gx, gy)
→ Stop and go to Step 4
3. Explore Neighbors:
For each direction:
Up → (x-1, y)
Down → (x+1, y)
Left → (x, y-1)
Right → (x, y+1)
For each neighbor (nx, ny):
Check if:
Inside grid bounds
Not blocked
Not visited
If valid:
Enqueue (nx, ny) into Q
Mark as visited
Set parent[(nx, ny)] = (x, y)
4. Reconstruct Path:
o Start from goal (gx, gy)
o Follow parent nodes back to start
o Reverse the path
5. If Goal Not Found:
o Return “No Path Exists”
# 1. Using BFS search on simple grid
from collections import deque
def bfs_shortest_path(grid, start, goal):
rows, cols = len(grid), len(grid[0])
queue = deque([start])
visited = set([start])
# To store the path
parent = {}
# Directions: up, down, left, right
directions = [(-1,0), (1,0), (0,-1), (0,1)]
while queue:
r, c = [Link]()
if (r, c) == goal:
# Reconstruct path
path = []
while (r, c) != start:
[Link]((r, c))
r, c = parent[(r, c)]
[Link](start)
[Link]()
return path
for dr, dc in directions:
nr, nc = r + dr, c + dc
if (0 <= nr < rows and
0 <= nc < cols and
grid[nr][nc] != 'X' and
(nr, nc) not in visited):
[Link]((nr, nc))
[Link]((nr, nc))
parent[(nr, nc)] = (r, c)
return None # No path found
# Example grid
grid = [
['S', '.', '.', 'X'],
['.', 'X', '.', '.'],
['.', '.', '.', 'G']
]
start = (0, 0)
goal = (2, 3)
path = bfs_shortest_path(grid, start, goal)
if path:
print("Shortest Path:", path)
else:
print("No path found")
OUTPUT
Shortest Path: [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (2, 3)]
# 2. DFS On a small graph
DFS Algorithm
Before learning the python code for Depth-First and its output, let us go through the algorithm it
follows for the same. The recursive method of the Depth-First Search algorithm is implemented
using stack. A standard Depth-First Search implementation puts every vertex of the graph into one
in all 2 categories: 1) Visited 2) Not Visited. The only purpose of this algorithm is to visit all the
vertex of the graph avoiding cycles.
The DSF algorithm follows as:
1. We will start by putting any one of the graph's vertex on top of the stack.
2. After that take the top item of the stack and add it to the visited list of the vertex.
3. Next, create a list of that adjacent node of the vertex. Add the ones which aren't in the
visited list of vertexes to the top of the stack.
4. Lastly, keep repeating steps 2 and 3 until the stack is empty.
# 2. DFS On a small graph
# Define the graph as an adjacency list
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': [],
'F': []
}
visited = set() # To track visited nodes
traversal_order = [] # To store DFS traversal result
def dfs(node):
if node not in visited:
[Link](node) # Mark node as visited
traversal_order.append(node)
for neighbor in graph[node]: # Visit all neighbors
dfs(neighbor)
dfs('A')
print("\nFinal Traversal Order:")
print(" → ".join(traversal_order))
OUTPUT
Final Traversal Order:
A→B→D→E→C→F
# Define the graph as an adjacency list
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': [],
'F': []
}
visited = set() # To track visited nodes
def dfs(visited,graph,node):
if node not in visited:
print(node)
[Link](node) # Mark node as visited
for neighbor in graph[node]: # Visit all neighbors
print("neighbor is " +neighbor)
dfs(visited,graph,neighbor)
dfs(visited,graph,'A')
OUTPUT
A
neighbor is B
B
neighbor is D
D
neighbor is E
E
neighbor is C
C
neighbor is F
F
# 3. Function to perform DFS to solve the water jug problem
Defining the State Space
We represent each state as a pair (x, y) where:
x is the amount of water in the 3-liter jug.
y is the amount of water in the 5-liter jug.
The initial state is (0, 0) because both jugs start empty, and the goal is to reach any state where
either jug contains exactly 4 liters of water.
Operations in State Space
The following operations define the possible transitions from one state to another:
1. Fill the 3-liter jug: Move to (3, y).
2. Fill the 5-liter jug: Move to (x, 5).
3. Empty the 3-liter jug: Move to (0, y).
4. Empty the 5-liter jug: Move to (x, 0).
5. Pour water from the 3-liter jug into the 5-liter jug: Move to (max(0, x - (5 - y)), min(5, x +
y)).
6. Pour water from the 5-liter jug into the 3-liter jug: Move to (min(3, x + y), max(0, y - (3 -
x))).
# 3. Function to perform DFS to solve the water jug problem
def water_jug_dfs(capacity1, capacity2, target):
visited = set() # To track visited states
path = [] # To store the solution path
def dfs(jug1, jug2):
# If we have already visited this state, return False (avoid cycles)
if (jug1, jug2) in visited:
returnFalse
# Mark the state as visited
[Link]((jug1, jug2))
# Append the current state to the path
[Link]((jug1, jug2))
# If the target is achieved in either jug, return True
if jug1 == target or jug2 == target:
returnTrue
# Explore all possible transitions (DFS recursive calls)
# Fill 4-liter jug
if dfs(4, jug2):
returnTrue
# Fill 3-liter jug
if dfs(jug1, 3):
returnTrue
# Empty 4-liter jug
if dfs(0, jug2):
returnTrue
# Empty 3-liter jug
if dfs(jug1, 0):
returnTrue
# Pour water from 3-liter jug into 5-liter jug
# Pour water from 4-liter jug into 3-liter jug
if dfs(max(0, jug1 - (3 - jug2)), min(3, jug1 + jug2)):
returnTrue
# Pour water from 5-liter jug into 3-liter jug
# Pour water from 3-liter jug into 4-liter jug
if dfs(min(4, jug1 + jug2), max(0, jug2 - (4 - jug1))):
returnTrue
# If none of the transitions lead to the goal, backtrack
[Link]()
returnFalse
# Start DFS from the initial state (0, 0)
dfs(0, 0)
# If we found a solution, return the path
return path
# Example Usage
capacity1 = 4 # Capacity of the 3-liter jug
capacity2 = 3 # Capacity of the 5-liter jug
target = 2 # Target amount to measure
solution = water_jug_dfs(capacity1, capacity2, target)
if solution:
print("Solution steps:")
for step in solution:
print(step)
else:
print("No solution found.")
Solution steps:
(0, 0)
(4, 0)
(4, 3)
(0, 3)
(3, 0)
(3, 3)
(4, 2)
4. Algorithm: Hill Climbing to Find Peak in 1D Dataset
Step 1: Start
Input: dataset = [a1, a2, ..., an]
Optional: starting index start_index
Initialize: max_iterations
Step 2: Initialize Current Position
If start_index is not provided:
o Choose a random index current_index in [0, n-1]
Set current_value = dataset[current_index]
Step 3: Repeat Until Termination
1. Identify neighbors of current index:
o left_index = current_index - 1 (if current_index > 0)
o right_index = current_index + 1 (if current_index < n-1)
2. Evaluate neighbor values:
o left_value = dataset[left_index] (or -∞ if out of bounds)
o right_value = dataset[right_index] (or -∞ if out of bounds)
3. Compare neighbors with current_value:
o If left_value > current_value:
Move to left: current_index = left_index, current_value = left_value
o Else if right_value > current_value:
Move to right: current_index = right_index, current_value = right_value
o Else:
No neighbor is better → local peak found, break
4. Increment iteration
o Stop if iteration >= max_iterations
Step 4: Output
Return current_index → index of peak
Return current_value → value of peak
# 4. Program For Hill Climbing
import random
# Hill Climbing function for 1D dataset
def hill_climb_dataset(data, start_index=None, max_iterations=100):
n = len(data)
# If no starting index, choose random
if start_index is None:
current_index = [Link](0, n-1)
else:
current_index = start_index
current_value = data[current_index]
for iteration in range(max_iterations):
left_index = current_index - 1 if current_index > 0 else None
right_index = current_index + 1 if current_index < n-1 else None
left_value = data[left_index] if left_index is not None else float('-inf')
right_value = data[right_index] if right_index is not None else float('-inf')
# Find best neighbor
if left_value > current_value:
current_index = left_index
current_value = left_value
elif right_value > current_value:
current_index = right_index
current_value = right_value
else:
# No neighbor is better → local peak found
break
print(f"Iteration {iteration+1}: Index = {current_index}, Value = {current_value}")
return current_index, current_value
# Main program
if __name__ == "__main__":
# Example numeric dataset
dataset = [1, 3, 7, 8, 12, 9, 6, 4, 2]
print("Dataset:", dataset)
peak_index, peak_value = hill_climb_dataset(dataset)
print(f"\nLocal peak found at index {peak_index}, value = {peak_value}")
OUTPUT
Dataset: [1, 3, 7, 8, 12, 9, 6, 4, 2]
Iteration 1: Index = 5, Value = 9
Iteration 2: Index = 4, Value = 12
Local peak found at index 4, value = 12
# 5. A* ALGORITHM TO FIND THE SHORTEST PATH IN 4X4 GRID
Step 1: Start
Step 2: Initialize
Define a 4×4 grid with:
o Start node S
o Goal node G
o Obstacles (if any)
Create:
o Open List → nodes to be explored
o Closed List → already explored nodes
For each node, maintain:
o g(n) = cost from start to current node
o h(n) = heuristic (estimated cost to goal)
o f(n) = g(n) + h(n)
Step 3: Add Start Node
Add start node to Open List
Set:
o g(S) = 0
o h(S) = heuristic distance to goal
o f(S) = g(S) + h(S)
Step 4: Loop Until Goal Found
Repeat:
1. Select node n from Open List with lowest f(n)
2. Remove n from Open List
3. Add n to Closed List
Step 5: Goal Test
IF n == Goal
→ Reconstruct path and STOP
Step 6: Expand Neighbors
For each neighbor of n (up, down, left, right):
1. If neighbor is:
o Outside grid OR
o Obstacle OR
o Already in Closed List
→ Skip it
2. Compute:
o g(neighbor) = g(n) + cost (usually 1)
o h(neighbor) = heuristic (Manhattan distance)
h = |x1 - x2| + |y1 - y2|
o f=g+h
3. If neighbor is not in Open List:
o Add it to Open List
4. If neighbor is already in Open List with higher g:
o Update its g and parent
Step 7: Path Reconstruction
Trace back from Goal to Start using parent pointers
Output shortest path
Step 8: Stop
# 5. A* ALGORITHM TO FIND THE SHORTEST PATH IN 4X4 GRID
importheapq
class Node:
def __init__(self, position, g_cost, h_cost, parent=None):
[Link] = position
self.g_cost = g_cost
self.h_cost = h_cost
self.f_cost = g_cost + h_cost
[Link] = parent
def __lt__(self, other):
returnself.f_cost<other.f_cost
def heuristic(pos1, pos2):
return abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1])
defa_star(grid, start, goal):
rows, cols = len(grid), len(grid[0])
open_list = []
closed_set = set()
start_node = Node(start, 0, heuristic(start, goal))
[Link](open_list, start_node)
whileopen_list:
current_node = [Link](open_list)
ifcurrent_node.position == goal:
path = []
whilecurrent_node:
[Link](current_node.position)
current_node = current_node.parent
return path[::-1]
closed_set.add(current_node.position)
fordr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
neighbor_pos = (current_node.position[0] + dr,
current_node.position[1] + dc)
if (0 <= neighbor_pos[0] < rows and
0 <= neighbor_pos[1] <cols and
grid[neighbor_pos[0]][neighbor_pos[1]] == 0):
ifneighbor_pos in closed_set:
continue
g_cost = current_node.g_cost + 1
h_cost = heuristic(neighbor_pos, goal)
neighbor_node = Node(neighbor_pos, g_cost, h_cost, current_node)
found_in_open = False
fori, node in enumerate(open_list):
[Link] == neighbor_pos:
ifnode.g_cost>g_cost:
open_list[i] = neighbor_node
[Link](open_list)
found_in_open = True
break
if not found_in_open:
[Link](open_list, neighbor_node)
return None
# Example Usage
if __name__ == "__main__":
grid = [
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 1, 0]
]
start_position = (0, 0)
goal_position = (3, 3)
path = a_star(grid, start_position, goal_position)
if path:
print("Path found:\n")
print("Starting Position:", start_position)
print("Goal Position:", goal_position)
print("\nPath:")
forpos in path:
print(pos)
else:
print("No path found.")
OUTPUT
Path found:
Starting Position: (0, 0)
Goal Position: (3, 3)
Path:
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 3)
(2, 3)
(3, 3)
# 6. Implement the minimax search algorithm 2 player games. you may use
game tree with 3 plies
Algorithm: Minimax (3-Ply Game Tree)
Step 1: Start
Step 2: Input
Read:
o Depth of tree (max_depth = 3)
o Leaf node values (utility values)
Define players:
o MAX (maximizing player)
o MIN (minimizing player)
Step 3: Define Recursive Function
Function: MINIMAX(depth, nodeIndex, isMaxPlayer)
Step 4: Base Case
IF depth == max_depth
→ RETURN value of current leaf node
Step 5: Recursive Case
If current player is MAX:
1. Set best = -∞
2. For each child node:
o Call MINIMAX(depth + 1, child, FALSE)
o Update best = max(best, returned value)
3. RETURN best
If current player is MIN:
1. Set best = +∞
2. For each child node:
o Call MINIMAX(depth + 1, child, TRUE)
o Update best = min(best, returned value)
3. RETURN best
Step 6: Initial Call
Call MINIMAX(0, 0, TRUE)
(Start from root as MAX player)
Step 7: Output
Display the optimal value returned
Step 8: Stop
# 6. Implement the minimax search algorithm 2 player games. you may use
game tree with 3 plies
import math
# Minimax function
def minimax(depth, node_index, is_max, values, max_depth):
# Base case: leaf node
if depth == max_depth:
return values[node_index]
if is_max:
best = -[Link]
# MAX player chooses maximum value
for i in range(2):
val = minimax(depth + 1, node_index * 2 + i, False, values, max_depth)
best = max(best, val)
return best
else:
best = [Link]
# MIN player chooses minimum value
for i in range(2):
val = minimax(depth + 1, node_index * 2 + i, True, values, max_depth)
best = min(best, val)
return best
# Driver code
if __name__ == "__main__":
# Leaf node values (8 leaves for 3 plies)
values = [3, 5, 6, 9, 1, 2, 0, -1]
tree_depth = 3
result = minimax(0, 0, True, values, tree_depth)
print("Optimal value (MAX player):", result)
OUTPUT
Optimal value (MAX player): 5
# 7. Algorithm: 4-Queen using Backtracking
Step 1: Start
Step 2: Initialize
Create an array board[4]
o Index = column
o Value = row position of queen
Step 3: Define Safety Function
Function: isSafe(board, row, col)
Check for all previous columns:
1. If same row → conflict
2. If diagonal conflict:
abs(board[i] - row) == abs(i - col)
If no conflict → safe
Step 4: Backtracking Function
Function: solve(col)
1. If col == 4
→ All queens placed successfully → RETURN TRUE
2. For each row from 0 to 3:
o If isSafe(board, row, col):
Place queen → board[col] = row
Recursively call solve(col + 1)
If success → RETURN TRUE
Else → Backtrack (remove queen)
3. If no row works → RETURN FALSE
Step 5: Initial Call
Call solve(0)
Step 6: Output
Print board configuration
Step 7: Stop
# 7. Solve 4 queen problems as a CSP backtracking problem
N=4
defis_safe(board, row, col):
# Check same row (left side only)
fori in range(col):
if board[row][i] == 1:
return False
# Check upper diagonal
i, j = row, col
whilei>= 0 and j >= 0:
if board[i][j] == 1:
return False
i -= 1
j -= 1
# Check lower diagonal
i, j = row, col
whilei< N and j >= 0:
if board[i][j] == 1:
return False
i += 1
j -= 1
return True
defsolve_n_queens(board, col):
# Base case: all queens placed
if col >= N:
return True
# Try placing queen in all rows
for row in range(N):
ifis_safe(board, row, col):
board[row][col] = 1 # Place queen
ifsolve_n_queens(board, col + 1):
return True
board[row][col] = 0 # Backtrack
return False
defprint_board(board):
for row in board:
for cell in row:
print("Q" if cell == 1 else ".", end=" ")
print()
# Main program
board = [[0]*N for _ in range(N)]
ifsolve_n_queens(board, 0):
print("Solution found:\n")
print_board(board)
else:
print("No solution exists")
OUTPUT
Solution found:
..Q.
Q...
...Q
.Q..
# 8. use constraint propagation to solve a magic square
puzzle
Algorithm:
Step 1: Start
Step 2: Initialize
Assign domain {1–9} to each cell
Maintain:
o Domains of variables
o Constraint list
Step 3: Apply Initial Constraint Propagation
Enforce:
o AllDifferent constraint → remove assigned values from others
o Use known facts:
Center must be 5 (for 3×3 magic square)
Step 4: Select Variable
Choose an unassigned variable using:
o MRV (Minimum Remaining Values) heuristic
Step 5: Assign Value
Assign a value from its domain
Step 6: Propagate Constraints
After assignment:
1. Remove assigned value from other domains
2. Check row/column/diagonal:
o If partial sum exceeds 15 → reject
o If only one cell left → assign required value
3. Apply forward checking:
o If any variable has empty domain → backtrack
Step 7: Check Completion
If all variables assigned and constraints satisfied
→ Solution found
Step 8: Backtrack if Needed
If inconsistency occurs:
o Undo assignment
o Try next value
Step 9: Repeat
Continue until solution found
Step 10: Stop
#8. Use constraint propagation to solve a magic square puzzle
import itertools
defis_valid(square):
# Rows
fori in range(3):
if sum(square[i*3:(i+1)*3]) != 15:
return False
# Columns
fori in range(3):
if square[i] + square[i+3] + square[i+6] != 15:
return False
# Diagonals
if square[0] + square[4] + square[8] != 15:
return False
if square[2] + square[4] + square[6] != 15:
return False
return True
defsolve_magic_square():
numbers = [1,2,3,4,5,6,7,8,9]
# Constraint propagation: fix center = 5
for perm in [Link](numbers):
if perm[4] != 5:
continue # enforce constraint early
ifis_valid(perm):
return perm
return None
defprint_square(square):
for i in range(3):
print(square[i*3:(i+1)*3])
# Run
solution = solve_magic_square()
if solution:
print("Magic Square Found:\n")
print_square(solution)
else:
print("No solution found")
OUTPUT
Magic Square Found:
(2, 7, 6)
(9, 5, 1)
(4, 3, 8)
#9. Apply optimization technique to find maximum value in list
Algorithm:
Input:
A list of numbers L = [a1, a2, ..., an]
Output:
Maximum value in the list
🔷 Steps
1. Start
2. Read the list L
3. Assume the first element is maximum
max ← L[0]
4. Repeat for each element from index 1 to n-1:
o If L[i] > max then:
max ← L[i]
5. After checking all elements, max holds the largest value
6. Display max
7. Stop
#9. Apply optimization technique to find maximum value in list
deffind_max(lst):
# Assume first element is maximum (initial solution)
max_val = lst[0]
# Optimization: improve solution step by step
fori in range(1, len(lst)):
iflst[i] >max_val:
max_val = lst[i] # update best value
returnmax_val
# Example usage
numbers = [10, 25, 5, 42, 18, 30]
result = find_max(numbers)
print("Maximum value is:", result)
OUTPUT
Maximum value is: 42
10. Represent and evaluate propositional logic expression in ai using python
Algorithm: Propositional Logic Evaluation
Step 1: Start
Step 2: Input
Read the logical expression E
(Example: (P ∧ Q) ∨ ¬P)
Identify all propositional variables
(Example: P, Q)
Step 3: Generate Truth Values
For n variables, generate all possible combinations of truth values
Total combinations = 2^n
Step 4: For Each Combination
Repeat the following:
1. Assign truth values to variables
(e.g., P = True, Q = False)
2. Replace variables in expression with their values
3. Replace logical operators:
o ∧ → AND
o ∨ → OR
o ¬ → NOT
o → → (NOT P OR Q)
o ↔ → (P == Q)
4. Evaluate the expression
Step 5: Store Result
Record the result for each combination
Step 6: Display Truth Table
Print variables and corresponding result
Step 7: Stop
# 10. Represent and evaluate propositional logic expression in AI using python
import itertools
# Logical operations
def implies(p, q):
return (not p) or q
def biconditional(p, q):
return p == q
# Evaluate expression from string
def evaluate_expression(expr, values):
# Replace variables with truth values
for var, val in [Link]():
expr = [Link](var, str(val))
# Replace logical symbols with Python equivalents
expr = [Link]('∧', ' and ')
expr = [Link]('∨', ' or ')
expr = [Link]('¬', ' not ')
# Replace implication and biconditional symbols
expr = [Link]('→', ' implies ')
expr = [Link]('↔', ' biconditional ')
return eval(expr)
# Generate truth table
def generate_truth_table(expr, variables):
print("\nTruth Table for:", expr)
print("-" * 40)
# Header
for var in variables:
print(var, end=" ")
print("| Result")
print("-" * 40)
# Generate combinations
for values in [Link]([True, False], repeat=len(variables)):
val_dict = dict(zip(variables, values))
result = evaluate_expression(expr, val_dict)
# Print row
for v in values:
print(int(v), end=" ")
print("|", int(result))
# Main program
if __name__ == "__main__":
# Input expression
expr = "(P ∧ Q) ∨ ¬P"
variables = ['P', 'Q']
generate_truth_table(expr, variables)
Truth Table for: (P ∧ Q) ∨ ¬P
OUTPUT
----------------------------------------
P Q | Result
----------------------------------------
11|1
10|0
01|1
00|1
11. Implement a basic rule based expert system for weather classification
Algorithm: Weather Classification Expert System
Step 1: Start
Step 2: Input Data
Read:
o Temperature (temp)
o Humidity (humidity)
o Wind speed (wind)
Step 3: Define Rules (Knowledge Base)
Apply IF–THEN rules:
1. IF temp > 30 AND humidity > 70
→ Weather = Rainy
2. ELSE IF temp > 30 AND humidity ≤ 70
→ Weather = Sunny
3. ELSE IF temp < 20 AND wind > 15
→ Weather = Stormy
4. ELSE IF 20 ≤ temp ≤ 30
→ Weather = Cloudy
5. ELSE
→ Weather = Moderate
Step 4: Apply Inference
Check conditions one by one
Match input values with rules
Select the first rule that satisfies the condition
Step 5: Output Result
Display the predicted weather condition
Step 6: Stop
# 11. Implement a basic rule based expert system for weather classification
def classify_weather(temp, humidity, wind):
# Rule-based conditions
# Rule 1: Rainy
if temp > 30 and humidity > 70:
return "Rainy"
# Rule 2: Sunny
elif temp > 30 and humidity <= 70:
return "Sunny"
# Rule 3: Stormy
elif temp < 20 and wind > 15:
return "Stormy"
# Rule 4: Cloudy
elif 20 <= temp <= 30:
return "Cloudy"
# Default rule
else:
return "Moderate Weather"
# Main program
if __name__ == "__main__":
print("Weather Classification Expert System\n")
temp = float(input("Enter temperature (°C): "))
humidity = float(input("Enter humidity (%): "))
wind = float(input("Enter wind speed (km/h): "))
result = classify_weather(temp, humidity, wind)
print("\nPredicted Weather Condition:", result)
OUTPUT
Weather Classification Expert System
Enter temperature (°C): 43
Enter humidity (%): 5
Enter wind speed (km/h): 3
Predicted Weather Condition: Sunny