0% found this document useful (0 votes)
160 views28 pages

Ai File

Breadth First Search (BFS) is an algorithm that explores all neighbor nodes of the root node first before moving to the next level neighbors. It uses a queue to keep track of nodes to be visited at each level. Depth First Search (DFS) explores as far as possible along each branch before backtracking. It uses a stack to keep track of nodes. The N Queen problem places N queens on a N*N chessboard such that no two queens attack each other. It is solved using backtracking. The Water Jug problem checks if a given quantity can be measured using fixed capacity jugs. It uses the GCD approach. The 8 Puzzle problem finds the shortest path to rearrange tiles in a 3

Uploaded by

dhruv kumar
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)
160 views28 pages

Ai File

Breadth First Search (BFS) is an algorithm that explores all neighbor nodes of the root node first before moving to the next level neighbors. It uses a queue to keep track of nodes to be visited at each level. Depth First Search (DFS) explores as far as possible along each branch before backtracking. It uses a stack to keep track of nodes. The N Queen problem places N queens on a N*N chessboard such that no two queens attack each other. It is solved using backtracking. The Water Jug problem checks if a given quantity can be measured using fixed capacity jugs. It uses the GCD approach. The 8 Puzzle problem finds the shortest path to rearrange tiles in a 3

Uploaded by

dhruv kumar
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/ 28

Breadth First Search

In [1]:
graph = {

'5' : ['3','7'],

'3' : ['2', '4'],

'7' : ['8'],

'2' : [],

'4' : ['8'],

'8' : []

visited = [] # List for visited nodes.

queue = [] #Initialize a queue

def bfs(visited, graph, node): #function for BFS

visited.append(node)

queue.append(node)

while queue: # Creating loop to visit each node

m = queue.pop(0)

print (m, end = " ")

for neighbour in graph[m]:

if neighbour not in visited:

visited.append(neighbour)
queue.append(neighbour)

# Driver Code

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

bfs(visited, graph, '5') # function calling

Following is the Breadth-First Search

5 3 7 2 4 8

Depth First Search


In [2]:
# Using a Python dictionary to act as an adjacency list

graph = {

'5' : ['3','7'],

'3' : ['2', '4'],

'7' : ['8'],

'2' : [],

'4' : ['8'],

'8' : []

visited = set() # Set to keep track of visited nodes of graph.

def dfs(visited, graph, node): #function for dfs

if node not in visited:

print (node)

visited.add(node)

for neighbour in graph[node]:

dfs(visited, graph, neighbour)

# Driver Code

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

dfs(visited, graph, '5')

Following is the Depth-First Search

N Queen Problem
In [3]:
# Python program to solve N Queen

# Problem using backtracking

global N

N = 4

def printSolution(board):

for i in range(N):

for j in range(N):

print (board[i][j],end=' ')

print()

# A utility function to check if a queen can

# be placed on board[row][col]. Note that this

# function is called when "col" queens are

# already placed in columns from 0 to col -1.

# So we need to check only left side for

# attacking queens

def isSafe(board, row, col):

# 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 solveNQUtil(board, col):

# base case: If all queens are placed

# then return true


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 isSafe(board, i, col):

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

board[i][col] = 1

# recur to place rest of the queens

if solveNQUtil(board, col + 1) == True:

return True

# If placing queen in board[i][col

# doesn't lead to a solution, then

# queen from board[i][col]

board[i][col] = 0

# if the queen can not be placed in any row in

# this column col then return false

return False

# This function solves the N Queen problem using

# Backtracking. It mainly uses solveNQUtil() to

# solve the problem. It returns false if queens

# cannot be placed, otherwise return true and

# placement of queens in the form of 1s.

# note that there may be more than one

# solutions, this function prints one of the

# feasible solutions.

def solveNQ():

board = [ [0, 0, 0, 0],

[0, 0, 0, 0],

[0, 0, 0, 0],

[0, 0, 0, 0]

if solveNQUtil(board, 0) == False:

print ("Solution does not exist")

return False

printSolution(board)

return True

# driver program to test above function

solveNQ()

# This code is contributed by Divyanshu Mehta

0 0 1 0

1 0 0 0

0 0 0 1

0 1 0 0

True
Out[3]:

Water Jug Problem


In [3]:
x = 4

y = 3

z = 2

def gcd(a, b):

if(b == 0):

return a

return gcd(b, a % b)

def waterJug(x, y, z):

if(x + y < z):

return False

if(x == 0 and y == 0):

if(z == 0):

return True

else:

return False

if(z % gcd(x, y) == 0):

return True

else:

return False

In [4]:
from collections import deque

def BFS(a, b, target):

m = {}

isSolvable = False

path = []

# Queue to maintain states

q = deque()

# Initialing with initial state

q.append((0, 0))

while (len(q) > 0):

# Current state

u = q.popleft()

#q.pop() #pop off used state

# If this state is already visited

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

continue

# Doesn't met jug constraints

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

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

continue

# Filling the vector for constructing

# the solution path

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

# Marking current state as visited

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

# If we reach solution state, put ans=1

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

isSolvable = True

if (u[0] == target):

if (u[1] != 0):

# Fill final state

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

else:

if (u[0] != 0):

# Fill final state

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

# Print the solution path

sz = len(path)

for i in range(sz):

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

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

# If we have not reached final state

# then, start developing intermediate

# states to reach solution state

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

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

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

# Pour amount ap from Jug2 to Jug1

c = u[0] + ap

d = u[1] - ap

# Check if this state is possible or not

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

q.append([c, d])

# Pour amount ap from Jug 1 to Jug2

c = u[0] - ap

d = u[1] + ap

# Check if this state is possible or not

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

q.append([c, d])

# Empty Jug2

q.append([a, 0])

# Empty Jug1

q.append([0, b])

# No, solution exists if ans=0

if (not isSolvable):

print ("No solution")

# Driver code

if __name__ == '__main__':

Jug1, Jug2, target = 4, 3, 2

print("Path from initial state "

"to solution state ::")

BFS(Jug1, Jug2, target)

Path from initial state to solution state ::

( 0 , 0 )

( 0 , 3 )

( 4 , 0 )

( 4 , 3 )

( 3 , 0 )

( 1 , 3 )

( 3 , 3 )

( 4 , 2 )

( 0 , 2 )

8 Puzzle Problem
In [4]:
# Python3 program to print the path from root

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

# algorithm using Branch and Bound

# The solution assumes that instance of

# puzzle is solvable

# Importing copy for deepcopy function

import copy

# Importing the heap functions from python

# library for Priority Queue

from heapq import heappush, heappop

# This variable can be changed to change

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

# puzzle(n=4) to 24 puzzle(n=5)...

n = 3

# bottom, left, top, right

row = [ 1, 0, -1, 0 ]

col = [ 0, -1, 0, 1 ]

# A class for Priority Queue

class priorityQueue:

# Constructor to initialize a

# Priority Queue

def __init__(self):

self.heap = []

# Inserts a new key 'k'

def push(self, k):

heappush(self.heap, k)

# Method to remove minimum element

# from Priority Queue

def pop(self):

return heappop(self.heap)

# Method to know if the Queue is empty

def empty(self):

if not self.heap:

return True

else:

return False

# Node structure

class node:

def __init__(self, parent, mat, empty_tile_pos,

cost, level):

# Stores the parent node of the

# current node helps in tracing

# path when the answer is found

self.parent = parent

# Stores the matrix

self.mat = mat

# Stores the position at which the

# empty space tile exists in the matrix

self.empty_tile_pos = empty_tile_pos

# Storesthe number of misplaced tiles


self.cost = cost

# Stores the number of moves so far

self.level = level

# This method is defined so that the

# priority queue is formed based on

# the cost variable of the objects

def __lt__(self, nxt):

return self.cost < nxt.cost

# Function to calculate the number of

# misplaced tiles ie. number of non-blank

# tiles not in their goal position

def calculateCost(mat, final) -> int:

count = 0

for i in range(n):

for j in range(n):

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

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

count += 1

return count

def newNode(mat, empty_tile_pos, new_empty_tile_pos,

level, parent, final) -> node:

# Copy data from parent matrix to current matrix

new_mat = copy.deepcopy(mat)

# Move tile by 1 position

x1 = empty_tile_pos[0]

y1 = empty_tile_pos[1]

x2 = new_empty_tile_pos[0]

y2 = new_empty_tile_pos[1]

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

# Set number of misplaced tiles

cost = calculateCost(new_mat, final)

new_node = node(parent, new_mat, new_empty_tile_pos,

cost, level)

return new_node

# Function to print the N x N matrix

def printMatrix(mat):

for i in range(n):

for j in range(n):

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

print()

# Function to check if (x, y) is a valid

# matrix coordinate

def isSafe(x, y):

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

# Print path from root node to destination node

def printPath(root):

if root == None:

return

printPath(root.parent)

printMatrix(root.mat)

print()

# Function to solve N*N - 1 puzzle algorithm

# using Branch and Bound. empty_tile_pos is

# the blank tile position in the initial state.

def solve(initial, empty_tile_pos, final):

# Create a priority queue to store live

# nodes of search tree

pq = priorityQueue()

# Create the root node

cost = calculateCost(initial, final)

root = node(None, initial,

empty_tile_pos, cost, 0)

# Add root to list of live nodes

pq.push(root)

# Finds a live node with least cost,

# add its children to list of live

# nodes and finally deletes it from

# the list.

while not pq.empty():

# Find a live node with least estimated

# cost and delete it form the list of


# live nodes

minimum = pq.pop()

# If minimum is the answer node

if minimum.cost == 0:

# Print the path from root to

# destination;

printPath(minimum)

return

# Generate all possible children

for i in range(n):

new_tile_pos = [

minimum.empty_tile_pos[0] + row[i],

minimum.empty_tile_pos[1] + col[i], ]

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

# Create a child node


child = newNode(minimum.mat,

minimum.empty_tile_p
new_tile_pos,

minimum.level + 1,

minimum, final,)

# Add child to list of live nodes

pq.push(child)

# Driver Code

# Initial configuration

# Value 0 is used for empty space

initial = [ [ 1, 2, 3 ],

[ 5, 6, 0 ],

[ 7, 8, 4 ] ]

# Solvable Final configuration

# Value 0 is used for empty space

final = [ [ 1, 2, 3 ],

[ 5, 8, 6 ],

[ 0, 7, 4 ] ]

# Blank tile coordinates in

# initial configuration

empty_tile_pos = [ 1, 2 ]

# Function call to solve the puzzle

solve(initial, empty_tile_pos, final)

# This code is contributed by Kevin Joshi

1 2 3

5 6 0

7 8 4

1 2 3

5 0 6

7 8 4

1 2 3

5 8 6

7 0 4

1 2 3

5 8 6

0 7 4

MinMax Algo Tic tac toe


In [2]:
def printBoard(board):

print(board[1] + '|' + board[2] + '|' + board[3])

print('-+-+-')

print(board[4] + '|' + board[5] + '|' + board[6])

print('-+-+-')

print(board[7] + '|' + board[8] + '|' + board[9])

print("\n")

def spaceIsFree(position):

if board[position] == ' ':

return True

else:

return False

def insertLetter(letter, position):

if spaceIsFree(position):

board[position] = letter

printBoard(board)

if (checkDraw()):

print("Draw!")
print("No. of moves ",n )

exit()

if checkForWin():

if letter == 'X':

print("You win!")

print("No. of moves ",n )

exit()

else:

print("Bot wins!")

print("No. of moves ",n )

exit()

return

else:

print("Can't insert there!")

position = int(input("Please enter new position: "))

insertLetter(letter, position)

return

def checkForWin():

if (board[1] == board[2] and board[1] == board[3] and board[1] != ' '):

return True

elif (board[4] == board[5] and board[4] == board[6] and board[4] != ' '):

return True

elif (board[7] == board[8] and board[7] == board[9] and board[7] != ' '):

return True

elif (board[1] == board[4] and board[1] == board[7] and board[1] != ' '):

return True

elif (board[2] == board[5] and board[2] == board[8] and board[2] != ' '):

return True

elif (board[3] == board[6] and board[3] == board[9] and board[3] != ' '):

return True

elif (board[1] == board[5] and board[1] == board[9] and board[1] != ' '):

return True

elif (board[7] == board[5] and board[7] == board[3] and board[7] != ' '):

return True

else:

return False

def checkWhichMarkWon(mark):

if board[1] == board[2] and board[1] == board[3] and board[1] == mark:

return True

elif (board[4] == board[5] and board[4] == board[6] and board[4] == mark):

return True

elif (board[7] == board[8] and board[7] == board[9] and board[7] == mark):

return True

elif (board[1] == board[4] and board[1] == board[7] and board[1] == mark):

return True

elif (board[2] == board[5] and board[2] == board[8] and board[2] == mark):

return True

elif (board[3] == board[6] and board[3] == board[9] and board[3] == mark):

return True

elif (board[1] == board[5] and board[1] == board[9] and board[1] == mark):

return True

elif (board[7] == board[5] and board[7] == board[3] and board[7] == mark):

return True

else:

return False

def checkDraw():

for key in board.keys():

if (board[key] == ' '):

return False

return True

def playerMove():

position = int(input("Enter the position for 'X': "))

insertLetter(player, position)

return

def compMove():

bestScore = -800

bestMove = 0

for key in board.keys():

if (board[key] == ' '):

board[key] = bot

score = minimax(board, 0, False)

board[key] = ' '

if (score > bestScore):

bestScore = score

bestMove = key

insertLetter(bot, bestMove)

return

def minimax(board, depth, isMaximizing):

if (checkWhichMarkWon(bot)):

return 1

elif (checkWhichMarkWon(player)):

return -1

elif (checkDraw()):

return 0

if (isMaximizing):

bestScore = -800

for key in board.keys():

if (board[key] == ' '):

board[key] = bot

score = minimax(board, depth + 1, False)

board[key] = ' '

if (score > bestScore):

bestScore = score

return bestScore

else:

bestScore = 800

for key in board.keys():

if (board[key] == ' '):

board[key] = player

score = minimax(board, depth + 1, True)

board[key] = ' '

if (score < bestScore):

bestScore = score

return bestScore

board = {1: ' ', 2: ' ', 3: ' ',

4: ' ', 5: ' ', 6: ' ',

7: ' ', 8: ' ', 9: ' '}

printBoard(board)

print("You go first! Don't worry you will not lose provided you use your brain ")

print("Positions are as follow:")

print("1, 2, 3 ")

print("4, 5, 6 ")

print("7, 8, 9 ")

print("\n")

player = 'X'

bot = 'O'

n=0

while not checkForWin():

n=n+1

playerMove()

n=n+1

compMove()

| |

-+-+-

| |

-+-+-

| |

You go first! Don't worry you will not lose provided you use your brain

Positions are as follow:

1, 2, 3

4, 5, 6

7, 8, 9

Enter the position for 'X': 1

X| |

-+-+-

| |

-+-+-

| |

X| |

-+-+-

|O|

-+-+-

| |

Enter the position for 'X': 4

X| |

-+-+-

X|O|

-+-+-

| |

X| |

-+-+-

X|O|

-+-+-

O| |

Enter the position for 'X': 3

X| |X

-+-+-

X|O|

-+-+-

O| |

X|O|X

-+-+-

X|O|

-+-+-

O| |

Enter the position for 'X': 9

X|O|X

-+-+-

X|O|

-+-+-

O| |X

X|O|X

-+-+-

X|O|

-+-+-

O|O|X

Bot wins!

No. of moves 8

Iterative Deepening Search


In [2]:
def iterative_deepening_dfs(start, target):

# Start by doing DFS with a depth of 1, keep doubling depth until we reach the "
depth = 1

bottom_reached = False # Variable to keep track if we have reached the bottom o


while not bottom_reached:

# One of the "end nodes" of the search with this depth has to still have chi
result, bottom_reached = iterative_deepening_dfs_rec(start, target, 0, depth
if result is not None:

# We've found the goal node while doing DFS with this max depth

return result

# We haven't found the goal node, but there are still deeper nodes to search
depth *= 2

print("Increasing depth to " + str(depth))

# Bottom reached is True.

# We haven't found the node and there were no more nodes that still have childre
return None

def iterative_deepening_dfs_rec(node, target, current_depth, max_depth):

print("Visiting Node " + str(node["value"]))

if node["value"] == target:

# We have found the goal node we we're searching for

print("Found the node we're looking for!")

return node, True

if current_depth == max_depth:

print("Current maximum depth reached, returning...")


# We have reached the end for this depth...

if len(node["children"]) > 0:

# ...but we have not yet reached the bottom of the tree

return None, False

else:

return None, True

# Recurse with all children

bottom_reached = True

for i in range(len(node["children"])):

result, bottom_reached_rec = iterative_deepening_dfs_rec(node["children"][i]


max_depth)

if result is not None:

# We've found the goal node while going down that child

return result, True

bottom_reached = bottom_reached and bottom_reached_rec

# We've gone through all children and not found the goal node

return None, bottom_reached

In [ ]:

Block World Problem


In [ ]:
class Node:

def __init__(self,data,level,fval):

""" Initialize the node with the data, level of the node and the calculated
self.data = data

self.level = level

self.fval = fval

def generate_child(self):

""" Generate child nodes from the given node by moving the blank space

either in the four directions {up,down,left,right} """

x,y = self.find(self.data,'_')

""" val_list contains position values for moving the blank space in either o
the 4 directions [up,down,left,right] respectively. """

val_list = [[x,y-1],[x,y+1],[x-1,y],[x+1,y]]

children = []

for i in val_list:

child = self.shuffle(self.data,x,y,i[0],i[1])

if child is not None:

child_node = Node(child,self.level+1,0)

children.append(child_node)

return children

def shuffle(self,puz,x1,y1,x2,y2):

""" Move the blank space in the given direction and if the position value ar
of limits the return None """

if x2 >= 0 and x2 < len(self.data) and y2 >= 0 and y2 < len(self.data):

temp_puz = []

temp_puz = self.copy(puz)

temp = temp_puz[x2][y2]

temp_puz[x2][y2] = temp_puz[x1][y1]

temp_puz[x1][y1] = temp

return temp_puz

else:

return None

def copy(self,root):

""" Copy function to create a similar matrix of the given node"""

temp = []

for i in root:

t = []

for j in i:

t.append(j)

temp.append(t)

return temp

def find(self,puz,x):

""" Specifically used to find the position of the blank space """

for i in range(0,len(self.data)):

for j in range(0,len(self.data)):

if puz[i][j] == x:

return i,j

class Puzzle:

def __init__(self,size):

""" Initialize the puzzle size by the specified size,open and closed lists t
self.n = size

self.open = []

self.closed = []

def accept(self):

""" Accepts the puzzle from the user """

puz = []

for i in range(0,self.n):

temp = input().split(" ")

puz.append(temp)

return puz

def f(self,start,goal):

""" Heuristic Function to calculate hueristic value f(x) = h(x) + g(x) """

return self.h(start.data,goal)+start.level

def h(self,start,goal):

""" Calculates the different between the given puzzles """

temp = 0

for i in range(0,self.n):

for j in range(0,self.n):

if start[i][j] != goal[i][j] and start[i][j] != '_':

temp += 1

return temp

def process(self):

""" Accept Start and Goal Puzzle state"""

print("Enter the start state matrix \n")

count = 0

start = self.accept()

print("Enter the goal state matrix \n")

goal = self.accept()

start = Node(start,0,0)

start.fval = self.f(start,goal)

""" Put the start node in the open list"""

self.open.append(start)

print("\n\n")

while True:

if count>20:

break

cur = self.open[0]

print("")

print(" | ")

print(" | ")

print(" \\\'/ \n")

for i in cur.data:

for j in i:

print(j,end=" ")

print("")

count+=1

""" If the difference between current and goal node is 0 we have reached
if(self.h(cur.data,goal) == 0):

break

for i in cur.generate_child():

i.fval = self.f(i,goal)

self.open.append(i)

self.closed.append(cur)

del self.open[0]

""" sort the opne list based on f value """

self.open.sort(key = lambda x:x.fval,reverse=False)

print("no. of steps : ",count)

puz = Puzzle(3)

puz.process()

Enter the start state matrix

b c a a

a b c c

b c c b

Enter the goal state matrix

Missionary and canibal


In [ ]:
#! /usr/bin/env python3

import sys

import time

from collections import defaultdict

class Direction:

OLD_TO_NEW = 1

NEW_TO_OLD = 0

class CONST:

def __init__(self, MAX_M, MAX_C, CAP_BOAT, MAX_TIME_S, MAX_NODES):

self.MAX_M = MAX_M

self.MAX_C = MAX_C

self.CAP_BOAT = CAP_BOAT

self.MAX_TIME = MAX_TIME_S

self.MAX_NODES = MAX_NODES

# TERMINAL_STATE = State(-1, -1, Direction.NEW_TO_OLD, -1, -1, 0)

# INITIAL_STATE = None

# # State(MAX_M, MAX_C, Direction.OLD_TO_NEW, 0, 0,0)

MAX_M = 30

MAX_C = 30

CAP_BOAT = 20

CNST = None

class State(object):

def __init__(self, missionaries, cannibals, dir, missionariesPassed, canniba


self.missionaries = missionaries

self.cannibals = cannibals

self.dir = dir

self.action = ""

self.level = level

self.missionariesPassed = missionariesPassed

self.cannibalsPassed = cannibalsPassed

self.CONSTANTS = CONSTS

self.moves = moves

global MAX_M

global MAX_C

global CAP_BOAT

global CNST

if not CONSTS is None:

CNST = CONSTS

MAX_M = CONSTS.MAX_M

MAX_C = CONSTS.MAX_C

CAP_BOAT = CONSTS.CAP_BOAT

# pass True to count forward

def successors(self):

listChild = []

if not self.isValid() or self.isGoalState():

return listChild

if self.dir == Direction.OLD_TO_NEW:

sgn = -1

direction = "from the original shore to the new shore"

else:

sgn = 1

direction = "back from the new shore to the original shore"

for i in self.moves:

(m, c) = i

self.addValidSuccessors(listChild, m, c, sgn, direction)

return listChild

def addValidSuccessors(self, listChild, m, c, sgn, direction):

newState = State(self.missionaries + sgn * m, self.cannibals + sgn *


self.missionariesPassed - sg
self.CONSTANTS,self.moves)

if newState.isValid():

newState.action = " take %d missionaries and %d cannibals %s


listChild.append(newState)

def isValid(self):

# obvious

if self.missionaries < 0 or self.cannibals < 0 or self.missionaries


self.dir != 0 and self.dir != 1):

return False

# then check whether missionaries outnumbered by cannibals in any sh


if (self.cannibals > self.missionaries > 0) or (

self.cannibalsPassed > self.missionariesPassed > 0):


return False

return True

def isGoalState(self):

return self.cannibals == 0 and self.missionaries == 0 and self.dir =

def __repr__(self):

return "\n%s\n\n< @Depth:%d State (%d, %d, %d, %d, %d) >" % (

self.action, self.level, self.missionaries, self.cannibals,


self.cannibalsPassed)

def __eq__(self, other):

return self.missionaries == other.missionaries and self.cannibals ==

def __hash__(self):

return hash((self.missionaries, self.cannibals, self.dir))

def __ne__(self, other):

return not (self == other)

TERMINAL_STATE = State(-1, -1, Direction.NEW_TO_OLD, -1, -1, 0, CNST,None)

# INITIAL_STATE = State(MAX_M, MAX_C, Direction.OLD_TO_NEW, 0, 0, 0, CNST)

import time

class Graph:

def __init__(self):

self.bfs_parent = {}

self.dfs_parent = {}

self.expandedBFS = 0

self.expandedDFS = 0

def BFS(self, s):

self.expandedBFS = 0

self.bfs_parent[s] = None

visited = {(s.missionaries, s.cannibals, s.dir): True}

s.level = 0

start_time = time.time()

queue = [s]

while queue:

self.expandedBFS += 1

u = queue.pop(0)

if u.isGoalState():

print("No of Expanded Nodes: " + str(self.expandedBF


print("No of Explored Nodes: " + str(visited.__len__
queue.clear()

self.bfs_parent[TERMINAL_STATE] = u
return self.bfs_parent

# Stops searching after a certain time/node limit

t = time.time() - start_time

if t > u.CONSTANTS.MAX_TIME or self.expandedBFS > u.CONSTANT


if t > u.CONSTANTS.MAX_TIME:

print("%.2fs EXCEEDED TIME LIMIT of %.2fs" %


else:

print("EXCEEDED NODE LIMIT of %d" % u.CONSTA


print("No of Expanded Nodes: " + str(self.expandedBF
print("No of Explored Nodes: " + str(visited.__len__
queue.clear()

return {}

for v in reversed(u.successors()):

if (v.missionaries, v.cannibals, v.dir) not in visit


self.bfs_parent[v] = u

v.level = u.level + 1

queue.append(v)

visited[(v.missionaries, v.cannibals, v.dir)

return {}

def DFS(self, s):

self.expandedDFS = 0

self.dfs_parent[s] = None

visited = {(s.missionaries, s.cannibals, s.dir): True}

start_time = time.time()

stack = [s]

while stack:

u = stack.pop()

self.expandedDFS += 1

if u.isGoalState():

print("No of Expanded Nodes: " + str(self.expandedDF


print("No of Explored Nodes: " + str(visited.__len__
self.dfs_parent[TERMINAL_STATE] = u
stack.clear()

return self.dfs_parent

t = time.time() - start_time

# Stops searching after a certain time/node limit

if t > u.CONSTANTS.MAX_TIME or self.expandedDFS > u.CONSTANT


if t > u.CONSTANTS.MAX_TIME:

print("%.2fs EXCEEDED TIME LIMIT of %.2fs" %


else:

print("EXCEEDED NODE LIMIT of %d" % u.CONSTA


print("No of Expanded Nodes: " + str(self.expandedDF
print("No of Explored Nodes: " + str(visited.__len__
stack.clear()

return {}

for v in u.successors():

if (v.missionaries, v.cannibals, v.dir) not in visit


visited[(v.missionaries, v.cannibals, v.dir)
self.dfs_parent[v] = u

stack.append(v)

return {}

# Prints the path returned by BFS/DFS

def printPath(self, parentList, tail):

if tail is None:

return

if parentList == {} or parentList is None: # tail not in parentList


return

if tail == TERMINAL_STATE: tail = parentList[tail]

stack = []

while tail is not None:

stack.append(tail)

tail = parentList[tail]

while stack:

print(stack.pop())

CON_IN = sys.stdin

CON_OUT = sys.stdout

# Generate All possible next moves for each state to reduce number of iterations on
def genPossibleMoves(CAP_BOAT):

moves = []

for m in range(CAP_BOAT + 1):

for c in range(CAP_BOAT + 1):

if 0 < m < c:

continue

if 1 <= m + c <= CAP_BOAT:

moves.append((m, c))

return moves

def runBFS(g, INITIAL_STATE):

print("\n\nBFS :: \n")

start_time = time.time()

p = g.BFS(INITIAL_STATE)

end_time = time.time()

# print("Printing Solution...")

if len(p):

g.printPath(p, TERMINAL_STATE)

else:

print("No Solution")

print("\n Elapsed time in BFS: %.2fms" % ((end_time - start_time)*1000))

def runDFS(g, INITIAL_STATE):

print("\n\nDFS :: \n")

start_time = time.time()

p = g.DFS(INITIAL_STATE)

end_time = time.time()

if len(p):

g.printPath(p, TERMINAL_STATE)

else:

print("No Solution")

print("\n Elapsed time in DFS: %.2fms" % ((end_time - start_time)*1000))

def main():

m = int(input("m="))

print(m, end="\n")

c = int(input("c="))

print(c, end="\n")

k = int(input("k="))

print(k, end="\n")

# t=10

t = int(10)

#print(t, end="\n")

n = int(100000)

#print(n, end="\n")

# t=10

# n=100000

CNST = CONST(m, c, k, t, n)

moves = genPossibleMoves(CNST.CAP_BOAT)

print(str(moves.__len__())+" iterations per Node.")

INITIAL_STATE = State(CNST.MAX_M, CNST.MAX_C, Direction.OLD_TO_NEW, 0, 0, 0,


# TERMINAL_STATE = State(-1, -1, Direction.NEW_TO_OLD, -1, -1, 0)

g = Graph()

sys.stdout = CON_OUT

print("\nRunning BFS>")

runBFS(g, INITIAL_STATE)

sys.stdout = CON_OUT

print("Executed BFS>")

print("\nRunning DFS>")

runDFS(g, INITIAL_STATE)

sys.stdout = CON_OUT

print("Executed DFS>")

if __name__ == '__main__':

main()

Burglary Alarm
In [3]:
# Import libraries

import pgmpy.models

import pgmpy.inference

import networkx as nx

import pylab as plt

# Create a bayesian network

model = pgmpy.models.BayesianNetwork([('Burglary', 'Alarm'),

('Earthquake', 'Alarm'),

('Alarm', 'JohnCalls'),

('Alarm', 'MaryCalls')])

# Define conditional probability distributions (CPD)

# Probability of burglary (True, False)

cpd_burglary = pgmpy.factors.discrete.TabularCPD('Burglary',2,[[0.001], [0.999]])


# Probability of earthquake (True, False)

cpd_earthquake = pgmpy.factors.discrete.TabularCPD('Earthquake', 2, [[0.002], [0.998


# Probability of alarm going of (True, False) given a burglary and/or earthquake

cpd_alarm = pgmpy.factors.discrete.TabularCPD('Alarm', 2, [[0.95, 0.94, 0.29, 0.001]


[0.05, 0.06, 0.71, 0.999]
evidence=['Burglary', 'Earthquake'],

evidence_card=[2, 2])
# Probability that John calls (True, False) given that the alarm has sounded

cpd_john = pgmpy.factors.discrete.TabularCPD('JohnCalls', 2, [[0.90, 0.05],

[0.10, 0.95]],

evidence=['Alarm'],

evidence_card=[2])

# Probability that Mary calls (True, False) given that the alarm has sounded

cpd_mary = pgmpy.factors.discrete.TabularCPD('MaryCalls', 2, [[0.70, 0.01],

[0.30, 0.99]],

evidence=['Alarm'],

evidence_card=[2])

# Add CPDs to the network structure

model.add_cpds(cpd_burglary, cpd_earthquake, cpd_alarm, cpd_john, cpd_mary)

# Check if the model is valid, throw an exception otherwise

model.check_model()

# Print probability distributions

print('Probability distribution, P(Burglary)')

print(cpd_burglary)

print()

print('Probability distribution, P(Earthquake)')

print(cpd_earthquake)

print()

print('Joint probability distribution, P(Alarm | Burglary, Earthquake)')

print(cpd_alarm)

print()

print('Joint probability distribution, P(JohnCalls | Alarm)')

print(cpd_john)

print()

print('Joint probability distribution, P(MaryCalls | Alarm)')

print(cpd_mary)

print()

# Plot the model

nx.draw(model, with_labels=True)

# Perform variable elimination for inference

# Variable elimination (VE) is a an exact inference algorithm in bayesian networks

infer = pgmpy.inference.VariableElimination(model)

# Calculate the probability of a burglary if John and Mary calls (0: True, 1: False)
posterior_probability = infer.query(['Burglary'], evidence={'JohnCalls': 0, 'MaryCal
# Print posterior probability

print('Posterior probability of Burglary if JohnCalls(True) and MaryCalls(True)')

print(posterior_probability)

print()

# Calculate the probability of alarm starting if there is a burglary and an earthqua


posterior_probability = infer.query(['Alarm'], evidence={'Burglary': 0, 'Earthquake'
# Print posterior probability

print('Posterior probability of Alarm sounding if Burglary(True) and Earthquake(True


print(posterior_probability)

print()

Probability distribution, P(Burglary)

+-------------+-------+

| Burglary(0) | 0.001 |

+-------------+-------+

| Burglary(1) | 0.999 |

+-------------+-------+

Probability distribution, P(Earthquake)

+---------------+-------+

| Earthquake(0) | 0.002 |

+---------------+-------+

| Earthquake(1) | 0.998 |

+---------------+-------+

Joint probability distribution, P(Alarm | Burglary, Earthquake)

+------------+---------------+---------------+---------------+---------------+

| Burglary | Burglary(0) | Burglary(0) | Burglary(1) | Burglary(1) |

+------------+---------------+---------------+---------------+---------------+

| Earthquake | Earthquake(0) | Earthquake(1) | Earthquake(0) | Earthquake(1) |

+------------+---------------+---------------+---------------+---------------+

| Alarm(0) | 0.95 | 0.94 | 0.29 | 0.001 |

+------------+---------------+---------------+---------------+---------------+

| Alarm(1) | 0.05 | 0.06 | 0.71 | 0.999 |

+------------+---------------+---------------+---------------+---------------+

Joint probability distribution, P(JohnCalls | Alarm)

+--------------+----------+----------+

| Alarm | Alarm(0) | Alarm(1) |

+--------------+----------+----------+

| JohnCalls(0) | 0.9 | 0.05 |

+--------------+----------+----------+

| JohnCalls(1) | 0.1 | 0.95 |

+--------------+----------+----------+

Joint probability distribution, P(MaryCalls | Alarm)

+--------------+----------+----------+

| Alarm | Alarm(0) | Alarm(1) |

+--------------+----------+----------+

| MaryCalls(0) | 0.7 | 0.01 |

+--------------+----------+----------+

| MaryCalls(1) | 0.3 | 0.99 |

+--------------+----------+----------+

---------------------------------------------------------------------------

IndexError Traceback (most recent call last)

C:\ProgramData\Anaconda3\lib\site-packages\networkx\utils\decorators.py in _random_s
tate(func, *args, **kwargs)

395 try:

--> 396 random_state_arg = args[random_state_index]

397 except TypeError as e:

IndexError: tuple index out of range

The above exception was the direct cause of the following exception:

NetworkXError Traceback (most recent call last)

<ipython-input-3-c7e2eb4ab24f> in <module>

50 print()

51 # Plot the model

---> 52 nx.draw(model, with_labels=True)

53 # Perform variable elimination for inference

54 # Variable elimination (VE) is a an exact inference algorithm in bayesian ne


tworks

C:\ProgramData\Anaconda3\lib\site-packages\networkx\drawing\nx_pylab.py in draw(G, p
os, ax, **kwds)

121 kwds["with_labels"] = "labels" in kwds

122

--> 123 draw_networkx(G, pos=pos, ax=ax, **kwds)

124 ax.set_axis_off()

125 plt.draw_if_interactive()

C:\ProgramData\Anaconda3\lib\site-packages\networkx\drawing\nx_pylab.py in draw_netw
orkx(G, pos, arrows, with_labels, **kwds)

331

332 if pos is None:

--> 333 pos = nx.drawing.spring_layout(G) # default to spring layout

334

335 draw_networkx_nodes(G, pos, **node_kwds)

C:\ProgramData\Anaconda3\lib\site-packages\decorator.py in fun(*args, **kw)

229 if not kwsyntax:

230 args, kw = fix(args, kw, sig)

--> 231 return caller(func, *(extras + args), **kw)

232 fun.__name__ = func.__name__

233 fun.__doc__ = func.__doc__

C:\ProgramData\Anaconda3\lib\site-packages\networkx\utils\decorators.py in _random_s
tate(func, *args, **kwargs)

398 raise nx.NetworkXError("random_state_index must be an integer")


from e

399 except IndexError as e:

--> 400 raise nx.NetworkXError("random_state_index is incorrect") from e

401

402 # Create a numpy.random.RandomState instance

NetworkXError: random_state_index is incorrect

8 puzzle using a*
In [1]:
class Node:

def __init__(self,data,level,fval):

self.data = data

self.level = level

self.fval = fval

def generate_child(self):

x,y = self.find(self.data,'_')

val_list = [[x,y-1],[x,y+1],[x-1,y],[x+1,y]]

children = []

for i in val_list:

child = self.shuffle(self.data,x,y,i[0],i[1])

if child is not None:

child_node = Node(child,self.level+1,0)

children.append(child_node)

return children

def shuffle(self,puz,x1,y1,x2,y2):

if x2 >= 0 and x2 < len(self.data) and y2 >= 0 and y2 < len(self.data):

temp_puz = []

temp_puz = self.copy(puz)

temp = temp_puz[x2][y2]

temp_puz[x2][y2] = temp_puz[x1][y1]

temp_puz[x1][y1] = temp

return temp_puz

else:

return None

def copy(self,root):

temp = []

for i in root:

t = []

for j in i:

t.append(j)

temp.append(t)

return temp

def find(self,puz,x):

for i in range(0,len(self.data)):

for j in range(0,len(self.data)):

if puz[i][j] == x:

return i,j

class Puzzle:

def __init__(self,size):

self.n = size

self.open = []

self.closed = []

def accept(self):

puz = []

for i in range(0,self.n):

temp = input().split(" ")

puz.append(temp)

return puz

def f(self,start,goal):

return self.h(start.data,goal)+start.level

def h(self,start,goal):

temp = 0

for i in range(0,self.n):

for j in range(0,self.n):

if start[i][j] != goal[i][j] and start[i][j] != '_':

temp += 1

return temp

def process(self):

print("Enter the start state matrix \n")

start = self.accept()

print("Enter the goal state matrix \n")

goal = self.accept()

start = Node(start,0,0)

start.fval = self.f(start,goal)

self.open.append(start)

print("\n\n")

while True:

cur = self.open[0]

for i in cur.data:

for j in i:

print(j,end=" ")

print("")

if(self.h(cur.data,goal) == 0):

break

for i in cur.generate_child():

i.fval = self.f(i,goal)

self.open.append(i)

self.closed.append(cur)

del self.open[0]

self.open.sort(key = lambda x:x.fval,reverse=False)

puz = Puzzle(3)

puz.process()

Enter the start state matrix

1 2 3

_ 4 6

7 5 8

Enter the goal state matrix

1 2 3

4 5 6

7 8 _

1 2 3

_ 4 6

7 5 8

1 2 3

4 _ 6

7 5 8

1 2 3

4 5 6

7 _ 8

1 2 3

4 5 6

7 8 _

Block world using Hill climbing


In [5]:
import copy

visited_states = []

# heuristic fn - number of misplaced blocks as compared to goal state

def heuristic(curr_state ,goal_state):

goal_=goal_state[3]

val=0

for i in range(len(curr_state)):

check_val=curr_state[i]

if len(check_val)>0:

for j in range(len(check_val)):

if check_val[j]!=goal_[j]:

# val-=1

val-=j

else:

# val+=1

val+=j

return val

# generate next possible solution for the current state

def generate_next(curr_state,prev_heu,goal_state):

global visited_states

state = copy.deepcopy(curr_state)

for i in range(len(state)):

temp = copy.deepcopy(state)

if len(temp[i]) > 0:

elem = temp[i].pop()

for j in range(len(temp)):

temp1 = copy.deepcopy(temp)

if j != i:

temp1[j] = temp1[j] + [elem]

if (temp1 not in visited_states):

curr_heu=heuristic(temp1,goal_state)

# if a better state than previous state of found

if curr_heu>prev_heu:

child = copy.deepcopy(temp1)

return child

# no better soln than current state is possible

return 0

def solution_(init_state,goal_state):

global visited_states

# checking if initial state is already the final state

if (init_state == goal_state):

print (goal_state)

print("solution found!")

return

current_state = copy.deepcopy(init_state)

# loop while goal is found or no better optimal solution is possible

while(True):

# add current state to visited to avoid repetition

visited_states.append(copy.deepcopy(current_state))

print(current_state)

prev_heu=heuristic(current_state,goal_state)

# generate possible better child from current state

child = generate_next(current_state,prev_heu,goal_state)

# No more better states are possible

if child==0:

print("Final state - ",current_state)

return

# change current state to child

current_state = copy.deepcopy(child)

def solver():

# maintaining a global visited to save all visited and avoid repetition & infini
global visited_states

# inputs

init_state = [[],[],[],['B','C','A','A']]

goal_state = [[],[],[],['A','B','C','D']]

# goal_state = [[],[],[],['A','D','C','B']]

solution_(init_state,goal_state)

solver()

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


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

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

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

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

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

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

Final state - [['A', 'B', 'C'], ['A'], [], []]

In [ ]:

You might also like