0% found this document useful (0 votes)
11 views33 pages

Ai Lab PDF

The document contains multiple Python implementations of various algorithms, including BFS, DFS, the 8-puzzle problem, the water jug problem, the traveling salesman problem (TSP), Tower of Hanoi, and Alpha-Beta pruning. Each section provides code snippets that demonstrate how to implement these algorithms effectively. The document serves as a reference for understanding and applying these algorithms in programming.

Uploaded by

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

Ai Lab PDF

The document contains multiple Python implementations of various algorithms, including BFS, DFS, the 8-puzzle problem, the water jug problem, the traveling salesman problem (TSP), Tower of Hanoi, and Alpha-Beta pruning. Each section provides code snippets that demonstrate how to implement these algorithms effectively. The document serves as a reference for understanding and applying these algorithms in programming.

Uploaded by

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

1] BFS

# 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 not visited[i]:

queue.append(i)
visited[i] = True

# Driver code

if __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)
2]DFS

def dfs_rec(adj, visited, s):

# Mark the current vertex as visited

visited[s] = True

# Print the current vertex

print(s, end=" ")

# Recursively visit all adjacent vertices

# that are not visited yet

for i in adj[s]:

if not visited[i]:

dfs_rec(adj, visited, i)

def dfs(adj, s):

visited = [False] * len(adj)

# Call the recursive DFS function

dfs_rec(adj, visited, s)

def add_edge(adj, s, t):

# Add edge from vertex s to t

adj[s].append(t)

# Due to undirected Graph

adj[t].append(s)
if __name__ == "__main__":

V=5

# Create an adjacency list for the graph

adj = [[] for _ in range(V)]

# Define the edges of the graph

edges = [[1, 2], [1, 0], [2, 0], [2, 3], [2, 4]]

# Populate the adjacency list with edges

for e in edges:

add_edge(adj, e[0], e[1])

source = 1

print("DFS from source:", source)

dfs(adj, source)

3]TTT

def dfs_rec(adj, visited, s):

# Mark the current vertex as visited

visited[s] = True
# Print the current vertex

print(s, end=" ")

# Recursively visit all adjacent vertices

# that are not visited yet

for i in adj[s]:

if not visited[i]:

dfs_rec(adj, visited, i)

def dfs(adj, s):

visited = [False] * len(adj)

# Call the recursive DFS function

dfs_rec(adj, visited, s)

def add_edge(adj, s, t):

# Add edge from vertex s to t

adj[s].append(t)

# Due to undirected Graph

adj[t].append(s)

if __name__ == "__main__":

V=5

# Create an adjacency list for the graph


adj = [[] for _ in range(V)]

# Define the edges of the graph

edges = [[1, 2], [1, 0], [2, 0], [2, 3], [2, 4]]

# Populate the adjacency list with edges

for e in edges:

add_edge(adj, e[0], e[1])

source = 1

print("DFS from source:", source)

dfs(adj, source)

4] 8 puzzle

# Python code to display the way from the root

# node to the final destination node for N*N-1 puzzle

# algorithm by the help of Branch and Bound technique

# The answer assumes that the instance of the

# puzzle can be solved

# Importing the 'copy' for deepcopy method

import copy
# Importing the heap methods from the python

# library for the Priority Queue

from heapq import heappush, heappop

# This particular var can be changed to transform

# the program from 8 puzzle(n=3) into 15

# puzzle(n=4) and so on ...

n=3

# bottom, left, top, right

rows = [ 1, 0, -1, 0 ]

cols = [ 0, -1, 0, 1 ]

# creating a class for the Priority Queue

class priorityQueue:

# Constructor for initializing a

# Priority Queue

def __init__(self):

self.heap = []

# Inserting a new key 'key'

def push(self, key):

heappush(self.heap, key)
# funct to remove the element that is minimum,

# from the Priority Queue

def pop(self):

return heappop(self.heap)

# funct to check if the Queue is empty or not

def empty(self):

if not self.heap:

return True

else:

return False

# structure of the node

class nodes:

def __init__(self, parent, mats, empty_tile_posi,

costs, levels):

# This will store the parent node to the

# current node And helps in tracing the

# path when the solution is visible

self.parent = parent

# Useful for Storing the matrix

self.mats = mats
# useful for Storing the position where the

# empty space tile is already existing in the matrix

self.empty_tile_posi = empty_tile_posi

# Store no. of misplaced tiles

self.costs = costs

# Store no. of moves so far

self.levels = levels

# This func is used in order to form the

# priority queue based on

# the costs var of objects

def __lt__(self, nxt):

return self.costs < nxt.costs

# method to calc. the no. of

# misplaced tiles, that is the no. of non-blank

# tiles not in their final posi

def calculateCosts(mats, final) -> int:

count = 0

for i in range(n):

for j in range(n):
if ((mats[i][j]) and

(mats[i][j] != final[i][j])):

count += 1

return count

def newNodes(mats, empty_tile_posi, new_empty_tile_posi,

levels, parent, final) -> nodes:

# Copying data from the parent matrixes to the present matrixes

new_mats = copy.deepcopy(mats)

# Moving the tile by 1 position

x1 = empty_tile_posi[0]

y1 = empty_tile_posi[1]

x2 = new_empty_tile_posi[0]

y2 = new_empty_tile_posi[1]

new_mats[x1][y1], new_mats[x2][y2] = new_mats[x2][y2], new_mats[x1][y1]

# Setting the no. of misplaced tiles

costs = calculateCosts(new_mats, final)

new_nodes = nodes(parent, new_mats, new_empty_tile_posi,

costs, levels)

return new_nodes
# func to print the N by N matrix

def printMatsrix(mats):

for i in range(n):

for j in range(n):

print("%d " % (mats[i][j]), end = " ")

print()

# func to know if (x, y) is a valid or invalid

# matrix coordinates

def isSafe(x, y):

return x >= 0 and x < n and y >= 0 and y < n

# Printing the path from the root node to the final node

def printPath(root):

if root == None:

return

printPath(root.parent)

printMatsrix(root.mats)

print()
# method for solving N*N - 1 puzzle algo

# by utilizing the Branch and Bound technique. empty_tile_posi is

# the blank tile position initially.

def solve(initial, empty_tile_posi, final):

# Creating a priority queue for storing the live

# nodes of the search tree

pq = priorityQueue()

# Creating the root node

costs = calculateCosts(initial, final)

root = nodes(None, initial,

empty_tile_posi, costs, 0)

# Adding root to the list of live nodes

pq.push(root)

# Discovering a live node with min. costs,

# and adding its children to the list of live

# nodes and finally deleting it from

# the list.

while not pq.empty():

# Finding a live node with min. estimatsed


# costs and deleting it form the list of the

# live nodes

minimum = pq.pop()

# If the min. is ans node

if minimum.costs == 0:

# Printing the path from the root to

# destination;

printPath(minimum)

return

# Generating all feasible children

for i in range(n):

new_tile_posi = [

minimum.empty_tile_posi[0] + rows[i],

minimum.empty_tile_posi[1] + cols[i], ]

if isSafe(new_tile_posi[0], new_tile_posi[1]):

# Creating a child node

child = newNodes(minimum.mats,

minimum.empty_tile_posi,

new_tile_posi,

minimum.levels + 1,
minimum, final,)

# Adding the child to the list of live nodes

pq.push(child)

# Main Code

# Initial configuration

# Value 0 is taken here as an empty space

initial = [ [ 1, 2, 3 ],

[ 5, 6, 0 ],

[ 7, 8, 4 ] ]

# Final configuration that can be solved

# Value 0 is taken as an empty space

final = [ [ 1, 2, 3 ],

[ 5, 8, 6 ],

[ 0, 7, 4 ] ]

# Blank tile coordinates in the

# initial configuration

empty_tile_posi = [ 1, 2 ]

# Method call for solving the puzzle

solve(initial, empty_tile_posi, final)


5]WATER-JUG

from collections import deque

def Solution(a, b, target):

m = {}

isSolvable = False

path = []

q = deque()

#Initializing with jugs being empty

q.append((0, 0))

while (len(q) > 0):

# Current state

u = q.popleft()

if ((u[0], u[1]) in m):

continue

if ((u[0] > a or u[1] > b or

u[0] < 0 or u[1] < 0)):

continue
path.append([u[0], u[1]])

m[(u[0], u[1])] = 1

if (u[0] == target or u[1] == target):

isSolvable = True

if (u[0] == target):

if (u[1] != 0):

path.append([u[0], 0])

else:

if (u[0] != 0):

path.append([0, u[1]])

sz = len(path)

for i in range(sz):

print("(", path[i][0], ",",

path[i][1], ")")

break

q.append([u[0], b]) # Fill Jug2

q.append([a, u[1]]) # Fill Jug1

for ap in range(max(a, b) + 1):


c = u[0] + ap

d = u[1] - ap

if (c == a or (d == 0 and d >= 0)):

q.append([c, d])

c = u[0] - ap

d = u[1] + ap

if ((c == 0 and c >= 0) or d == b):

q.append([c, d])

q.append([a, 0])

q.append([0, b])

if (not isSolvable):

print("Solution not possible")

if __name__ == '__main__':

Jug1, Jug2, target = 4, 3, 2

print("Path from initial state "

"to solution state ::")

Solution(Jug1, Jug2, target)


6]TSP

# Python program to find the shortest possible route

# that visits every city exactly once and returns to

# the starting point

from itertools import permutations

def tsp(cost):

# Number of nodes

numNodes = len(cost)

nodes = list(range(1, numNodes))

minCost = float('inf')

# Generate all permutations of the

# remaining nodes

for perm in permutations(nodes):

currCost = 0

currNode = 0

# Calculate the cost of the current permutation

for node in perm:

currCost += cost[currNode][node]

currNode = node
# Add the cost to return to the starting node

currCost += cost[currNode][0]

# Update the minimum cost if the current cost

# is lower

minCost = min(minCost, currCost)

return minCost

if __name__ == "__main__":

cost = [

[0, 10, 15, 20],

[10, 0, 35, 25],

[15, 35, 0, 30],

[20, 25, 30, 0]

res = tsp(cost)

print(res)
7]TOH

# Recursive Python function to solve the tower of hanoi

def TowerOfHanoi(n , source, destination, auxiliary):

if n==1:

print ("Move disk 1 from source",source,"to destination",destination)

return

TowerOfHanoi(n-1, source, auxiliary, destination)

print ("Move disk",n,"from source",source,"to destination",destination)

TowerOfHanoi(n-1, auxiliary, destination, source)

# Driver code

n=4

TowerOfHanoi(n,'A','B','C')

# A, C, B are the name of rods

# Contributed By Dilip Jain


8.MONKEY BANANA

9.AIPHA-BETA

# Python3 program to demonstrate

# working of Alpha-Beta Pruning

# Initial values of Alpha and Beta

MAX, MIN = 1000, -1000

# Returns optimal value for current player

#(Initially called for root and maximizer)

def minimax(depth, nodeIndex, maximizingPlayer,

values, alpha, beta):

# Terminating condition. i.e

# leaf node is reached

if depth == 3:

return values[nodeIndex]

if maximizingPlayer:

best = MIN
# Recur for left and right children

for i in range(0, 2):

val = minimax(depth + 1, nodeIndex * 2 + i,

False, values, alpha, beta)

best = max(best, val)

alpha = max(alpha, best)

# Alpha Beta Pruning

if beta <= alpha:

break

return best

else:

best = MAX

# Recur for left and

# right children

for i in range(0, 2):

val = minimax(depth + 1, nodeIndex * 2 + i,

True, values, alpha, beta)

best = min(best, val)

beta = min(beta, best)


# Alpha Beta Pruning

if beta <= alpha:

break

return best

# Driver Code

if __name__ == "__main__":

values = [3, 5, 6, 9, 1, 2, 0, -1]

print("The optimal value is :", minimax(0, 0, True, values, MIN, MAX))

# This code is contributed by Rituraj Jain


10]8-queens

# Python code to display the way from the root

# node to the final destination node for N*N-1 puzzle

# algorithm by the help of Branch and Bound technique

# The answer assumes that the instance of the

# puzzle can be solved

# Importing the 'copy' for deepcopy method

import copy

# Importing the heap methods from the python

# library for the Priority Queue

from heapq import heappush, heappop

# This particular var can be changed to transform

# the program from 8 puzzle(n=3) into 15

# puzzle(n=4) and so on ...

n=3

# bottom, left, top, right

rows = [ 1, 0, -1, 0 ]

cols = [ 0, -1, 0, 1 ]

# creating a class for the Priority Queue

class priorityQueue:
# Constructor for initializing a

# Priority Queue

def __init__(self):

self.heap = []

# Inserting a new key 'key'

def push(self, key):

heappush(self.heap, key)

# funct to remove the element that is minimum,

# from the Priority Queue

def pop(self):

return heappop(self.heap)

# funct to check if the Queue is empty or not

def empty(self):

if not self.heap:

return True

else:

return False

# structure of the node

class nodes:
def __init__(self, parent, mats, empty_tile_posi,

costs, levels):

# This will store the parent node to the

# current node And helps in tracing the

# path when the solution is visible

self.parent = parent

# Useful for Storing the matrix

self.mats = mats

# useful for Storing the position where the

# empty space tile is already existing in the matrix

self.empty_tile_posi = empty_tile_posi

# Store no. of misplaced tiles

self.costs = costs

# Store no. of moves so far

self.levels = levels

# This func is used in order to form the

# priority queue based on

# the costs var of objects

def __lt__(self, nxt):


return self.costs < nxt.costs

# method to calc. the no. of

# misplaced tiles, that is the no. of non-blank

# tiles not in their final posi

def calculateCosts(mats, final) -> int:

count = 0

for i in range(n):

for j in range(n):

if ((mats[i][j]) and

(mats[i][j] != final[i][j])):

count += 1

return count

def newNodes(mats, empty_tile_posi, new_empty_tile_posi,

levels, parent, final) -> nodes:

# Copying data from the parent matrixes to the present matrixes

new_mats = copy.deepcopy(mats)

# Moving the tile by 1 position

x1 = empty_tile_posi[0]

y1 = empty_tile_posi[1]
x2 = new_empty_tile_posi[0]

y2 = new_empty_tile_posi[1]

new_mats[x1][y1], new_mats[x2][y2] = new_mats[x2][y2], new_mats[x1][y1]

# Setting the no. of misplaced tiles

costs = calculateCosts(new_mats, final)

new_nodes = nodes(parent, new_mats, new_empty_tile_posi,

costs, levels)

return new_nodes

# func to print the N by N matrix

def printMatsrix(mats):

for i in range(n):

for j in range(n):

print("%d " % (mats[i][j]), end = " ")

print()

# func to know if (x, y) is a valid or invalid

# matrix coordinates

def isSafe(x, y):

return x >= 0 and x < n and y >= 0 and y < n


# Printing the path from the root node to the final node

def printPath(root):

if root == None:

return

printPath(root.parent)

printMatsrix(root.mats)

print()

# method for solving N*N - 1 puzzle algo

# by utilizing the Branch and Bound technique. empty_tile_posi is

# the blank tile position initially.

def solve(initial, empty_tile_posi, final):

# Creating a priority queue for storing the live

# nodes of the search tree

pq = priorityQueue()

# Creating the root node

costs = calculateCosts(initial, final)

root = nodes(None, initial,

empty_tile_posi, costs, 0)
# Adding root to the list of live nodes

pq.push(root)

# Discovering a live node with min. costs,

# and adding its children to the list of live

# nodes and finally deleting it from

# the list.

while not pq.empty():

# Finding a live node with min. estimatsed

# costs and deleting it form the list of the

# live nodes

minimum = pq.pop()

# If the min. is ans node

if minimum.costs == 0:

# Printing the path from the root to

# destination;

printPath(minimum)

return

# Generating all feasible children

for i in range(n):

new_tile_posi = [
minimum.empty_tile_posi[0] + rows[i],

minimum.empty_tile_posi[1] + cols[i], ]

if isSafe(new_tile_posi[0], new_tile_posi[1]):

# Creating a child node

child = newNodes(minimum.mats,

minimum.empty_tile_posi,

new_tile_posi,

minimum.levels + 1,

minimum, final,)

# Adding the child to the list of live nodes

pq.push(child)

# Main Code

# Initial configuration

# Value 0 is taken here as an empty space

initial = [ [ 1, 2, 3 ],

[ 5, 6, 0 ],

[ 7, 8, 4 ] ]

# Final configuration that can be solved

# Value 0 is taken as an empty space


final = [ [ 1, 2, 3 ],

[ 5, 8, 6 ],

[ 0, 7, 4 ] ]

# Blank tile coordinates in the

# initial configuration

empty_tile_posi = [ 1, 2 ]

# Method call for solving the puzzle

solve(initial, empty_tile_posi, final)

You might also like