You are on page 1of 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