Final AI LAB FILE
Final AI LAB FILE
Date:
Signature:
INDEX
for j in range(3):
check_column(j)
check_row(j)
check_diagonals(board[0][0],board[1][1],board[2][2])
check_diagonals(board[0][2],board[1][1],board[2][0])
if __name__=='__main__':
main()
OUTPUT
-l-l-
-l-l-
-l-l-
Enter a number:0
-l-l-
-l-l-
-l-lX
Enter a number:2
-lOl-
-l-l-
-l-lX
Enter a number:3
-lOlX
-l-l-
-l-lX
Enter a number:5
-lOlX
-lOl-
-l-lX
Enter a number:6
X won
-lOlX
-lOlX
-l-lX
OUTPUT
Following is the Breadth-First Search
5 3 7 2 4 8
OUTPUT
Following is the Depth-First Search
5
3
2
4
8
7
OUTPUT
nCurrent level--> 0
Goal node testing failed
nExpanding the current node A
nCurrent level--> 1
Goal node testing failed
nExpanding the current node B
nCurrent level--> 2
Goal node testing failed
nExpanding the current node D
nCurrent level--> 2
Goal node testing failed
nExpanding the current node E
nCurrent level--> 1
Goal node testing failed
nExpanding the current node C
nCurrent level--> 2
Goal node testing failed
nExpanding the current node F
nCurrent level--> 2
Goal node testing failed
nExpanding the current node G
No path available for the goal node in given depth limit
5. iterative deepening depth first search
graph = {
'A': ['B', 'C'],
'B': ['D','E'],
"C": ['G'],
'D': [],
'E': ['F'],
'G': [],
'F':[]
}
path = list()
def DFS(currentNode,destination,graph,maxDepth,curList):
print("Checking for destination",currentNode)
curList.append(currentNode)
if currentNode==destination:
return True
if maxDepth<=0:
path.append(curList)
return False
for node in graph[currentNode]:
if DFS(node,destination,graph,maxDepth-1,curList):
return True
else:
curList.pop()
return False
def iterativeDDFS(currentNode,destination,graph,maxDepth):
for i in range(maxDepth):
curList = list()
if DFS(currentNode,destination,graph,i,curList):
return True
return False
if not iterativeDDFS('A','E',graph,4):
print("Path is not available")
else:
print("A path exists")
print(path.pop())
OUTPUT
Checking for destination A
Checking for destination A
Checking for destination B
Checking for destination C
Checking for destination A
Checking for destination B
Checking for destination D
Checking for destination E
A path exists
['A', 'B', 'E']
OUTPUT
Minimum cost from 0 to 6 is = 3
7. Bidirectional Search
class adjacent_Node:
def __init__(self, v):
self.vertex = v
self.next = None
class bidirectional_Search:
def __init__(self, vertices):
self.vertices = vertices
self.graph = [None] * self.vertices
self.source_queue = list()
self.last_node_queue = list()
self.source_visited = [False] * self.vertices
self.last_node_visited = [False] * self.vertices
self.source_parent = [None] * self.vertices
self.last_node_parent = [None] * self.vertices
def AddEdge(self, source, last_node):
node = adjacent_Node(last_node)
node.next = self.graph[source]
self.graph[source] = node
node = adjacent_Node(source)
node.next = self.graph[last_node]
self.graph[last_node] = node
def breadth_fs(self, direction = 'forward'):
if direction == 'forward':
current = self.source_queue.pop(0)
connected_node = self.graph[current]
while connected_node:
vertex = connected_node.vertex
if not self.source_visited[vertex]:
self.source_queue.append(vertex)
self.source_visited[vertex] = True
self.source_parent[vertex] = current
connected_node = connected_node.next
else:
current = self.last_node_queue.pop(0)
connected_node = self.graph[current]
while connected_node:
vertex = connected_node.vertex
if not self.last_node_visited[vertex]:
self.last_node_queue.append(vertex)
self.last_node_visited[vertex] = True
self.last_node_parent[vertex] = current
connected_node = connected_node.next
def is_intersecting(self):
for i in range(self.vertices):
if (self.source_visited[i] and
self.last_node_visited[i]):
return i
return -1
def path_st(self, intersecting_node,
source, last_node):
path = list()
path.append(intersecting_node)
i = intersecting_node
while i != source:
path.append(self.source_parent[i])
i = self.source_parent[i]
path = path[::-1]
i = intersecting_node
while i != last_node:
path.append(self.last_node_parent[i])
i = self.last_node_parent[i]
print("*****Path*****")
path = list(map(str, path))
print(' '.join(path))
def bidirectional_search(self, source, last_node):
self.source_queue.append(source)
self.source_visited[source] = True
self.source_parent[source] = -1
self.last_node_queue.append(last_node)
self.last_node_visited[last_node] = True
self.last_node_parent[last_node] = -1
while self.source_queue and self.last_node_queue:
self.breadth_fs(direction = 'forward')
self.breadth_fs(direction = 'backward')
intersecting_node = self.is_intersecting()
if intersecting_node != -1:
print("Path exists between {} and {}".format(source,
last_node))
print("Intersection at : {}".format(intersecting_node))
self.path_st(intersecting_node, source, last_node)
exit(0)
return -1
if __name__ == '__main__':
n = 17
source = 1
last_node = 16
my_Graph = bidirectional_Search(n)
my_Graph.AddEdge(1, 4)
my_Graph.AddEdge(2, 4)
my_Graph.AddEdge(3, 6)
my_Graph.AddEdge(5, 6)
my_Graph.AddEdge(4, 8)
my_Graph.AddEdge(6, 8)
my_Graph.AddEdge(8, 9)
my_Graph.AddEdge(9, 10)
my_Graph.AddEdge(10, 11)
my_Graph.AddEdge(11, 13)
my_Graph.AddEdge(11, 14)
my_Graph.AddEdge(10, 12)
my_Graph.AddEdge(12, 15)
my_Graph.AddEdge(12, 16)
out = my_Graph.bidirectional_search(source, last_node)
if out == -1:
print("No path between {} and {}".format(source, last_node))
OUTPUT
Path exists between 1 and 16
Intersection at : 9
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 9
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 8
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 8
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 8
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 4
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 3
*****Path*****
1 4 8 6 3 6 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 1
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 1
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 1
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 1
*****Path*****
1 4 8 9 10 12 16
Path exists between 1 and 16
Intersection at : 1
*****Path*****
1 4 8 9 10 12 16
No path between 1 and 16
8. Greedy BFS
#Greedy BFS
from queue import PriorityQueue
# Filling adjacency matrix with empty arrays
vertices = 14
graph = [[] for i in range(vertices)]
# Function for adding edges to graph
def add_edge(x, y, cost):
graph[x].append((y, cost))
graph[y].append((x, cost))
# Function For Implementing Best First Search
# Gives output path having the lowest cost
def best_first_search(source, target, vertices):
visited = [0] * vertices
pq = PriorityQueue()
pq.put((0, source))
print("Path: ")
while not pq.empty():
u = pq.get()[1]
# Displaying the path having the lowest cost
print(u, end=" ")
if u == target:
break
for v, c in graph[u]:
if not visited[v]:
visited[v] = True
pq.put((c, v))
print()
if __name__ == '__main__':
# The nodes shown in above example(by alphabets) are
# implemented using integers add_edge(x,y,cost);
add_edge(0, 1, 1)
add_edge(0, 2, 8)
add_edge(1, 2, 12)
add_edge(1, 4, 13)
add_edge(2, 3, 6)
add_edge(4, 3, 3)
source = 0
target = 2
best_first_search(source, target, vertices)
OUTPUT
Path:
0 1 0 2
9. A* algoritm
# A* algorithm
def aStarAlgo(start_node, stop_node):
open_set = set(start_node)
closed_set = set()
g = {} #store distance from starting node
parents = {}# parents contains an adjacency map of all nodes
#ditance of starting node from itself is zero
g[start_node] = 0
#start_node is root node i.e it has no parent nodes
#so start_node is set to its own parent node
parents[start_node] = start_node
while len(open_set) > 0:
n = None
#node with lowest f() is found
for v in open_set:
if n == None or g[v] + heuristic(v) < g[n] + heuristic(n):
n = v
if n == stop_node or Graph_nodes[n] == None:
pass
else:
for (m, weight) in get_neighbors(n):
#nodes 'm' not in first and last set are added to first
#n is set its parent
if m not in open_set and m not in closed_set:
open_set.add(m)
parents[m] = n
g[m] = g[n] + weight
#for each node m,compare its distance from start i.e g(m) to
the
#from start through n node
else:
if g[m] > g[n] + weight:
#update g(m)
g[m] = g[n] + weight
#change parent of m to n
parents[m] = n
#if m in closed set,remove and add to open
if m in closed_set:
closed_set.remove(m)
open_set.add(m)
if n == None:
print('Path does not exist!')
return None
# if the current node is the stop_node
# then we begin reconstructin the path from it to the start_node
if n == stop_node:
path = []
while parents[n] != n:
path.append(n)
n = parents[n]
path.append(start_node)
path.reverse()
print('Path found: {}'.format(path))
return path
# remove n from the open_list, and add it to closed_list
# because all of his neighbors were inspected
open_set.remove(n)
closed_set.add(n)
print('Path does not exist!')
return None
#define fuction to return neighbor and its distance
#from the passed node
def get_neighbors(v):
if v in Graph_nodes:
return Graph_nodes[v]
else:
return None
#for simplicity we ll consider heuristic distances given
#and this function returns heuristic distance for all nodes
def heuristic(n):
H_dist = {
'A': 11,
'B': 6,
'C': 99,
'D': 1,
'E': 7,
'G': 0,
}
return H_dist[n]
#Describe your graph here
Graph_nodes = {
'A': [('B', 2), ('E', 3)],
'B': [('C', 1),('G', 9)],
'C': None,
'E': [('D', 6)],
'D': [('G', 1)],
}
aStarAlgo('A', 'G')
OUTPUT
Path found: ['A', 'E', 'D', 'G']
['A', 'E', 'D', 'G']
neighbours = []
dim = landscape.shape
# left neighbour
if state[0] != 0:
neighbours.append((state[0] - 1, state[1]))
# right neighbour
if state[0] != dim[0] - 1:
neighbours.append((state[0] + 1, state[1]))
# top neighbour
if state[1] != 0:
neighbours.append((state[0], state[1] - 1))
# bottom neighbour
if state[1] != dim[1] - 1:
neighbours.append((state[0], state[1] + 1))
# top left
if state[0] != 0 and state[1] != 0:
neighbours.append((state[0] - 1, state[1] - 1))
# bottom left
if state[0] != 0 and state[1] != dim[1] - 1:
neighbours.append((state[0] - 1, state[1] + 1))
# top right
if state[0] != dim[0] - 1 and state[1] != 0:
neighbours.append((state[0] + 1, state[1] - 1))
# bottom right
if state[0] != dim[0] - 1 and state[1] != dim[1] - 1:
neighbours.append((state[0] + 1, state[1] + 1))
return neighbours
# Current optimization objective: local/global maximum
def hill_climb(curr_state, landscape):
neighbours = find_neighbours(curr_state, landscape)
bool
ascended = False
next_state = curr_state
for neighbour in neighbours: #Find the neighbour with the greatest value
if landscape[neighbour[0]][neighbour[1]] > landscape[next_state[0]]
[next_state[1]]:
next_state = neighbour
ascended = True
return ascended, next_state
def __main__():
landscape = np.random.randint(1, high=50, size=(10, 10))
print(landscape)
start_state = (3, 6) # matrix index coordinates
current_state = start_state
count = 1
ascending = True
while ascending:
print("\nStep #", count)
print("Current state coordinates: ", current_state)
print("Current state value: ", landscape[current_state[0]]
[current_state[1]])
count += 1
ascending, current_state = hill_climb(current_state, landscape)
print("\nStep #", count)
print("Optimization objective reached.")
print("Final state coordinates: ", current_state)
print("Final state value: ", landscape[current_state[0]][current_state[1]])
__main__()
OUTPUT
[[ 8 4 34 38 12 40 38 26 42 34]
[46 26 46 14 34 14 4 29 46 41]
[44 41 15 32 37 39 23 7 20 11]
[15 46 40 38 25 14 48 10 8 48]
[29 21 1 26 35 44 35 44 49 29]
[10 16 24 3 38 12 47 6 23 42]
[35 21 6 4 4 36 45 4 49 7]
[22 37 49 16 26 26 39 11 44 42]
[30 21 2 13 16 41 28 14 40 48]
[22 46 20 12 20 14 40 6 23 23]]
Step # 1
Current state coordinates: (3, 6)
Current state value: 48
Step # 2
Optimization objective reached.
Final state coordinates: (3, 6)
Final state value: 48