0% found this document useful (0 votes)
15 views130 pages

123 - Merged (1) - Merged

The document contains various algorithms and implementations in Python, including Breadth-First Search (BFS), Depth-First Search (DFS), the 8-Queens problem, Uniform Cost Search (UCS), Iterative Deepening Search (IDS), and the Missionaries and Cannibals problem. Each section provides code examples and explanations for the respective algorithms and problems. The document serves as a comprehensive guide for understanding and implementing these search algorithms and puzzles in Python.

Uploaded by

shriyuktasinha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views130 pages

123 - Merged (1) - Merged

The document contains various algorithms and implementations in Python, including Breadth-First Search (BFS), Depth-First Search (DFS), the 8-Queens problem, Uniform Cost Search (UCS), Iterative Deepening Search (IDS), and the Missionaries and Cannibals problem. Each section provides code examples and explanations for the respective algorithms and problems. The document serves as a comprehensive guide for understanding and implementing these search algorithms and puzzles in Python.

Uploaded by

shriyuktasinha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 130

BFS

graph = {

'A': ['B', 'C'],

'B': ['D', 'E'],

'C': ['F'],

'D': [],

'E': ['F'],

'F': []

visited = []

queue = []

def bfs(visited, graph, node):

visited.append(node)

queue.append(node)

while queue:

m = queue.pop(0)

print(m, end=" ")

for neighbour in graph[m]:

if neighbour not in visited:

visited.append(neighbour)

queue.append(neighbour)

print("Following is the Breadth-First Search")

bfs(visited, graph, '10')


# Function to take graph input from the user

def get_graph_input():

graph = {}

nodes = input("Enter nodes separated by spaces: ").split()

for node in nodes:

neighbors = input(f"Enter neighbors of node {node} separated by spaces (or leave blank if
none): ").split()

graph[node] = neighbors

return graph

# Main code

visited = []

queue = []

def bfs(visited, graph, node):

visited.append(node)

queue.append(node)

while queue:

m = queue.pop(0)

print(m, end=" ")

for neighbour in graph[m]:

if neighbour not in visited:

visited.append(neighbour)

queue.append(neighbour)

# Get graph input from the user

graph = get_graph_input()

print("Following is the Breadth-First Search")


bfs(visited, graph, 'A') # Change 'A' to any valid starting node from the user-provided graph

# Function to take graph input from the user

def get_graph_input():

graph = {}

nodes = list(map(int, input("Enter nodes separated by spaces: ").split()))

for node in nodes:

neighbors = list(map(int, input(f"Enter neighbors of node {node} separated by spaces (or leave
blank if none): ").split()))

graph[node] = neighbors

return graph

# Main code

visited = []

queue = []

def bfs(visited, graph, node):

visited.append(node)

queue.append(node)

while queue:

m = queue.pop(0)

print(m, end=" ")

for neighbour in graph[m]:

if neighbour not in visited:

visited.append(neighbour)

queue.append(neighbour)

# Get graph input from the user


graph = get_graph_input()

print("Following is the Breadth-First Search")

bfs(visited, graph, 1) # Change 1 to any valid starting node from the user-provided graph

DFS

graph = {
'5': ['3', '7'],
'3': ['2', '4'],
'7': ['8'],
'2': [],
'4': ['8'],
'8': []
}

visited = set()

def dfs(visited, graph, node):


if node not in visited:
print(node)
visited.add(node)
for neighbour in graph[node]:
dfs(visited, graph, neighbour)

print("Following is the Depth-First Search")


dfs(visited, graph, '5')
3) The 8-Queens problem is a classic problem in computer science.
The goal is to place eight queens on a chessboard in such a way that
no two queens threaten each other. This means that no two queens
can be in the same row, column, or diagonal. Make an
implementation of the 8-Queens problem in Python using a
backtracking algorithm:

def is_safe(board, row, col, N):

for i in range(col):
if board[row][i] == 1:
return False

for i, j in zip(range(row, -1, -1), range(col, -1, -1)):


if board[i][j] == 1:
return False

for i, j in zip(range(row, N, 1), range(col, -1, -1)):


if board[i][j] == 1:
return False

return True

def solve_nqueens_util(board, col, N):


if col >= N:
return True
for i in range(N):
if is_safe(board, i, col, N):
board[i][col] = 1
if solve_nqueens_util(board, col + 1, N):
return True

board[i][col] = 0
return False
def solve_nqueens(N):

board = [[0] * N for _ in range(N)]

if not solve_nqueens_util(board, 0, N):


print("Solution does not exist")
return
for row in board:
print(" ".join("Q" if cell == 1 else "." for cell in row))

solve_nqueens(11)

4) Uniform Cost Search (UCS) is a search algorithm that explores a


weighted graph by expanding the least-cost node. It is often used
for finding the shortest path in a graph with non-negative edge
weights. Make an implementation of the Uniform Cost Search
algorithm in Python.

import heapq

def uniform_cost_search(graph, start, goal):


priority_queue = [(0, start)]
visited = {start: (0, None)}

while priority_queue:
current_cost, current_node = heapq.heappop(priority_queue)

if current_node == goal:
# Reached the goal, print the path and cost
path, cost = reconstruct_path(visited, start, goal)
print(f"Shortest path from {start} to {goal}: {path}")
print(f"Shortest distance: {cost}")
return

for neighbor, weight in graph[current_node].items():


total_cost = current_cost + weight

if neighbor not in visited or total_cost < visited[neighbor][0]:


visited[neighbor] = (total_cost, current_node)
heapq.heappush(priority_queue, (total_cost, neighbor))

print(f"No path found from {start} to {goal}")

def reconstruct_path(visited, start, goal):


path = [goal]
cost = visited[goal][0]

while path[-1] != start:


path.append(visited[path[-1]][1])

return ' -> '.join(reversed(path)), cost


graph = {
'A': {'B': 5, 'C': 2, 'D': 7},
'B': {'A': 5, 'C': 4, 'E': 3},
'C': {'A': 2, 'B': 4, 'D': 1, 'F': 7},
'D': {'A': 7, 'C': 1, 'F': 2},
'E': {'B': 3, 'F': 4},
'F': {'C': 7, 'D': 2, 'E': 4}
}

start_city = 'A'
goal_city = 'F'

uniform_cost_search(graph, start_city, goal_city)

import heapq

def get_graph_input():
graph = {}
num_edges = int(input("Enter the number of edges: "))
print("Enter edges in the format 'node1 node2 weight' separated by spaces:")
for _ in range(num_edges):
node1, node2, weight = input().split()
weight = int(weight)
node1 = node1.strip() # Remove leading/trailing spaces
node2 = node2.strip()
if node1 not in graph:
graph[node1] = {}
if node2 not in graph:
graph[node2] = {}
graph[node1][node2] = weight
graph[node2][node1] = weight # Assuming an undirected graph
return graph

def uniform_cost_search(graph, start, goal):


priority_queue = [(0, start)]
visited = {start: (0, None)}

while priority_queue:
current_cost, current_node = heapq.heappop(priority_queue)

if current_node == goal:
# Reached the goal, print the path and cost
path, cost = reconstruct_path(visited, start, goal)
print(f"Shortest path from {start} to {goal}: {path}")
print(f"Shortest distance: {cost}")
return

for neighbor, weight in graph[current_node].items():


total_cost = current_cost + weight

if neighbor not in visited or total_cost < visited[neighbor][0]:


visited[neighbor] = (total_cost, current_node)
heapq.heappush(priority_queue, (total_cost, neighbor))

print(f"No path found from {start} to {goal}")


def reconstruct_path(visited, start, goal):
path = [goal]
cost = visited[goal][0]

while path[-1] != start:


path.append(visited[path[-1]][1])

return ' -> '.join(reversed(path)), cost

# Get graph input from the user


road_network = get_graph_input()

start_city = input("Enter the start city: ").strip() # Remove leading/trailing spaces


goal_city = input("Enter the goal city: ").strip()

uniform_cost_search(road_network, start_city, goal_city)

5) Iterative Deepening Search (IDS) is a combination of depth-first


search and breadth-first search. It repeatedly performs depth-first
search with increasing depth limits until the goal is found. This
allows the algorithm to explore deeper levels gradually, avoiding
the disadvantages of pure depth-first or breadth-first search. Make
an implementation of the Iterative Deepening Search in Python.

def iterative_deepening_search(graph, start, goal):


depth_limit = 0

while True:
result, path = depth_limited_search(graph, start, goal, depth_limit)

if result == goal:
return result, path
elif result == 'cutoff':
depth_limit += 1
else:
return None, []

def depth_limited_search(graph, current, goal, depth_limit):


return recursive_depth_limited_search(graph, current, goal, depth_limit, set(), [])

def recursive_depth_limited_search(graph, current, goal, depth_limit, visited, path):


if current == goal:
return current, path + [current]

if depth_limit == 0:
return 'cutoff', []

cutoff_occurred = False

for neighbor in graph.get(current, []): # Use .get() to handle nodes without neighbors
if neighbor not in visited:
visited.add(neighbor)
result, subpath = recursive_depth_limited_search(graph, neighbor, goal,
depth_limit - 1, visited, path + [current])

if result == 'cutoff':
cutoff_occurred = True
elif result is not None:
return result, subpath
if cutoff_occurred:
return 'cutoff', []
else:
return None, []

# Define the graph


graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}

start_node = 'A'
goal_node = 'F'

result, path = iterative_deepening_search(graph, start_node, goal_node)

if result:
print(f"Goal {goal_node} found using Iterative Deepening Search.")
print(f"Path: {' -> '.join(path)}")
else:
print(f"Goal {goal_node} not reachable.")
def get_graph_input():
graph = {}
num_edges = int(input("Enter the number of edges: "))
print("Enter edges in the format 'node1 node2' separated by spaces:")
for _ in range(num_edges):
node1, node2 = input().split()
if node1 not in graph:
graph[node1] = []
if node2 not in graph:
graph[node2] = []
graph[node1].append(node2)
graph[node2].append(node1) # Assuming an undirected graph

# Add nodes without outgoing edges to the graph


all_nodes = set(graph.keys())
for node in all_nodes:
if not graph[node]:
graph[node] = []

return graph

def iterative_deepening_search(graph, start, goal):


depth_limit = 0

while True:
result, path = depth_limited_search(graph, start, goal, depth_limit)

if result == goal:
return result, path
elif result == 'cutoff':
depth_limit += 1
else:
return None, []

def depth_limited_search(graph, current, goal, depth_limit):


return recursive_depth_limited_search(graph, current, goal, depth_limit, set(), [])

def recursive_depth_limited_search(graph, current, goal, depth_limit, visited, path):


if current == goal:
return current, path + [current]

if depth_limit == 0:
return 'cutoff', []

cutoff_occurred = False

for neighbor in graph.get(current, []): # Use .get() to handle nodes without neighbors
if neighbor not in visited:
visited.add(neighbor)
result, subpath = recursive_depth_limited_search(graph, neighbor, goal,
depth_limit - 1, visited, path + [current])

if result == 'cutoff':
cutoff_occurred = True
elif result is not None:
return result, subpath
if cutoff_occurred:
return 'cutoff', []
else:
return None, []

# Get graph input from the user


graph = get_graph_input()

start_node = input("Enter the start node: ")


goal_node = input("Enter the goal node: ")

result, path = iterative_deepening_search(graph, start_node, goal_node)

if result:
print(f"Goal {goal_node} found using Iterative Deepening Search.")
print(f"Path: {' -> '.join(path)}")
else:
print(f"Goal {goal_node} not reachable.")

6) The Missionaries and Cannibals problem is a classic river-crossing


puzzle that involves moving missionaries and cannibals from one
side of a river to the other. The challenge is to find a sequence of
moves that allows all missionaries and cannibals to cross without
violating certain rules. The rules usually include constraints on the
number of missionaries and cannibals on each side of the river, and
ensuring that the cannibals don't outnumber the missionaries on
either side. Create an implementation of the Missionaries and
Cannibals problem using a simple BFS algorithm in Python.

from queue import Queue


def is_valid_state(state):
m1, c1, b, m2, c2 = state
if m1 < 0 or c1 < 0 or m2 < 0 or c2 < 0:
return False
if (m1 < c1 and m1 > 0) or (m2 < c2 and m2 > 0):
return False
return True

def generate_successors(state):
m1, c1, b, m2, c2 = state
successors = []

if b == 0:
successors.extend([(m1 - 1, c1, 1, m2 + 1, c2),
(m1 - 2, c1, 1, m2 + 2, c2),
(m1, c1 - 1, 1, m2, c2 + 1),
(m1 - 1, c1 - 1, 1, m2 + 1, c2 + 1),
(m1, c1 - 2, 1, m2, c2 + 2)])
else:
successors.extend([(m1 + 1, c1, 0, m2 - 1, c2),
(m1 + 2, c1, 0, m2 - 2, c2),
(m1, c1 + 1, 0, m2, c2 - 1),
(m1 + 1, c1 + 1, 0, m2 - 1, c2 - 1),
(m1, c1 + 2, 0, m2, c2 - 2)])

return [s for s in successors if is_valid_state(s)]

def missionaries_and_cannibals_bfs(start_state, goal_state):


queue = Queue()
visited = set()
queue.put([start_state])

while not queue.empty():


path = queue.get()
current_state = path[-1]

if current_state == goal_state:
return path

if current_state not in visited:


successors = generate_successors(current_state)
for successor in successors:
if successor not in visited:
new_path = list(path)
new_path.append(successor)
queue.put(new_path)
visited.add(current_state)

return None

def print_solution(path):
for i, state in enumerate(path):
m1, c1, b, m2, c2 = state
print(f"Step {i + 1}: {('M' * m1) + ('C' * c1)} {'B' if b == 0 else ' ' * 3} {('M' *
m2) + ('C' * c2)}")

if __name__ == "__main__":
m1 = int(input("Enter the number of missionaries on the starting side: "))
c1 = int(input("Enter the number of cannibals on the starting side: "))
b=0
m2 = 0
c2 = 0
start_state = (m1, c1, b, m2, c2)

m1 = int(input("Enter the number of missionaries on the goal side: "))


c1 = int(input("Enter the number of cannibals on the goal side: "))
b=1
m2 = 3
c2 = 3
goal_state = (m1, c1, b, m2, c2)

solution_path = missionaries_and_cannibals_bfs(start_state, goal_state)

if solution_path:
print("Solution found:")
print_solution(solution_path)
else:
print("No solution found.")

TCS:
from itertools import permutations

def calculate_total_distance(path, distances):


total_distance = 0
for i in range(len(path) - 1):
total_distance += distances[path[i]][path[i + 1]]
total_distance += distances[path[-1]][path[0]] # Return to the starting city
return total_distance

def traveling_salesman_bruteforce(distances):
num_cities = len(distances)
cities = list(range(num_cities))
all_paths = permutations(cities)

min_distance = float('inf')
best_path = None

for path in all_paths:


current_distance = calculate_total_distance(path, distances)
if current_distance < min_distance:
min_distance = current_distance
best_path = path

return best_path, min_distance

# Example usage:
distances = [
[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]
]

best_path, min_distance = traveling_salesman_bruteforce(distances)


print("Best Path:", best_path)
print("Minimum Distance:", min_distance)

from itertools import permutations

def calculate_total_distance(path, distances):


total_distance = 0
for i in range(len(path) - 1):
total_distance += distances[path[i]][path[i + 1]]
total_distance += distances[path[-1]][path[0]] # Return to the starting city
return total_distance

def traveling_salesman_bruteforce(distances):
num_cities = len(distances)
cities = list(range(num_cities))
all_paths = permutations(cities)

min_distance = float('inf')
best_path = None

for path in all_paths:


current_distance = calculate_total_distance(path, distances)
if current_distance < min_distance:
min_distance = current_distance
best_path = path

return best_path, min_distance


# Take user input for the distance matrix
def get_distance_matrix():
num_cities = int(input("Enter the number of cities: "))
distances = []
print("Enter the distance between cities (row by row):")
for _ in range(num_cities):
row = list(map(int, input().split()))
distances.append(row)
return distances

# Example usage with user input


distances = get_distance_matrix()
best_path, min_distance = traveling_salesman_bruteforce(distances)
print("Best Path:", best_path)
print("Minimum Distance:", min_distance)

Bi directional

class AdjacentNode:
def __init__(self, vertex):
self.vertex = vertex
self.next = None

class BidirectionalSearch:
def __init__(self, vertices):
self.vertices = vertices
self.graph = [None] * self.vertices
self.src_queue = list()
self.dest_queue = list()
self.src_visited = [False] * self.vertices
self.dest_visited = [False] * self.vertices
self.src_parent = [None] * self.vertices
self.dest_parent = [None] * self.vertices

def add_edge(self, src, dest):


node = AdjacentNode(dest)
node.next = self.graph[src]
self.graph[src] = node
node = AdjacentNode(src)
node.next = self.graph[dest]
self.graph[dest] = node

def bfs(self, direction='forward'):


if direction == 'forward':
current = self.src_queue.pop(0)
connected_node = self.graph[current]
while connected_node:
vertex = connected_node.vertex
if not self.src_visited[vertex]:
self.src_queue.append(vertex)
self.src_visited[vertex] = True
self.src_parent[vertex] = current
connected_node = connected_node.next
else:
current = self.dest_queue.pop(0)
connected_node = self.graph[current]
while connected_node:
vertex = connected_node.vertex
if not self.dest_visited[vertex]:
self.dest_queue.append(vertex)
self.dest_visited[vertex] = True
self.dest_parent[vertex] = current
connected_node = connected_node.next

def is_intersecting(self):
for i in range(self.vertices):
if self.src_visited[i] and self.dest_visited[i]:
return i
return -1

def print_path(self, intersecting_node, src, dest):


path = list()
path.append(intersecting_node)
i = intersecting_node
while i != src:
path.append(self.src_parent[i])
i = self.src_parent[i]
path = path[::-1]
i = intersecting_node
while i != dest:
path.append(self.dest_parent[i])
i = self.dest_parent[i]
print("Path:")
print(' '.join(map(str, path)))
def bidirectional_search(self, src, dest):
self.src_queue.append(src)
self.src_visited[src] = True
self.src_parent[src] = -1
self.dest_queue.append(dest)
self.dest_visited[dest] = True
self.dest_parent[dest] = -1

while self.src_queue and self.dest_queue:


self.bfs(direction='forward')
self.bfs(direction='backward')
intersecting_node = self.is_intersecting()
if intersecting_node != -1:
print(f"Path exists between {src} and {dest}")
print(f"Intersection at: {intersecting_node}")
self.print_path(intersecting_node, src, dest)
return
print(f"Path does not exist between {src} and {dest}")

vertices = int(input("Enter the number of vertices in the graph: "))

src = int(input("Enter the source vertex: "))


dest = int(input("Enter the destination vertex: "))

graph = BidirectionalSearch(vertices)
edges = int(input("Enter the number of edges: "))
print("Enter the edges (src dest) separated by space:")
for _ in range(edges):
edge = list(map(int, input().split()))
graph.add_edge(edge[0], edge[1])

graph.bidirectional_search(src, dest)

Enter the number of vertices in the graph: 6


Enter the source vertex: 0
Enter the destination vertex: 5
Enter the number of edges: 7
Enter the edges (src dest) separated by space:
01
02
13
24
35
45
25
Path exists between 0 and 5
Intersection at: 2
Path:
025
A*
import math
import heapq

class Cell:
def __init__(self):
self.parent_i = 0
self.parent_j = 0
self.f = float('inf')
self.g = float('inf')
self.h = 0

def is_valid(row, col, ROW, COL):


return (row >= 0) and (row < ROW) and (col >= 0) and (col < COL)

# Check if a cell is unblocked


def is_unblocked(grid, row, col):
return grid[row][col] == 1

def is_destination(row, col, dest):


return row == dest[0] and col == dest[1]

def calculate_h_value(row, col, dest):


return math.sqrt((row - dest[0]) ** 2 + (col - dest[1]) ** 2)

def trace_path(cell_details, dest):


print("The Path is ")
path = []
row = dest[0]
col = dest[1]

while not (cell_details[row][col].parent_i == row and cell_details[row][col].parent_j ==


col):
path.append((row, col))
temp_row = cell_details[row][col].parent_i
temp_col = cell_details[row][col].parent_j
row = temp_row
col = temp_col

path.append((row, col))

path.reverse()

# Print the path


for i in path:
print("->", i, end=" ")
print()

def a_star_search(grid, src, dest):


ROW = len(grid)
COL = len(grid[0])

if not is_valid(src[0], src[1], ROW, COL) or not is_valid(dest[0], dest[1], ROW, COL):
print("Source or destination is invalid")
return
# Check if the source and destination are unblocked
if not is_unblocked(grid, src[0], src[1]) or not is_unblocked(grid, dest[0], dest[1]):
print("Source or the destination is blocked")
return

if is_destination(src[0], src[1], dest):


print("We are already at the destination")
return

closed_list = [[False for _ in range(COL)] for _ in range(ROW)]

cell_details = [[Cell() for _ in range(COL)] for _ in range(ROW)]

# Initialize the start cell details


i = src[0]
j = src[1]
cell_details[i][j].f = 0
cell_details[i][j].g = 0
cell_details[i][j].h = 0
cell_details[i][j].parent_i = i
cell_details[i][j].parent_j = j

open_list = []
heapq.heappush(open_list, (0.0, i, j))

found_dest = False
while len(open_list) > 0:

p = heapq.heappop(open_list)

i = p[1]
j = p[2]
closed_list[i][j] = True

directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
for dir in directions:
new_i = i + dir[0]
new_j = j + dir[1]

if is_valid(new_i, new_j, ROW, COL) and is_unblocked(grid, new_i, new_j) and not
closed_list[new_i][new_j]:

if is_destination(new_i, new_j, dest):

cell_details[new_i][new_j].parent_i = i
cell_details[new_i][new_j].parent_j = j
print("The destination cell is found")

trace_path(cell_details, dest)
found_dest = True
return
else:

g_new = cell_details[i][j].g + 1.0


h_new = calculate_h_value(new_i, new_j, dest)
f_new = g_new + h_new

if cell_details[new_i][new_j].f == float('inf') or cell_details[new_i][new_j].f >


f_new:

heapq.heappush(open_list, (f_new, new_i, new_j))

cell_details[new_i][new_j].f = f_new
cell_details[new_i][new_j].g = g_new
cell_details[new_i][new_j].h = h_new
cell_details[new_i][new_j].parent_i = i
cell_details[new_i][new_j].parent_j = j

if not found_dest:
print("Failed to find the destination cell")

def main():

ROW = int(input("Enter the number of rows in the grid: "))


COL = int(input("Enter the number of columns in the grid: "))
print("Enter the grid (1 for unblocked, 0 for blocked):")
grid = []
for i in range(ROW):
row = list(map(int, input().split()))
grid.append(row)

src = list(map(int, input("Enter the source cell coordinates (row col): ").split()))
dest = list(map(int, input("Enter the destination cell coordinates (row col): ").split()))

a_star_search(grid, src, dest)

if __name__ == "__main__":
main()

Enter the number of rows in the grid: 5


Enter the number of columns in the grid: 5
Enter the grid (1 for unblocked, 0 for blocked):
11111
00000
11111
00000
11111
Enter the source cell coordinates (row col): 1 1
Enter the destination cell coordinates (row col): 3 3
Source or the destination is blocked

Best first search


from queue import PriorityQueue
v = 14
graph = [[] for i in range(v)]

def best_first_search(actual_Src, target, n):


visited = [False] * n
pq = PriorityQueue()
pq.put((0, actual_Src))
visited[actual_Src] = True

while pq.empty() == False:


u = pq.get()[1]
print(u, end=" ")
if u == target:
break

for v, c in graph[u]:
if visited[v] == False:
visited[v] = True
pq.put((c, v))
print()

def addedge(x, y, cost):


graph[x].append((y, cost))
graph[y].append((x, cost))

edges = int(input("Enter the number of edges: "))


for _ in range(edges):
x, y, cost = map(int, input("Enter edge (x y cost): ").split())
addedge(x, y, cost)

source = int(input("Enter the source node: "))


target = int(input("Enter the target node: "))

best_first_search(source, target, v)

Enter the number of edges: 13


Enter edge (x y cost): 0 1 3
Enter edge (x y cost): 0 2 6
Enter edge (x y cost): 1 3 9
Enter edge (x y cost): 1 4 8
Enter edge (x y cost): 2 5 12
Enter edge (x y cost): 2 6 14
Enter edge (x y cost): 3 7 6
Enter edge (x y cost): 4 8 5
Enter edge (x y cost): 5 9 10
Enter edge (x y cost): 5 10 4
Enter edge (x y cost): 6 11 3
Enter edge (x y cost): 6 12 8
Enter edge (x y cost): 7 13 9
Enter the source node: 0
Enter the target node: 9

MINMAX

initial_board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]

def print_board(board):
for row in board:
print("|".join(row))
print("-----")

def check_winner(board, player):

for i in range(3):
if all(board[i][j] == player for j in range(3)) or all(board[j][i] == player for j in range(3)):
return True
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

# Function to check if the board is full (a tie)


def is_full(board):
return all(board[i][j] != ' ' for i in range(3) for j in range(3))

# Minimax function with alpha-beta pruning


def minimax(board, depth, alpha, beta, maximizing_player):
if check_winner(board, 'O'):
return -1
elif check_winner(board, 'X'):
return 1
elif is_full(board):
return 0

if maximizing_player:
max_eval = float('-inf')
for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'X'
eval = minimax(board, depth + 1, alpha, beta, False)
board[i][j] = ' '
max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break # Beta cutoff
return max_eval
else:
min_eval = float('inf')
for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'O'
eval = minimax(board, depth + 1, alpha, beta, True)
board[i][j] = ' '
min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break # Alpha cutoff
return min_eval

def find_best_move(board):
best_val = float('-inf')
best_move = (-1, -1)
alpha = float('-inf')
beta = float('inf')

for i in range(3):
for j in range(3):
if board[i][j] == ' ':
board[i][j] = 'X'
move_val = minimax(board, 0, alpha, beta, False)
board[i][j] = ' '

if move_val > best_val:


best_move = (i, j)
best_val = move_val

alpha = max(alpha, move_val)

return best_move

# Main function to play the game


def play_game():
current_board = initial_board

while not check_winner(current_board, 'X') and not check_winner(current_board, 'O')


and not is_full(current_board):
print_board(current_board)
player_move = tuple(map(int, input("Enter your move (row and column, separated by a
space): ").split()))

if current_board[player_move[0]][player_move[1]] == ' ':


current_board[player_move[0]][player_move[1]] = 'O'
else:
print("Invalid move. Try again.")
continue

if check_winner(current_board, 'O'):
print_board(current_board)
print("Congratulations! You won!")
break

if is_full(current_board):
print_board(current_board)
print("It's a tie!")
break

print("Computer is making a move...")


computer_move = find_best_move(current_board)
current_board[computer_move[0]][computer_move[1]] = 'X'

if check_winner(current_board, 'X'):
print_board(current_board)
print("Computer wins! Better luck next time.")
break

if is_full(current_board):
print_board(current_board)
print("It's a tie!")
break
play_game()

ALPHA BETA

import math

def minimax(node, depth, alpha, beta, maximizing_player):

if depth == 0 or node.is_terminal():

return node.evaluate(), None

if maximizing_player:

max_eval = -math.inf

best_move = None

for child_node in node.generate_children():

eval, _ = minimax(child_node, depth - 1, alpha, beta, False)

max_eval = max(max_eval, eval)

if max_eval > alpha:

alpha = max_eval

best_move = child_node

if alpha >= beta:

break

return max_eval, best_move

else:

min_eval = math.inf
best_move = None

for child_node in node.generate_children():

eval, _ = minimax(child_node, depth - 1, alpha, beta, True)

min_eval = min(min_eval, eval)

if min_eval < beta:

beta = min_eval

best_move = child_node

if beta <= alpha:

break

return min_eval, best_move

# Example usage:

class Node:

def __init__(self, value, children=None):

self.value = value

self.children = children if children else []

def is_terminal(self):

return len(self.children) == 0

def evaluate(self):

return self.value

def generate_children(self):

return self.children
root = Node(0)

node1 = Node(5, [Node(3), Node(6), Node(8)])

node2 = Node(2, [Node(9), Node(7), Node(4)])

root.children = [node1, node2]

best_score, best_move = minimax(root, 3, -math.inf, math.inf, True)

print("Best Score:", best_score)

print("Best Move:", best_move.value if best_move else None)


Shobhit tomar
21bit0093

artiFiCiaL iNtELLiGENCE Lab (bitE308P)


DiGitaL aSSiGNmENt 1

1. Write a Program to Implement Breadth First


Search.
CODE:
# Python3 Program to print BFS traversal

# from a given source vertex. BFS(int s)

# traverses vertices reachable from s.

from collections import defaultdict #

This class represents a directed graph

# using adjacency list representation

class Graph:

# Constructor

def __init__(self): #

Default dictionary to

store graph self.graph =

defaultdict(list)
# Function to add an edge to

graph def addEdge(self, u, v):

self.graph[u].append(v)

# Function to print a BFS of graph

def BFS(self, s):

# Mark all the vertices as not visited

visited = [False] * (max(self.graph) + 1)

# Create a queue for BFS

queue = []

# Mark the source node as

# visited and enqueue it

queue.append(s)

visited[s] = True

while

queue:

# Dequeue a vertex

from # queue and print it

s = queue.pop(0)

print(s, end=" ")

# Get all adjacent vertices of the

# dequeued vertex s.

# If an adjacent has not been visited,

# then mark it visited and enqueue it

for i in self.graph[s]:

if visited[i] == False:
queue.append(i)

visited[i] = True

# Driver code

__name__== '__main__':

# Create a graph given

in # the above diagram

g = Graph()

g.addEdge(0, 1)

g.addEdge(0, 2)

g.addEdge(1, 2)

g.addEdge(2, 0)

g.addEdge(2, 3)

g.addEdge(3, 3)

print("Following is Breadth First Traversal"

" (starting from vertex 2)") g.BFS(2)

Implementation In Laptop :
2. Write a Program to Implement Depth First Search
technique.
CODE:
# Python3 program to print DFS traversal

# from a given graph from

collections import defaultdict

# This class represents a directed graph using

# adjacency list representation class

Graph:

# Constructor

def __init__(self):

# Default dictionary to store graph

self.graph = defaultdict(list)
# Function to add an edge to graph

def addEdge(self, u, v):

self.graph[u].append(v)

# A function used by DFS

def DFSUtil(self, v, visited):

# Mark the current node as visited

# and print it

visited.add(v) print(v,

end=' ')

# Recur for all the vertices

# adjacent to this vertex for

neighbour in self.graph[v]: if

neighbour not in visited:

self.DFSUtil(neighbour, visited)

# The function to do DFS traversal. It uses

# recursive DFSUtil()

def DFS(self, v):

# Create a set to store visited vertices

visited = set()

# Call the recursive helper function # to print DFS

traversal self.DFSUtil(v, visited)


# Driver's code if __name__

== "__main__":

g = Graph()

g.addEdge(0, 1)

g.addEdge(0, 2)

g.addEdge(1, 2)

g.addEdge(2, 0)

g.addEdge(2, 3)

g.addEdge(3, 3)

print("Following is Depth First Traversal (starting from vertex 2)")

# Function call

g.DFS(2)
3. Write a program to implement the Greedy Best
First Search technique.
CODE:
from typing import List, Tuple

grid = [

[0, 0, 0, 0, 0, 0, 0],

[0, 1, 0, 0, 0, 0, 0], # 0 are free path whereas 1's are obstacles

[0, 0, 0, 0, 0, 0, 0],

[0, 0, 1, 0, 0, 0, 0],

[1, 0, 1, 0, 0, 0, 0],

[0, 0, 0, 0, 0, 0, 0],

[0, 0, 0, 0, 1, 0, 0],

delta = ([-1, 0], [0, -1], [1, 0], [0, 1]) # up, left, down, right

class Node:

"""

>>> k = Node(0, 0, 4, 5, 0, None)

>>> k.calculate_heuristic()

>>> n = Node(1, 4, 3, 4, 2, None)

>>> n.calculate_heuristic()

>>> l = [k, n]

>>> n == l[0]

False
>>> l.sort()

>>> n == l[0]

True

"""

def __init__(self, pos_x, pos_y, goal_x, goal_y, g_cost, parent):

self.pos_x = pos_x self.pos_y =

pos_y self.pos = (pos_y, pos_x)

self.goal_x = goal_x self.goal_y =

goal_y self.g_cost = g_cost

self.parent = parent self.f_cost =

self.calculate_heuristic()

def calculate_heuristic(self) -> float:

"""

The heuristic here is the Manhattan Distance

Could elaborate to offer more than one choice

"""

dy = abs(self.pos_x - self.goal_x)

dx = abs(self.pos_y - self.goal_y)

return dx + dy

def __lt__(self, other) -> bool:

return self.f_cost < other.f_cost

class GreedyBestFirst:

"""

>>> gbf = GreedyBestFirst((0, 0), (len(grid) - 1, len(grid[0]) - 1))

>>> [x.pos for x in gbf.get_successors(gbf.start)]


[(1, 0), (0, 1)]

>>> (gbf.start.pos_y + delta[3][0], gbf.start.pos_x + delta[3][1]) (0, 1)

>>> (gbf.start.pos_y + delta[2][0], gbf.start.pos_x + delta[2][1])

(1, 0)

>>> gbf.retrace_path(gbf.start)

[(0, 0)]

>>> gbf.search() # doctest: +NORMALIZE_WHITESPACE

[(0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (4, 1), (5, 1), (6, 1),

(6, 2), (6, 3), (5, 3), (5, 4), (5, 5), (6, 5), (6, 6)]

"""

def __init__(self, start, goal):

self.start = Node(start[1], start[0], goal[1], goal[0], 0, None)

self.target = Node(goal[1], goal[0], goal[1], goal[0], 99999, None)

self.open_nodes = [self.start]

self.closed_nodes = []

self.reached = False

def search(self) -> List[Tuple[int]]:

"""

Search for the path, if a path is not found, only the

starting position is returned

"""

while self.open_nodes:

# Open Nodes are sorted using __lt__

self.open_nodes.sort() current_node =

self.open_nodes.pop(0)
if current_node.pos == self.target.pos:

self.reached = True

return self.retrace_path(current_node)

self.closed_nodes.append(current_node)

successors = self.get_successors(current_node)

for child_node in successors:

if child_node in self.closed_nodes:

continue

if child_node not in self.open_nodes:

self.open_nodes.append(child_node)

else:

# retrieve the best current path

better_node = self.open_nodes.pop(self.open_nodes.index(child_node))

if child_node.g_cost < better_node.g_cost:

self.open_nodes.append(child_node)

else:

self.open_nodes.append(better_node)

if not (self.reached):

return [self.start.pos]

def get_successors(self, parent: Node) -> List[Node]:

"""

Returns a list of successors (both in the grid and free spaces)

"""
successors = []

for action in delta:

pos_x = parent.pos_x + action[1]

pos_y = parent.pos_y + action[0] if not

(0 <= pos_x <= len(grid[0]) - 1 and 0 <= pos_y

<= len(grid) - 1):

continue

if grid[pos_y][pos_x] != 0:

continue

successors.append(

Node( pos_x,

pos_y,

self.target.pos_y,

self.target.pos_x,

parent.g_cost + 1,

parent,

return successors

def retrace_path(self, node: Node) -> List[Tuple[int]]:

"""

Retrace the path from parents to parents until start node

"""

current_node = node

path = [] while

current_node is not None:


path.append((current_node.pos_y, current_node.pos_x))

current_node = current_node.parent path.reverse()

return path

if __name__ == "__main__":

init = (0, 0) goal = (len(grid) - 1,

len(grid[0]) - 1) for elem in grid:

print(elem)

print("------")

greedy_bf = GreedyBestFirst(init, goal)

path = greedy_bf.search()

for elem in path:

grid[elem[0]][elem[1]] = 2

for elem in grid:


print(elem)
4. Write a program to implement A* Algorithm
CODE:
#include <bits/stdc++.h> using

namespace std;

#define ROW 9

#define COL 10

// Creating a shortcut for int, int pair type typedef

pair<int, int> Pair;

// Creating a shortcut for pair<int, pair<int, int>> type typedef

pair<double, pair<int, int> > pPair;

// A structure to hold the necessary parameters

struct cell {

// Row and Column index of its parent //

Note that 0 <= i <= ROW-1 & 0 <= j <= COL-1 int

parent_i, parent_j; // f = g + h double f, g, h;

};

// A Utility Function to check whether given cell (row, col)

// is a valid cell or not. bool

isValid(int row, int col)

// Returns true if row number and column number

// is in range

return (row >= 0) && (row < ROW) && (col >= 0)

&& (col < COL);


}

// A Utility Function to check whether the given cell is

// blocked or not bool isUnBlocked(int

grid[][COL], int row, int col)

// Returns true if the cell is not blocked else false

if (grid[row][col] == 1)

return (true);

else

return (false);

// A Utility Function to check whether destination cell has

// been reached or not bool

isDestination(int row, int col, Pair dest)

if (row == dest.first && col == dest.second)

return (true);

else

return (false);

// A Utility Function to calculate the 'h' heuristics. double

calculateHValue(int row, int col, Pair dest)

// Return using the distance formula

return ((double)sqrt(

(row - dest.first) * (row - dest.first)

+ (col - dest.second) * (col - dest.second)));


}

// A Utility Function to trace the path from the source

// to destination void tracePath(cell

cellDetails[][COL], Pair dest)

printf("\nThe Path is ");

int row = dest.first; int col

= dest.second;

stack<Pair> Path;

while (!(cellDetails[row][col].parent_i == row

&& cellDetails[row][col].parent_j == col)) {

Path.push(make_pair(row, col)); int temp_row =

cellDetails[row][col].parent_i; int temp_col =

cellDetails[row][col].parent_j;

row = temp_row;

col = temp_col;

Path.push(make_pair(row, col)); while

(!Path.empty()) { pair<int, int> p =

Path.top();

Path.pop();

printf("-> (%d,%d) ", p.first, p.second);

return;

}
// A Function to find the shortest path between

// a given source cell to a destination cell according

// to A* Search Algorithm void aStarSearch(int

grid[][COL], Pair src, Pair dest)

// If the source is out of range if

(isValid(src.first, src.second) == false) {

printf("Source is invalid\n");

return;

// If the destination is out of range if

(isValid(dest.first, dest.second) == false) {

printf("Destination is invalid\n");

return;

// Either the source or the destination is blocked

if (isUnBlocked(grid, src.first, src.second) == false

|| isUnBlocked(grid, dest.first, dest.second)

== false) {

printf("Source or the destination is blocked\n");

return;

// If the destination cell is the same as source cell

if (isDestination(src.first, src.second, dest)

== true) {

printf("We are already at the destination\n");

return;
}

// Create a closed list and initialise it to false which

// means that no cell has been included yet This closed //

list is implemented as a boolean 2D array

bool closedList[ROW][COL];

memset(closedList, false, sizeof(closedList));

// Declare a 2D array of structure to hold the details

// of that cell cell

cellDetails[ROW][COL];

int i, j;

for (i = 0; i < ROW; i++) {

for (j = 0; j < COL; j++) {

cellDetails[i][j].f = FLT_MAX;

cellDetails[i][j].g = FLT_MAX;

cellDetails[i][j].h = FLT_MAX;

cellDetails[i][j].parent_i = -1;

cellDetails[i][j].parent_j = -1;

// Initialising the parameters of the starting node

i = src.first, j = src.second; cellDetails[i][j].f = 0.0;

cellDetails[i][j].g = 0.0; cellDetails[i][j].h = 0.0;

cellDetails[i][j].parent_i = i;

cellDetails[i][j].parent_j = j;

/*
Create an open list having information as-

<f, <i, j>> where

f = g + h,

and i, j are the row and column index of that cell

Note that 0 <= i <= ROW-1 & 0 <= j <= COL-1

This open list is implemented as a set of pair of

pair.*/

set<pPair> openList;

// Put the starting cell on the open list and set its

// 'f' as 0

openList.insert(make_pair(0.0, make_pair(i, j)));

// We set this boolean value as false as initially

// the destination is not reached.

bool foundDest = false;

while (!openList.empty()) {

pPair p = *openList.begin();

// Remove this vertex from the open list

openList.erase(openList.begin());

// Add this vertex to the closed list

i = p.second.first;

j = p.second.second;

closedList[i][j] = true;

/*

Generating all the 8 successor of this cell


N.W N N.E

\|/

\|/

W----Cell----E

/|\

/|\

S.W S S.E

Cell-->Popped Cell (i, j)

N --> North (i-1, j)

S --> South (i+1, j)

E --> East (i, j+1)

W --> West (i, j-1)

N.E--> North-East (i-1, j+1)

N.W--> North-West (i-1, j-1)

S.E--> South-East (i+1, j+1)

S.W--> South-West (i+1, j-1)*/

// To store the 'g', 'h' and 'f' of the 8 successors

double gNew, hNew, fNew;

//----------- 1st Successor (North) ------------

// Only process this cell if this is a valid one

if (isValid(i - 1, j) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i - 1, j, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i - 1][j].parent_i = i;
cellDetails[i - 1][j].parent_j = j;

printf("The destination cell is

found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i - 1][j] == false

&& isUnBlocked(grid, i - 1, j)

== true) {

gNew = cellDetails[i][j].g + 1.0;

hNew = calculateHValue(i - 1, j, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i - 1][j].f == FLT_MAX

|| cellDetails[i - 1][j].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i - 1, j)));


// Update the details of this cell

cellDetails[i - 1][j].f = fNew;

cellDetails[i - 1][j].g = gNew;

cellDetails[i - 1][j].h = hNew;

cellDetails[i - 1][j].parent_i = i;

cellDetails[i - 1][j].parent_j = j;

//----------- 2nd Successor (South) ------------

// Only process this cell if this is a valid one

if (isValid(i + 1, j) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i + 1, j, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i + 1][j].parent_i = i;

cellDetails[i + 1][j].parent_j = j; printf("The

destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i + 1][j] == false

&& isUnBlocked(grid, i + 1, j)
== true) {

gNew = cellDetails[i][j].g + 1.0; hNew

= calculateHValue(i + 1, j, dest); fNew

= gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i + 1][j].f == FLT_MAX

|| cellDetails[i + 1][j].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i + 1, j))); // Update

the details of this cell cellDetails[i +

1][j].f = fNew; cellDetails[i + 1][j].g =

gNew; cellDetails[i + 1][j].h = hNew;

cellDetails[i + 1][j].parent_i = i;

cellDetails[i + 1][j].parent_j = j;

//----------- 3rd Successor (East) ------------

// Only process this cell if this is a valid one

if (isValid(i, j + 1) == true) {

// If the destination cell is the same as the


// current successor

if (isDestination(i, j + 1, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i][j + 1].parent_i = i;

cellDetails[i][j + 1].parent_j = j;

printf("The destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i][j + 1] == false

&& isUnBlocked(grid, i, j + 1)

== true) {

gNew = cellDetails[i][j].g + 1.0;

hNew = calculateHValue(i, j + 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i][j + 1].f == FLT_MAX


|| cellDetails[i][j + 1].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i, j + 1)));

// Update the details of this cell

cellDetails[i][j + 1].f =

fNew; cellDetails[i][j + 1].g =

gNew;

cellDetails[i][j + 1].h = hNew;

cellDetails[i][j + 1].parent_i = i;

cellDetails[i][j + 1].parent_j = j;

//----------- 4th Successor (West) ------------

// Only process this cell if this is a valid one

if (isValid(i, j - 1) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i, j - 1, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i][j - 1].parent_i = i;

cellDetails[i][j - 1].parent_j = j; printf("The

destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

}
// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i][j - 1] == false

&& isUnBlocked(grid, i, j - 1)

== true) {

gNew = cellDetails[i][j].g + 1.0;

hNew = calculateHValue(i, j - 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i][j - 1].f == FLT_MAX

|| cellDetails[i][j - 1].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i, j - 1)));

// Update the details of this cell

cellDetails[i][j - 1].f = fNew;

cellDetails[i][j - 1].g = gNew;

cellDetails[i][j - 1].h = hNew;

cellDetails[i][j - 1].parent_i = i;

cellDetails[i][j - 1].parent_j = j;

}
}

//----------- 5th Successor (North-East)

//------------

// Only process this cell if this is a valid one if

(isValid(i - 1, j + 1) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i - 1, j + 1, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i - 1][j + 1].parent_i = i;

cellDetails[i - 1][j + 1].parent_j = j;

printf("The destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i - 1][j + 1] == false

&& isUnBlocked(grid, i - 1, j + 1)

== true) {

gNew = cellDetails[i][j].g + 1.414;

hNew = calculateHValue(i - 1, j + 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to


// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure. if

(cellDetails[i - 1][j + 1].f == FLT_MAX ||

cellDetails[i - 1][j + 1].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i - 1, j + 1)));

// Update the details of this cell

cellDetails[i - 1][j + 1].f = fNew;

cellDetails[i - 1][j + 1].g = gNew;

cellDetails[i - 1][j + 1].h = hNew;

cellDetails[i - 1][j + 1].parent_i = i;

cellDetails[i - 1][j + 1].parent_j = j;

//----------- 6th Successor (North-West)

//------------

// Only process this cell if this is a valid one

if (isValid(i - 1, j - 1) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i - 1, j - 1, dest) == true) {


// Set the Parent of the destination cell

cellDetails[i - 1][j - 1].parent_i = i;

cellDetails[i - 1][j - 1].parent_j = j;

printf("The destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true; return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i - 1][j - 1] == false

&& isUnBlocked(grid, i - 1, j - 1)

== true) {

gNew = cellDetails[i][j].g + 1.414;

hNew = calculateHValue(i - 1, j - 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i - 1][j - 1].f == FLT_MAX

|| cellDetails[i - 1][j - 1].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i - 1, j - 1)));


// Update the details of this cell

cellDetails[i - 1][j - 1].f = fNew;

cellDetails[i - 1][j - 1].g = gNew;

cellDetails[i - 1][j - 1].h = hNew;

cellDetails[i - 1][j - 1].parent_i = i;

cellDetails[i - 1][j - 1].parent_j = j;

//----------- 7th Successor (South-East)

//------------

// Only process this cell if this is a valid one

if (isValid(i + 1, j + 1) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i + 1, j + 1, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i + 1][j + 1].parent_i = i;

cellDetails[i + 1][j + 1].parent_j = j;

printf("The destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following


else if (closedList[i + 1][j + 1] == false

&& isUnBlocked(grid, i + 1, j + 1)

== true) {

gNew = cellDetails[i][j].g + 1.414;

hNew = calculateHValue(i + 1, j + 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the

// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i + 1][j + 1].f == FLT_MAX ||

cellDetails[i + 1][j + 1].f > fNew) {

openList.insert(make_pair(

fNew, make_pair(i + 1, j + 1)));

// Update the details of this cell

cellDetails[i + 1][j + 1].f = fNew;

cellDetails[i + 1][j + 1].g = gNew;

cellDetails[i + 1][j + 1].h = hNew;

cellDetails[i + 1][j + 1].parent_i = i;

cellDetails[i + 1][j + 1].parent_j = j;

}
//----------- 8th Successor (South-West)

//------------

// Only process this cell if this is a valid one

if (isValid(i + 1, j - 1) == true) {

// If the destination cell is the same as the

// current successor

if (isDestination(i + 1, j - 1, dest) == true) {

// Set the Parent of the destination cell

cellDetails[i + 1][j - 1].parent_i = i;

cellDetails[i + 1][j - 1].parent_j = j;

printf("The destination cell is found\n");

tracePath(cellDetails, dest);

foundDest = true;

return;

// If the successor is already on the closed

// list or if it is blocked, then ignore it.

// Else do the following

else if (closedList[i + 1][j - 1] == false

&& isUnBlocked(grid, i + 1, j - 1)

== true) {

gNew = cellDetails[i][j].g + 1.414;

hNew = calculateHValue(i + 1, j - 1, dest);

fNew = gNew + hNew;

// If it isn’t on the open list, add it to

// the open list. Make the current square

// the parent of this square. Record the


// f, g, and h costs of the square cell

// OR

// If it is on the open list already, check

// to see if this path to that square is

// better, using 'f' cost as the measure.

if (cellDetails[i + 1][j - 1].f == FLT_MAX

|| cellDetails[i + 1][j - 1].f >

fNew) { openList.insert(make_pair(

fNew, make_pair(i + 1, j - 1)));

// Update the details of this cell

cellDetails[i + 1][j - 1].f = fNew;

cellDetails[i + 1][j - 1].g = gNew;

cellDetails[i + 1][j - 1].h = hNew;

cellDetails[i + 1][j - 1].parent_i = i; cellDetails[i + 1][j - 1].parent_j = j;

// When the destination cell is not found and the open

// list is empty, then we conclude that we failed to

// reach the destination cell. This may happen when the

// there is no way to destination cell (due to

// blockages) if (foundDest == false)

printf("Failed to find the Destination Cell\n");

return;

}
// Driver program to test above function int

main()

/* Description of the Grid- 1--> The

cell is not blocked

0--> The cell is blocked */ int

grid[ROW][COL]

= { { 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },

{ 1, 1, 1, 0, 1, 1, 1, 0, 1, 1 },

{ 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 },

{ 0, 0, 1, 0, 1, 0, 0, 0, 0, 1 },

{ 1, 1, 1, 0, 1, 1, 1, 0, 1, 0 },

{ 1, 0, 1, 1, 1, 1, 0, 1, 0, 0 },

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1 },

{ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },

{ 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 } };

// Source is the left-most bottom-most corner

Pair src = make_pair(8, 0);

// Destination is the left-most top-most corner

Pair dest = make_pair(0, 0);

aStarSearch(grid, src, dest);

return (0);
}

5. Write a program to implement AO* Algorithm


CODE:
# Cost to find the AND and OR path def

Cost(H, condition, weight = 1):

cost = {}

if 'AND' in condition:

AND_nodes = condition['AND']

Path_A = ' AND '.join(AND_nodes)

PathA = sum(H[node]+weight for node in AND_nodes)

cost[Path_A] = PathA

if 'OR' in condition:

OR_nodes = condition['OR']

Path_B =' OR '.join(OR_nodes)

PathB = min(H[node]+weight for node in

OR_nodes) cost[Path_B] = PathB return cost


# Update the cost def update_cost(H,

Conditions, weight=1):

Main_nodes = list(Conditions.keys())

Main_nodes.reverse() least_cost= {} for

key in Main_nodes:

condition = Conditions[key]

print(key,':', Conditions[key],'>>>', Cost(H, condition, weight))

c = Cost(H, condition, weight)

H[key] = min(c.values()) least_cost[key] =

Cost(H, condition, weight) return

least_cost

# Print the shortest path

def shortest_path(Start,Updated_cost, H):

Path = Start

if Start in Updated_cost.keys():

Min_cost = min(Updated_cost[Start].values())

key = list(Updated_cost[Start].keys())

values = list(Updated_cost[Start].values())

Index = values.index(Min_cost)

# FIND MINIMIMUM PATH KEY

Next = key[Index].split()

# ADD TO PATH FOR OR PATH

if len(Next) == 1:

Start =Next[0]

Path += '<--' +shortest_path(Start, Updated_cost, H)

# ADD TO PATH FOR AND PATH

else:
Path +='<--('+key[Index]+') '

Start = Next[0]

Path += '[' +shortest_path(Start, Updated_cost, H) + ' + '

Start = Next[-1]

Path += shortest_path(Start, Updated_cost, H) + ']'

return Path

H = {'A': -1, 'B': 5, 'C': 2, 'D': 4, 'E': 7, 'F': 9, 'G': 3, 'H': 0, 'I':0, 'J':0}

Conditions = {

'A': {'OR': ['B'], 'AND': ['C', 'D']},

'B': {'OR': ['E', 'F']},

'C': {'OR': ['G'], 'AND': ['H', 'I']},

'D': {'OR': ['J']}

# weight weight = 1 #

Updated cost

print('Updated Cost :')

Updated_cost = update_cost(H, Conditions, weight=1)

print('*'*75) print('Shortest Path :\n',shortest_path('A',

Updated_cost,H))
6. Write a program to implement Simulated Annealing
Algorithm
CODE:
#include <bits/stdc++.h>

using namespace std;

//c++ code for the above approach

class Solution {

public: float

CVRMSE;

vector<int> config;

Solution(float CVRMSE, vector<int> configuration) {

this->CVRMSE = CVRMSE;

config = configuration;

};
// Function prototype

Solution genRandSol();

// global variables. Int

T = 1;

float Tmin = 0.0001;

float alpha = 0.9; int

numIterations = 100; int

M = 5; int N = 5;

vector<vector<char>> sourceArray(M, vector<char>(N, ‘X’)); vector<int>

temp = {};

Solution mini = Solution((float)INT_MAX, temp);

Solution currentSol = genRandSol();

Solution genRandSol() {

// Instantiating for the sake of compilation vector<int> a = {1, 2,

3, 4, 5}; return Solution(-1.0, a);

Solution neighbor(Solution currentSol) {

return currentSol;

float cost(vector<int> inputConfiguration) {

return -1.0;

}
// Mapping from [0, M*N]  [0,M]x[0,N]

vector<int> indexToPoints(int index) {

vector<int> points = {index % M,index/M};

return points;

//Returns minimum value based on optimization

int main(){

while (T > Tmin) { for (int I =

0; I < numIterations; i++) {

// Reassigns global minimum accordingly

if (currentSol.CVRMSE < mini.CVRMSE) {

mini = currentSol;

Solution newSol = neighbor(currentSol);

float ap = exp((currentSol.CVRMSE – newSol.CVRMSE) / T);

srand( (unsigned)time( NULL ) );


if (ap > (float) rand()/RAND_MAX) {

currentSol = newSol;

T *= alpha; // Decreases T, cooling phase

cout << mini.CVRMSE << “\n\n”;

for (int I = 0; I < M; i++) {

for (int j = 0; j < N; j++) {

sourceArray[i][j] = ‘X’;

// Displays for(int index = 0; index <

mini.config.size(); index++){

int obj = mini.config[index];

vector<int> coord = indexToPoints(obj);

sourceArray[coord[0]][coord[1]] = ‘-‘;

// Displays optimal location for

(int I = 0; I < M; i++) {

string row = “”;

for (int j = 0; j < N; j++) {

row = row + sourceArray[i][j] + “ “;

cout << (row) << endl;

}
}
7. Write a program to implement Hill Climbing
Algorithm
CODE:
#include <algorithm>

#include <iostream>

#include <vector>

// Generates neighbors of x std::vector<int>

generate_neighbors(int x)

// TODO: implement this function

int hill_climbing(int (*f)(int), int x0)

int x = x0; // initial solution

while (true) { std::vector<int> neighbors =

generate_neighbors(

x); // generate neighbors of x


int best_neighbor = *std::max_element(

neighbors.begin(), neighbors.end(),

[f](int a, int b) {

return f(a) < f(b);

}); // find the neighbor with the highest

// function value

if (f(best_neighbor)

<= f(x)) // if the best neighbor is not better

// than x, stop

return x;

x = best_neighbor; // otherwise, continue with the

// best neighbor

int main()

// Example usage

int x0 = 1;

int x = hill_climbing([](int x) { return x * x; }, x0);

std::cout << “Result: “ << x << std::endl;

return 0;

}
Shobhit Tomar
21BIT0093
Artificial Intelligence Lab
Digital Assignment 2

Q1. Write a Program to Implement 8-Puzzle problem.

CODE:

import heapq

import itertools

class PuzzleNode:

def __init__(self, state, parent=None, move=None):

self.state = state

self.parent = parent

self.move = move

if parent is not None:

self.cost = parent.cost + 1

else:

self.cost = 0

def __lt__(self, other):

return self.cost < other.cost

def __eq__(self, other):

return self.state == other.state


def __hash__(self):

return hash(str(self.state))

def __repr__(self):

return f"Node with state: {self.state}, cost: {self.cost}"

def get_blank_position(self):

for i, row in enumerate(self.state):

for j, value in enumerate(row):

if value == 0:

return i, j

def get_children(self):

i, j = self.get_blank_position()

children = []

for new_i, new_j in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:

if 0 <= new_i < 3 and 0 <= new_j < 3:

new_state = [list(row) for row in self.state]

new_state[i][j], new_state[new_i][new_j] = new_state[new_i][new_j], new_state[i][j]

children.append(PuzzleNode(new_state, parent=self, move=(i, j)))

return children

def manhattan_distance(state):

distance = 0

for i in range(3):

for j in range(3):

value = state[i][j]

if value != 0:
goal_i, goal_j = divmod(value - 1, 3)

distance += abs(i - goal_i) + abs(j - goal_j)

return distance

def solve_puzzle(initial_state):

initial_node = PuzzleNode(initial_state)

frontier = [initial_node]

visited = set()

while frontier:

current_node = heapq.heappop(frontier)

visited.add(current_node)

if current_node.state == goal_state:

path = []

while current_node.parent:

path.append(current_node.move)

current_node = current_node.parent

path.reverse()

return path

for child in current_node.get_children():

if child not in visited:

child_cost = child.cost + manhattan_distance(child.state)

heapq.heappush(frontier, child)

visited.add(child)

initial_state = [

[2, 8, 3],

[1, 6, 4],

[7, 0, 5]
]

goal_state = [

[1, 2, 3],

[8, 0, 4],

[7, 6, 5]

path = solve_puzzle(initial_state)

if path:

print("Moves to solve the puzzle:")

for move in path:

print(move)

else:

print("No solution found.")


Output:
Q 2. Write a Program to Implement Tic-Tac-Toe game.

Code:

def print_board(board):

for row in board:

print("|".join(row))

print("-" * 5)

def check_winner(board, player):

for i in range(3):

if all(board[i][j] == player for j in range(3)):

return True

if all(board[j][i] == player for j in range(3)):

return True

if all(board[i][i] == player for i in range(3)):

return True

if all(board[i][2 - i] == player for i in range(3)):

return True

return False

def tic_tac_toe():

board = [[" " for _ in range(3)] for _ in range(3)]

players = ['X', 'O']

current_player = 0

print("Welcome to Tic-Tac-Toe!")

for _ in range(9):

print_board(board)

print(f"Player {players[current_player]}'s turn.")

row = int(input("Enter row number (0, 1, or 2): "))

col = int(input("Enter column number (0, 1, or 2): "))


if board[row][col] != " ":

print("That cell is already occupied. Try again.")

continue

board[row][col] = players[current_player]

if check_winner(board, players[current_player]):

print_board(board)

print(f"Player {players[current_player]} wins!")

return

current_player = 1 - current_player

print_board(board)

print("It's a draw!")

tic_tac_toe()

Output:
Q 3. Write a Program to Implement Water-Jug problem.

Code:
from collections import deque

# Function to check if a state is valid

def is_valid(state, jug1_capacity, jug2_capacity):

jug1, jug2 = state

return jug1 >= 0 and jug2 >= 0 and jug1 <= jug1_capacity and jug2 <= jug2_capacity

# Function to get all possible next states from the current state

def get_next_states(state, jug1_capacity, jug2_capacity):

jug1, jug2 = state

next_states = []

# Filling jug1

next_states.append((jug1_capacity, jug2) if jug1 < jug1_capacity else state)

# Filling jug2

next_states.append((jug1, jug2_capacity) if jug2 < jug2_capacity else state)

# Emptying jug1

next_states.append((0, jug2))

# Emptying jug2

next_states.append((jug1, 0))

# Pouring jug1 into jug2

amount_to_pour = min(jug1, jug2_capacity - jug2)

next_states.append((jug1 - amount_to_pour, jug2 + amount_to_pour))

# Pouring jug2 into jug1

amount_to_pour = min(jug2, jug1_capacity - jug1)

next_states.append((jug1 + amount_to_pour, jug2 - amount_to_pour))

return [state for state in next_states if is_valid(state, jug1_capacity, jug2_capacity)]


# Function to solve the Water Jug problem using BFS

def water_jug_bfs(jug1_capacity, jug2_capacity, target):

start_state = (0, 0)

visited = set()

queue = deque([(start_state, [])])

while queue:

current_state, path = queue.popleft()

if current_state == target:

return path

if current_state in visited:

continue

visited.add(current_state)

for next_state in get_next_states(current_state, jug1_capacity, jug2_capacity):

queue.append((next_state, path + [next_state]))

return None

# Example usage

jug1_capacity = 4

jug2_capacity = 3

target = (2, 0)

solution = water_jug_bfs(jug1_capacity, jug2_capacity, target)

if solution:

print("Solution found:", solution)

else:

print("No solution exists.")


Output:
Q 4. Write a Program to Implement Missionaries-Cannibals Problem.
Code:

from collections import deque

# Define the states of the problem

state_format = "MMMCCC"

initial_state = (3, 0, 3, 0)

goal_state = (0, 0, 0, 3)

# Define the actions that can be taken in each state

actions = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, -1), (-1, 1), (1, 1), (-1, -1)]

# Define the function to generate the successor states

def successors(state):

(missionaries_left, cannibals_left, missionaries_right, cannibals_right) = state

successors = []

for a in actions:

new_missionaries_left = missionaries_left - a[0]

new_cannibals_left = cannibals_left - a[1]

new_missionaries_right = missionaries_right + a[0]

new_cannibals_right = cannibals_right + a[1]

if new_missionaries_left >= 0 and new_cannibals_left >= 0 and new_missionaries_right >= 0 and


new_cannibals_right >= 0 and (new_missionaries_left > new_cannibals_left or
new_missionaries_right > new_cannibals_right):

new_state = (new_missionaries_left, new_cannibals_left, new_missionaries_right,


new_cannibals_right)

successors.append(new_state)

return successors

# Define the function to check if the goal state is reached

def is_goal(state):

(missionaries_left, cannibals_left, missionaries_right, cannibals_right) = state


return missionaries_right == 0 and cannibals_right == 3

# Define the function to print the solution path

def print_path(path):

for state in path:

print(state_format % state)

# Define the function to solve the problem using breadth-first search

def bfs():

queue = deque([(initial_state, [initial_state])])

visited = set()

while queue:

(state, path) = queue.popleft()

if state in visited:

continue

visited.add(state)

if is_goal(state):

print_path(path)

return

for new_state in successors(state):

if new_state not in visited:

queue.append((new_state, path + [new_state]))

# Call the bfs function to solve the problem

bfs()
Output:
Q 5. Write a Program to Implement N-Queens Problem.

Code:

def is_safe(board, row, col, n):

# Check this row on left side

for i in range(col):

if board[row][i] == 1:

return False

# Check upper diagonal on left side

for i, j in zip(range(row, -1, -1), range(col, -1, -1)):

if board[i][j] == 1:

return False

# Check lower diagonal on left side

for i, j in zip(range(row, n, 1), range(col, -1, -1)):

if board[i][j] == 1:

return False

return True

def solve_n_queens_util(board, col, n):

# base case: If all queens are placed

if col >= n:

return True

# Consider this column and try placing this queen in all rows one by one

for i in range(n):

if is_safe(board, i, col, n):

# Place this queen in board[i][col]

board[i][col] = 1
# recur to place rest of the queens

if solve_n_queens_util(board, col + 1, n):

return True

# If placing queen in board[i][col] doesn't lead to a solution, then remove queen from
board[i][col]

board[i][col] = 0

# If queen can not be place in any row in this column col then return false

return False

def solve_n_queens(n):

# Create an empty board with all elements 0

board = [[0 for _ in range(n)] for _ in range(n)]

if not solve_n_queens_util(board, 0, n):

print("Solution does not exist")

return None

return board

def print_solution(board):

n = len(board)

for i in range(n):

for j in range(n):

if board[i][j] == 1:

print("Q ", end="")

else:

print("* ", end="")

print()
# Test the function

n=4

board = solve_n_queens(n)

if board:

print_solution(board)

Output:
Shobhit tomar
21bit0093
artificial intelligence lab
Digital aSSignment 4
SubmitteD to – tapan kumar DaS Sir
Q1. Find a solution for wumpus world problem.
CODE:
class WumpusWorld:
def __init__(self, size):
self.size = size
self.grid = [[' ' for _ in range(size)] for _ in range(size)]
self.agent_position = (0, 0)
self.has_gold = False
self.wumpus_position = (2, 2) # Example, you can set this
randomly
self.pit_positions = [(1, 1)] # Example, you can set these
randomly

self.grid[self.agent_position[0]][self.agent_position[1]] = 'A'
self.grid[self.wumpus_position[0]][self.wumpus_position[1]] =
'W'
for pit_pos in self.pit_positions:
self.grid[pit_pos[0]][pit_pos[1]] = 'P'
self.grid[0][3] = 'G' # Gold location

def print_world(self):
for row in self.grid:
print(' '.join(row))

def is_valid(self, x, y):


return 0 <= x < self.size and 0 <= y < self.size

def dfs(self, x, y, visited):


if not self.is_valid(x, y) or (x, y) in visited:
return False
if self.grid[x][y] == 'W' or self.grid[x][y] == 'P':
return False
if self.grid[x][y] == 'G':
self.has_gold = True
print("Gold found at position:", (x, y))
return True
visited.add((x, y))
directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
for dx, dy in directions:
new_x, new_y = x + dx, y + dy
if self.dfs(new_x, new_y, visited):
return True
return False

def find_gold(self):
visited = set()
self.dfs(self.agent_position[0], self.agent_position[1], visited)
if not self.has_gold:
print("Gold not found!")
# Example usage:
world = WumpusWorld(4)
world.print_world()
world.find_gold()

Output:
Q2. The law says that it is a crime for an American to sell weapons to
hostile nations. The country Nono, an enemy of America, has some
missiles, and all of its missiles were sold to it by Colonel West, who is
American. Using Forward chaining prove that “West is a criminal.”

CODE:
rules = {
"sold_missiles": ["Colonel West", "Nono"],
"american_sold_to_hostile_nations": ["Colonel West"]
}
facts = set()

# Implement forward chaining


def forward_chaining(goal):
queue = [goal]
while queue:
current = queue.pop(0)
if current in facts:
continue
facts.add(current)
for rule, conclusion in rules.items():
if current in conclusion:
queue.append(rule)

# Prove "West is a criminal"


forward_chaining("West is a criminal")

if "West is a criminal" in facts:


print("Colonel West is a criminal.")
else:
print("Colonel West is not a criminal.")

Output:
Q3. The law says that it is a crime for an American to sell weapons to
hostile nations. The country Nono, an enemy of America, has some
missiles, and all of its missiles were sold to it by Colonel West, who is
American. Using Backward chaining prove that “West is a criminal.”

CODE:
rules = {
"sold_missiles": ["Colonel West", "Nono"],
"american_sold_to_hostile_nations": ["Colonel West"]
}
facts = set()

# Implement backward chaining


def backward_chaining(goal):
if goal in facts:
return True
for rule, conclusion in rules.items():
if goal == rule:
if all(backward_chaining(con) for con in conclusion):
facts.add(goal)
return True
return False

# Prove "West is a criminal"


backward_chaining("West is a criminal")
if "West is a criminal" in facts:
print("Colonel West is a criminal.")
else:
print("Colonel West is not a criminal.")

Output:
Q4. It is estimated that 50% of emails are spam emails. Some
software has been applied to filter these spam emails before they
reach your inbox. A certain brand of software claims that it can
detect 99% of spam emails, and the probability for a false positive (a
non-spam email detected as spam) is 5%. Now if an email is detected
as spam, then what is the probability that it is in fact a non-spam
email?
CODE:
# Prior probability of an email being spam
prior_spam = 0.5

# Sensitivity (true positive rate) of the spam detection software


sensitivity = 0.99

# False positive rate of the spam detection software


false_positive_rate = 0.05

# Calculate the probability that an email detected as spam is actually


non-spam using Bayes' theorem
posterior_non_spam = (1 - sensitivity) * (1 - prior_spam) / ((1 -
sensitivity) * (1 - prior_spam) + false_positive_rate * prior_spam)

print("Probability that an email detected as spam is non-spam:",


posterior_non_spam)
Output:
Q5. Write a program to implement the naïve Bayesian classifier for a
sample training data set stored as a .CSV file. Compute the accuracy
of the classifier, considering few test data.

CODE:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score

# Load the training data from CSV file


data = pd.read_csv('training_data.csv')

# Separate features and target variable


X = data.drop('class', axis=1)
y = data['class']

# Split the data into training and testing sets


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
random_state=42)

# Initialize the Naïve Bayes classifier


classifier = GaussianNB()

# Train the classifier on the training data


classifier.fit(X_train, y_train)

# Predict the class labels for test data


y_pred = classifier.predict(X_test)

# Calculate the accuracy of the classifier


accuracy = accuracy_score(y_test, y_pred)
print("Accuracy of the Naïve Bayes classifier:", accuracy)

Output:
Name – Shobhit tomar
reg No. – 21bit0093

CourSe Name – artifiCial iNtelligeNCe


lab

Submitted to – tapaN kumar daS Sir

digital aSSigNmeNt 5
Q1. Write a Program to solve the Monkey Banana Problem.

CODE:

class MonkeyBananaProblem:

def __init__(self, initial_state):

self.initial_state = initial_state

self.goal_state = (0, 4) # Position of the banana

def actions(self, state):

possible_actions = []

x, y = state

# The monkey can move in four directions: up, down,


left, right

if y > 0:

possible_actions.append("up")

if y < 4:

possible_actions.append("down")

if x > 0:
possible_actions.append("left")

if x < 4:

possible_actions.append("right")

return possible_actions

def result(self, state, action):

x, y = state

if action == "up":

return (x, y - 1)

elif action == "down":

return (x, y + 1)

elif action == "left":

return (x - 1, y)

elif action == "right":

return (x + 1, y)
def goal_test(self, state):

return state == self.goal_state

def solve(self):

frontier = [(self.initial_state, [])] # (state, actions)

explored = set()

while frontier:

state, actions = frontier.pop(0)

if self.goal_test(state):

return actions

explored.add(state)

for action in self.actions(state):

next_state = self.result(state, action)

if next_state not in explored:


frontier.append((next_state, actions + [action]))

return None

if __name__ == "__main__":

initial_state = (4, 0) # Initial position of the monkey

problem = MonkeyBananaProblem(initial_state)

solution = problem.solve()

if solution:

print("Sequence of actions to reach the banana:")

print(solution)

else:

print("No solution found.")


OUTPUT:

Q2. Solve the planning problem (Shakey's World). Refer page


397-398 of Russel, Norvig book for complete specification of
the problem.

CODE:
class Shakey:

def __init__(self, initial_room, initial_boxes):

self.room = initial_room

self.boxes = initial_boxes

def move(self, direction):

if direction == 'left':

if self.room[1] > 0:
self.room = (self.room[0], self.room[1] - 1)

print("Shakey moves left.")

else:

print("Cannot move left. Reached the edge of the


room.")

elif direction == 'right':

if self.room[1] < 4:

self.room = (self.room[0], self.room[1] + 1)

print("Shakey moves right.")

else:

print("Cannot move right. Reached the edge of the


room.")

elif direction == 'up':

if self.room[0] > 0:

self.room = (self.room[0] - 1, self.room[1])

print("Shakey moves up.")

else:
print("Cannot move up. Reached the edge of the
room.")

elif direction == 'down':

if self.room[0] < 2:

self.room = (self.room[0] + 1, self.room[1])

print("Shakey moves down.")

else:

print("Cannot move down. Reached the edge of the


room.")

else:

print("Invalid direction.")

def pick_box(self):

if self.room in self.boxes:

self.boxes.remove(self.room)

print("Shakey picks up a box at room", self.room)

else:

print("No box to pick up in the current room.")


def put_box(self):

if len(self.boxes) < 3:

self.boxes.append(self.room)

print("Shakey puts down a box at room", self.room)

else:

print("Cannot put down a box. Already carrying


maximum number of boxes.")

def goal_achieved(self, goal_room, goal_boxes):

if self.room == goal_room and set(self.boxes) ==


set(goal_boxes):

print("Goal achieved!")

return True

else:

print("Goal not achieved.")

return False
# Initial state

initial_room = (0, 0)

initial_boxes = [(0, 2), (2, 3)]

# Goal state

goal_room = (2, 4)

goal_boxes = [(1, 1), (1, 2), (1, 3)]

# Instantiate Shakey agent

shakey = Shakey(initial_room, initial_boxes)

# Actions to reach the goal

shakey.move('right')

shakey.move('right')

shakey.move('down')

shakey.pick_box()

shakey.move('up')

shakey.move('up')
shakey.move('up')

shakey.put_box()

shakey.move('right')

shakey.move('down')

shakey.move('down')

shakey.pick_box()

shakey.move('up')

shakey.move('up')

shakey.move('right')

shakey.put_box()

shakey.goal_achieved(goal_room, goal_boxes)

OUTPUT:
Q3. Develop the Decision Tree Classification model for a
given dataset and use it to classify a new sample.

CODE:

# Step 1: Import necessary libraries

from sklearn.model_selection import train_test_split

from sklearn.tree import DecisionTreeClassifier

from sklearn.metrics import accuracy_score

import pandas as pd

# Step 2: Load the dataset

# Replace 'your_dataset.csv' with the name of your dataset

data = pd.read_csv('your_dataset.csv')

# Step 3: Preprocess the data

# Assuming the last column is the target variable

X = data.iloc[:, :-1]

y = data.iloc[:, -1]
# Step 4: Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(X, y,


test_size=0.2, random_state=42)

# Step 5: Train the Decision Tree Classifier

clf = DecisionTreeClassifier()

clf.fit(X_train, y_train)

# Step 6: Evaluate the model

y_pred = clf.predict(X_test)

print("Accuracy:", accuracy_score(y_test, y_pred))

# Step 7: Classify a new sample

new_sample = [[value_1, value_2, ..., value_n]] # Replace


with your new sample

prediction = clf.predict(new_sample)

print("Prediction:", prediction[0])
OUTPUT:

Q4. Carry out the performance analysis of classification


algorithms on a specific dataset

• Decision Tree Classifier,

• Random Forest Classifier,

• XGBoost Classifier,

• Naïve Bayes,

CODE:
# Step 1: Import necessary libraries

import time

from sklearn.model_selection import train_test_split

from sklearn.tree import DecisionTreeClassifier


from sklearn.ensemble import RandomForestClassifier

from sklearn.ensemble import GradientBoostingClassifier as


XGBoostClassifier

from sklearn.naive_bayes import GaussianNB

from sklearn.metrics import accuracy_score,


classification_report, confusion_matrix

# Step 2: Load the dataset

# Replace 'your_dataset.csv' with the name of your dataset

data = pd.read_csv('your_dataset.csv')

# Step 3: Preprocess the data

# Assuming the last column is the target variable

X = data.iloc[:, :-1]

y = data.iloc[:, -1]

# Step 4: Split the data into training and testing sets


X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2, random_state=42)

# Step 5: Train and evaluate each classification algorithm

classifiers = [

('Decision Tree', DecisionTreeClassifier()),

('Random Forest', RandomForestClassifier()),

('XGBoost', XGBoostClassifier()),

('Naive Bayes', GaussianNB())

start_time = time.time()

for name, clf in classifiers:

clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)

print(f"\n{name} Accuracy: {accuracy_score(y_test,


y_pred)}")
print(f"{name} Classification
Report:\n{classification_report(y_test, y_pred)}\n")

print(f"{name} Confusion
Matrix:\n{confusion_matrix(y_test, y_pred)}\n")

print(f"Total time: {time.time() - start_time:.4f} seconds")

OUTPUT:

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy