AI Lab Manual
AI Lab Manual
Semester IV
Course Code BAD402 CIE Marks 50
Teaching Hours/Week (L:T:P: S) 3:0:2:0 SEE Marks 50
Total Hours of Pedagogy 40 hours Theory + 8-10 Lab slots Total Marks 100
Credits 04 Exam Hours
Experiments
Problem Statement:
Given two jugs of different capacities (say m liters and n liters) and an unlimited supply of water,
the goal is to measure exactly d liters of water using the two jugs.
5. Pour Jug1 into Jug2 until Jug2 is full or Jug1 is empty.
6. Pour Jug2 into Jug1 until Jug1 is full or Jug2 is empty.
3. Use DFS to Explore States:
● Start from (0, 0) (both jugs empty).
Problem Statement
Three missionaries and three cannibals are on one side of the river, and they must cross to the
other side using a boat that can carry at most two people. The challenge is that at no point should
the number of cannibals be greater than the number of missionaries on either side, as the
cannibals would eat the missionaries.
scss
CopyEdit
(M_left, C_left, Boat_side, M_right, C_right)
The boat can carry at most two people, so possible moves include:
● Expand states based on a heuristic (e.g., the number of people moved closer to the goal).
def is_valid(state):
if (M_left < C_left and M_left > 0) or (M_right < C_right and M_right > 0):
return False
return False
return True
def generate_states(state):
moves = [(1, 0), (2, 0), (0, 1), (0, 2), (1, 1)] # Possible moves
next_states = []
for m, c in moves:
if boat == 1: # Boat on the left side
if is_valid(new_state):
next_states.append(new_state)
return next_states
def best_first_search():
initial_state = (3, 3, 1, 0, 0)
goal_state = (0, 0, 0, 3, 3)
pq = PriorityQueue()
visited = set()
_, path = pq.get()
current_state = path[-1]
if current_state in visited:
continue
visited.add(current_state)
if current_state == goal_state:
solution = best_first_search()
if solution:
print("Solution Path:")
print(step)
else:
1. is_valid(state):
2. generate_states(state):
3. best_first_search():
● Uses a priority queue (min-heap) to explore the most promising states first.
● The heuristic function is remaining people on the left side, ensuring minimal steps.
Solution Path:
(3, 3, 1, 0, 0)
(2, 2, 0, 1, 1)
(3, 2, 1, 0, 1)
(1, 1, 0, 2, 2)
(2, 1, 1, 1, 2)
(0, 0, 0, 3, 3)
This shows the step-by-step transitions until all missionaries and cannibals safely cross the river.
Conclusion
This implementation: ✔ Uses Best First Search (BFS) with a heuristic to prioritize better moves.
✔ Ensures only valid states are explored.
✔ Finds the optimal path to solve the problem efficiently.
3.Implement A* Search algorithm
Problem Overview
The Missionaries and Cannibals problem involves three missionaries and three cannibals
attempting to cross a river using a boat that can carry a maximum of two people. The challenge
is to ensure that missionaries are never outnumbered by cannibals on either side.
scss
CopyEdit
(M_left, C_left, Boat_side, M_right, C_right)
The boat can carry at most two people, so possible moves include:
3. Define Constraints
A state is valid only if:
A* uses:
● h(n): Heuristic estimating cost from the current state to the goal.
A suitable heuristic function is the number of people remaining on the left because it estimates
how far we are from the goal.
return True
for m, c in moves:
if boat == 1: # Boat on the left side
new_state = (M_left - m, C_left - c, 0, M_right + m, C_right + c)
else: # Boat on the right side
new_state = (M_left + m, C_left + c, 1, M_right - m, C_right - c)
if is_valid(new_state):
next_states.append(new_state)
return next_states
# A* Search Algorithm
def a_star_search():
initial_state = (3, 3, 1, 0, 0)
goal_state = (0, 0, 0, 3, 3)
pq = PriorityQueue()
pq.put((0, 0, [initial_state])) # (f(n), g(n), path)
visited = set()
if current_state in visited:
continue
visited.add(current_state)
if current_state == goal_state:
return path # Return solution path
1. is_valid(state):
2. generate_states(state):
3. heuristic(state):
4. a_star_search():
● Uses a priority queue to store states based on their f(n) = g(n) + h(n) values.
Example Output
Solution Path:
(3, 3, 1, 0, 0)
(2, 2, 0, 1, 1)
(3, 2, 1, 0, 1)
(1, 1, 0, 2, 2)
(2, 1, 1, 1, 2)
(0, 0, 0, 3, 3)
This output represents the sequence of moves required to transport all missionaries and cannibals
safely across the river.
Why A Search?*
Conclusion
✅
This implementation: ✅ Uses A Search* to find the optimal solution.
AO* (And-Or) Search is an optimal search algorithm used in AND-OR graphs, where some
states require multiple sub-goals to be solved together. Unlike A*, which finds a single optimal
path, AO finds optimal solutions in problems with sub-goals (AND nodes) and decision points
(OR nodes).*
scss
CopyEdit
(M_left, C_left, Boat_side, M_right, C_right)
● AND Nodes: Represent required sub-goals to solve the problem (e.g., "move 1
missionary and then 1 cannibal").
The boat can carry at most two people, so possible moves include:
4. Define Constraints
2. Expand the most promising node (with the lowest cost).
3. If a state requires multiple sub-goals (AND nodes), expand them together.
return True
# Function to generate possible moves
def generate_states(state):
M_left, C_left, boat, M_right, C_right = state
moves = [(1, 0), (2, 0), (0, 1), (0, 2), (1, 1)] # Possible moves
next_states = []
for m, c in moves:
if boat == 1: # Boat on the left side
new_state = (M_left - m, C_left - c, 0, M_right + m, C_right + c)
else: # Boat on the right side
new_state = (M_left + m, C_left + c, 1, M_right - m, C_right - c)
if is_valid(new_state):
next_states.append(new_state)
return next_states
pq = PriorityQueue()
pq.put((0, 0, [initial_state])) # (f(n), g(n), path)
visited = set()
if current_state in visited:
continue
visited.add(current_state)
if current_state == goal_state:
return path # Return solution path
1. is_valid(state):
2. generate_states(state):
3. heuristic(state):
4. ao_star_search():
● Uses a priority queue to store states based on their f(n) = g(n) + h(n) values.
Example Output
Solution Path:
(3, 3, 1, 0, 0)
(2, 2, 0, 1, 1)
(3, 2, 1, 0, 1)
(1, 1, 0, 2, 2)
(2, 1, 1, 1, 2)
(0, 0, 0, 3, 3)
This output represents the sequence of moves required to transport all missionaries and cannibals
safely across the river.
Why AO Search?*
✔ Optimal Solution: Finds the best path while handling multiple sub-goals.
✔ Handles AND-OR Structures: Works well when multiple solutions need to be combined.
✔ Efficient Exploration: Uses a heuristic to prioritize better moves.
Conclusion
✅
This implementation: ✅ Uses AO Search* to find the optimal solution.
● Each queen is placed in a different row (since there are 8 rows and 8 queens).
● The problem reduces to selecting one column per row so that no queens attack each other.
2. Choose an Algorithm
Backtracking works by placing a queen in a row, then recursively placing queens in the next row,
backtracking if a conflict occurs.
solutions = []
for col in range(N):
if is_safe(board, row, col):
board[row] = col # Place queen
solutions.extend(solve_n_queens(board, row + 1)) # Recur for next row
return solutions
3. print_solution(solution)
This method solves the problem optimally by only exploring valid placements, avoiding brute
force.
Conclusion
Since exact solutions using brute force or dynamic programming become computationally
infeasible for large N, we use heuristic approaches to find near-optimal solutions efficiently.
○ N nodes (cities)
○ A distance matrix where dist[i][j] gives the distance between cities i and j.
import numpy as np
current = start
for _ in range(N - 1):
# Find the nearest unvisited city
nearest_city = None
min_distance = float('inf')
○ A symmetric matrix where dist[i][j] represents the distance between city i and city
j.
Example Output
Optimal Path (Nearest Neighbor Heuristic): [0, 1, 3, 4, 2, 0]
Total Cost: 85
This means:
● The salesman starts from City 0, visits cities in the order [0 → 1 → 3 → 4 → 2 → 0].
✖ Can produce sub-optimal routes (doesn’t always find the global minimum).
✖ Greedy approach may lead to poor solutions for specific cases.
Forward Chaining is a data-driven inference technique. It starts from known facts and applies
rules to derive new conclusions until the goal is reached.
○ For each rule, check if its conditions are satisfied by existing facts.
○ If all conditions of a rule are met, infer the conclusion and add it to the facts.
while changes:
changes = False
for rule in rules:
if set(rule["conditions"]).issubset(facts) and rule["conclusion"] not in facts:
facts.add(rule["conclusion"])
inferred.add(rule["conclusion"])
changes = True # A new fact was added
return inferred
Output
Since the patient had fever, cough, and rash, Forward Chaining inferred: ✔ Flu (from fever &
cough).
✔ Measles (from flu & rash).
✔ High fever (from measles).
Backward Chaining is a goal-driven inference technique. It starts from a goal and works
backwards to verify if the given facts support the goal.
○ Check if all conditions of the selected rule can be proved using known facts or
other rules.
○ If conditions are satisfied, conclude the goal as true.
Output
The goal 'measles' is PROVED using Backward Chaining.
✔ Since the patient had flu and rash, Backward Chaining proved measles.
Use Case Deriving all possible outcomes Checking if a goal can be proved
● ✅ Both strategies are widely used in AI, rule-based systems, and expert systems.
8.Implement resolution principle on FOPL related problems
The Resolution Principle is a rule of inference used in automated theorem proving for
First-Order Predicate Logic (FOPL). It is used to refute a contradiction by deriving an empty
clause (⊥), proving that a given conclusion follows logically from a set of premises.
● Represent the given knowledge base and the negation of the conclusion using predicate
logic.
● Eliminate implications (→): Convert statements into conjunctive normal form (CNF).
4. Apply Unification
● Repeat until:
○ Clause 2: Man(Socrates)Man(Socrates)Man(Socrates)
✅
✔ Since we reached an empty clause, the proof is complete.
✔ Socrates is proven to be mortal!
# Define predicates
Man = symbols('Man')
Mortal = symbols('Mortal')
Socrates = symbols('Socrates')
# Apply Resolution
if resolve(clause1.subs(Man, Socrates), clause2):
resolved_clause = Mortal.subs(Mortal, Socrates)
print(f"Resolved Clause: {resolved_clause}") # Mortal(Socrates)
if resolve(resolved_clause, clause3):
print("Empty Clause Derived (⊥) → Proof Complete ✅")
else:
❌
print("Proof Failed ")
# Apply Resolution
if resolve(clause1.subs(Man, Socrates), clause2):
resolved_clause = Mortal.subs(Mortal, Socrates)
print(f"Resolved Clause: {resolved_clause}") # Mortal(Socrates)
if resolve(resolved_clause, clause3):
print("Empty Clause Derived (⊥) → Proof Complete ✅")
else:
❌
print("Proof Failed ")
9. Implement Tic-Tac-Toe game using Python
6. Switch Turns
# Tic-Tac-Toe Game
# Check diagonals
if all(board[i][i] == player for i in range(3)) or all(board[i][2 - i] == player for i in range(3)):
return True
return False
while True:
print_board()
print(f"Player {current_player}, enter your move (row and column: 0, 1, or 2): ")
ow It Works
1. Players take turns entering a row and column number (0-2).
2. The board updates with "X" or "O" based on the current player.
5. The game ends when a player wins or all cells are filled.
Enhancements
Overview
✅
We will build a Search Bot that:
✅
✅
Fetches relevant information from a predefined dataset or the web.
Returns the best possible answer based on the input.
Can be enhanced with AI, NLP, and Web Scraping.
● Web Scraping: Fetch live results from the internet using APIs (e.g., Wikipedia API,
Google Search API).
● AI Model: Use Natural Language Processing (NLP) for better query understanding.
app = Flask(__name__)
if __name__ == "__main__":
app.run(debug=True)
How It Works
2. Minimax Algorithm (Optimal AI): Looks ahead for the best move
import random
if is_maximizing:
best_score = -float("inf")
for i in range(3):
for j in range(3):
if board[i][j] == " ":
board[i][j] = "O"
score = minimax(False)
board[i][j] = " "
best_score = max(score, best_score)
return best_score
else:
best_score = float("inf")
for i in range(3):
for j in range(3):
if board[i][j] == " ":
board[i][j] = "X"
score = minimax(True)
board[i][j] = " "
best_score = min(score, best_score)
return best_score
# AI Move (Optimal using Minimax)
def ai_move():
best_score = -float("inf")
best_move = None
for i in range(3):
for j in range(3):
if board[i][j] == " ":
board[i][j] = "O"
score = minimax(False)
board[i][j] = " "
if score > best_score:
best_score = score
best_move = (i, j)
board[best_move[0]][best_move[1]] = "O"
# Main Game Loop
def play_game():
print("Tic-Tac-Toe: Player (X) vs AI (O)")
current_player = "X"
while True:
print_board()
if current_player == "X":
row, col = map(int, input("Enter row and column (0-2): ").split())
if board[row][col] != " ":
print("Cell taken! Try again.")
continue
board[row][col] = "X"
else:
ai_move() # AI plays optimally
if check_win(current_player):
print_board()
🎉
print(f"Player {current_player} wins! ")
break
if check_draw():
print_board()
🤝
print("It's a draw! ")
break
current_player = "O" if current_player == "X" else "X"
# Start Game
play_game()
🔹 Key Takeaways
✔ Game Rules: Players take turns, aiming to win by aligning marks.
✔ Winning Strategies:
🚀 Next Steps
1. Add a GUI version using Tkinter or Pygame.