I am trying to implement iterative deepening search for the k - puzzle. I have managed to find the goal node. However, I am unable to backtrack from the goal node to the start node to find the optimal moves. I think it has something to do with repeated states in IDS. Currently, I am keeping track of all visited states in the IDS algorithm.
This is the current implementation of my algorithm. In the code below, moves_dict stores each node's previous state and move to get to current state.
import os
import sys
from itertools import chain
from collections import deque
# Iterative Deepening Search (IDS)
class Node:
def __init__(self, state, empty_pos = None, depth = 0):
self.state = state
self.depth = depth
self.actions = ["UP", "DOWN", "LEFT", "RIGHT"]
if empty_pos is None:
self.empty_pos = self.find_empty_pos(self.state)
else:
self.empty_pos = empty_pos
def find_empty_pos(self, state):
for x in range(n):
for y in range(n):
if state[x][y] == 0:
return (x, y)
def find_empty_pos(self, state):
for x in range(n):
for y in range(n):
if state[x][y] == 0:
return (x, y)
def do_move(self, move):
if move == "UP":
return self.up()
if move == "DOWN":
return self.down()
if move == "LEFT":
return self.left()
if move == "RIGHT":
return self.right()
def swap(self, state, (x1, y1), (x2, y2)):
temp = state[x1][y1]
state[x1][y1] = state[x2][y2]
state[x2][y2] = temp
def down(self):
empty = self.empty_pos
if (empty[0] != 0):
t = [row[:] for row in self.state]
pos = (empty[0] - 1, empty[1])
self.swap(t, pos, empty)
return t, pos
else:
return self.state, empty
def up(self):
empty = self.empty_pos
if (empty[0] != n - 1):
t = [row[:] for row in self.state]
pos = (empty[0] + 1 , empty[1])
self.swap(t, pos, empty)
return t, pos
else:
return self.state, empty
def right(self):
empty = self.empty_pos
if (empty[1] != 0):
t = [row[:] for row in self.state]
pos = (empty[0] , empty[1] - 1)
self.swap(t, pos, empty)
return t, pos
else:
return self.state, empty
def left(self):
empty = self.empty_pos
if (empty[1] != n - 1):
t = [row[:] for row in self.state]
pos = (empty[0] , empty[1] + 1)
self.swap(t, pos, empty)
return t, pos
else:
return self.state, empty
class Puzzle(object):
def __init__(self, init_state, goal_state):
self.init_state = init_state
self.state = init_state
self.goal_state = goal_state
self.total_nodes = 1
self.total_visited = 0
self.max_frontier = 0
self.depth = 0
self.visited = {}
self.frontier_node = []
self.move_dict = {}
def is_goal_state(self, node):
return node.state == self.goal_state
def is_solvable(self):
flat_list = list(chain.from_iterable(self.init_state))
num_inversions = 0
for i in range(max_num):
current = flat_list[i]
for j in range(i + 1, max_num + 1):
next = flat_list[j]
if current > next and next != 0:
num_inversions += 1
if n % 2 != 0 and num_inversions % 2 == 0:
return True
elif n % 2 == 0:
row_with_blank = n - flat_list.index(0) // n
return (row_with_blank % 2 == 0) == (num_inversions % 2 != 0)
else:
return False
def succ(self, node, frontier):
succs = deque()
node_str = str(node.state)
self.visited[node_str] = node.depth
self.total_visited += 1
frontier -= 1
for m in node.actions:
transition, t_empty = node.do_move(m)
transition_str = str(transition)
transition_depth = node.depth + 1
if transition_str not in self.visited or transition_depth < self.visited[transition_str]:
self.total_nodes += 1
transition_depth = node.depth + 1
transition_str = str(transition)
self.move_dict[transition_str] = (node_str, m)
succs.append(Node(transition, t_empty, transition_depth))
frontier += 1
return succs , frontier
def depth_limited(self, node, depth, frontier):
if self.is_goal_state(node):
return node
if node.depth >= depth:
return None
succs, frontier = self.succ(node, frontier)
self.max_frontier = max(self.max_frontier, frontier)
while succs:
result = self.depth_limited(succs.popleft(), depth, frontier)
if result is not None:
return result
return None
def solve(self):
if not self.is_solvable():
return ["UNSOLVABLE"]
goal_node = None
while goal_node is None:
goal_node = self.depth_limited(Node(self.init_state), self.depth, 1)
if goal_node is not None:
break
# reset statistics
self.visited = {}
self.total_nodes = 1
self.move_dict = {}
self.depth += 1
print self.depth
print "out"
print goal_node.state
solution = deque()
init_str = str(self.init_state)
current_str = str(goal_node.state)
while current_str != init_str:
current_str, move = self.move_dict[current_str]
solution.appendleft(move)
print "Total number of nodes generated: " + str(self.total_nodes)
print "Total number of nodes explored: " + str(self.total_visited)
print "Maximum number of nodes in frontier: " + str(self.max_frontier)
print "Solution depth: " + str(self.depth)
return solution
I have been cracking my head for awhile now. I use a hashMap that maps the state string to its depth and when adds the node whenever the same state appears in a shallower depth
EDIT
Optimal solution depth for this test case is 22.
init state: [[1,8,3],[5,2,4],[0,7,6]]
Goal state: [[1,2,3],[4,5,6],[7,8,0]]
im not going to implement your k puzzle but consider the following datastruct
d = {'A':{'B':{'Z':7,'Q':9},'R':{'T':0}},'D':{'G':1}}
def find_node(search_space,target,path_so_far=None):
if not path_so_far: # empty path to start
path_so_far = []
for key,value in search_space.items():
if value == target:
# found the value return the path
return path_so_far+[key]
else:
# pass the path so far down to the next step of the search space
result = find_node(search_space[key],target, path_so_far+[key])
if result:
print("Found Path:",result)
return result
Related
As we know from daily experience diagonal moves are cheaper than a
horizontal + vertical moves, this becomes a problem of uneven step cost.
So, uniform cost search will be required to solve this problem.
To implement uniform cost search, you will need a Priority Queue for frontier.
To add a child to the frontier
frontier.insert(item)
To extract the item with minimum cost
Temp = frontier.extract_min()
To decrease the cost of an item
frontier.decrease_key(item)
To check if in an item is already in the frontier
frontier.is_in(item)
It returns true if item is in the frontier, returns false if not in the frontier.
Algorithm I used for this code :
import collections
import copy
grid_size = 5
source = (0, 0)
destination = (4, 3)
grid = [[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]]
class Location:
def __init__(self, p, cost=0):
self.point = p
self.parent = None
self.cost = cost
self.hash_value = self.hash_calc()
def hash_calc(self):
x, y = self.point
return str(x) + "_" + str(y)
def make_move(self, direction):
x, y = self.point
# up
if direction == 'l':
if y > 0 and grid[x][y-1] == 0:
self.point = x, y-1
self.cost = self.cost + 1
# down
elif direction == 'r':
if y < grid_size-1 and grid[x][y+1] == 0:
self.point = x, y+1
self.cost = self.cost + 1
# left
elif direction == 'u':
if x > 0 and grid[x-1][y] == 0:
self.point = x-1, y
self.cost = self.cost + 1
# right
elif direction == 'd':
if x < grid_size-1 and grid[x+1][y] == 0:
self.point = x+1, y
self.cost = self.cost + 1
# up-left
elif direction == 'ul':
if y>0 and x>0 and grid[x-1][y-1] == 0:
self.point = x-1, y-1
self.cost = self.cost + 1.5
# up-right
elif direction == 'dl':
if y>0 and x<grid_size-1 and grid[x+1][y-1] == 0:
self.point = x+1, y-1
self.cost = self.cost + 1.5
# down-left
elif direction == 'ur':
if y<grid_size-1 and x>0 and grid[x-1][y+1] == 0:
self.point = x-1, y+1
self.cost = self.cost + 1.5
# down-right
elif direction == 'dr':
if y<grid_size-1 and x<grid_size-1 and grid[x+1][y+1] == 0:
self.point = x+1, y+1
self.cost = self.cost + 1.5
self.hash_value = self.hash_calc()
print(self.point, self.cost)
def copy_location(self):
temp = Location(self.point, cost=self.cost)
temp.parent = self
return temp
def print_path(self):
ancestors = []
temp = self
while(temp.parent != None):
ancestors.append(temp.parent)
temp = temp.parent
n = len(ancestors)
for i in range(n):
temp = ancestors.pop()
print(temp.point, end='->')
print(self.point)
print('%d steps were required.\nTotal cost is %f' % (n, self.cost))
def goal_test(self):
return self.point == destination
def get_key(self):
return self.cost
class Priority_Queue:
def __init__(self):
self.capacity = 2
self.q = [None] * self.capacity
self.items = [None] * self.capacity
self.dict = {}
self.size = 0
def parent(self, i):
return int((i-1)/2)
def left(self, i):
return 2*i + 1
def right(self, i):
return 2*i + 2
def move(self, i, j):
self.q[i] = self.q[j]
self.items[i] = self.items[j]
self.dict[self.items[i].hash_value] = i
def swap(self, i, j):
self.q[i], self.q[j] = self.q[j], self.q[i]
self.items[i], self.items[j] = self.items[j], self.items[i]
self.dict[self.items[i].hash_value] = i
self.dict[self.items[j].hash_value] = j
def min_heapify(self, i):
left = self.left(i)
right = self.right(i)
smallest = i
if left < self.size and self.q[left] < self.q[i]:
smallest = left
if right < self.size and self.q[right] < self.q[smallest]:
smallest = right
if smallest != i:
self.swap(i, smallest)
self.min_heapify(smallest)
def insert(self, item):
self.size = self.size + 1
if self.size > self.capacity:
self.q = self.q + [None] * self.capacity
self.items = self.items + [None] * self.capacity
self.capacity = self.capacity * 2
i = self.size - 1
self.q[i] = item.get_key()
self.items[i] = item
self.dict[item.hash_value] = i
while i != 0 and self.q[self.parent(i)] > self.q[i]:
self.swap(i, self.parent(i))
i = self.parent(i)
def extract_min(self):
item = self.items[0]
self.move(0, self.size - 1)
self.dict.pop(item.hash_value)
self.size = self.size - 1
self.min_heapify(0)
return item
def decrease_key(self, item):
i = self.dict[item.hash_value]
if self.q[i] < item.get_key():
return
self.q[i] = item.get_key()
self.items[i] = item
while i != 0 and self.q[self.parent(i)] > self.q[i]:
self.swap(i, self.parent(i))
i = self.parent(i)
def get_min(self):
return self.items[0]
def is_in(self, item):
return item.hash_value in self.dict.keys()
# Make an initial State with source
initial_state = Location(source)
# Create an empty frontier
frontier = Priority_Queue()
frontier.insert(initial_state)
# Create an empty explored list
explored = set()
# initialize frontier with initial state
##########################################
####Solution would be here
##############Solution i Tried to solve
x = 0
children=()
Output = False
#While Output is False
while Output == False:
x = x+1
if frontier.size == 0:
print('No Solution Found !')
break
z = frontier.get_min()
explored.add(z)
#make moves
for d in ['u','d','l','r','ul','dl','ur','dr']:
children = z.copy_location()
children.make_move(d)
if children not in explored and children:
if children.goal_test() == True:
children.print_path()
Output = True
break
frontier.insert(children)
#if output is true
if Output == True:
print('Total %d states Explored !.' %(x))
break
i want to implement uniform cost search here. i tried to follow the pseudo code but i failed.
well this is my first time in stack overflow so if i made any mistake please forgive me !
i will be more careful from next time.
I'm trying to count the number of probes (or number of indices that must be passed over) when inserting keys into a list using quadratic probing
I have
def hash_quadratic(key, values):
tablesize=len(values)
index=key%tablesize
probes=0
if values[index] is None:
values[index]=key
probes+=1
return probes
else:
while values[index] is not None:
index = (index+1**2)% tablesize
probes+=1
values[index]=key
return probes
I think this just counts every time the index changes but doesn't count the number of indices that it crosses over. How do I count every index that the key passes?
If you would like to implement Quadratic probe on a hash table, you need more than the function you have written. The following class does the job you are looking for:
class HashTable(object):
def __init__(self, size=200):
self.size = size
self.slots = [None] * self.size
def hash_function(self, key):
s = str(key)
n_hash = 0
for obj in s:
if obj.isdigit():
n_hash = (n_hash << 5) + n_hash + ord(obj)
return n_hash % self.size
def quad_prob(self, oldhash, iter):
n_hash = 0
n_hash = (oldhash + iter**2) % self.size
return n_hash
def put(self, key):
collis_count = 0
hashval = self.hash_function(key)
if self.slots[hashval] == None:
self.slots[hashval] = key
else:
if self.slots[hashval] == key:
pass
else:
iter_count = 1
first_hash = hashval
nextslot = self.quad_prob(first_hash, iter_count)
# looking for a key or any empty slot
while self.slots[nextslot] != None and self.slots[nextslot] != key and iter_count <= self.size:
iter_count += 1
nextslot = self.quad_prob(first_hash, iter_count)
collis_count = iter_count
if self.slots[nextslot] == None:
self.slots[nextslot] = key
return collis_count
Below is what I have done but it Does not handle the max requirement on insert.
how do I Give the class a max value and check it in the insert and then remove the least significant element. Then figure out what is the least significant element in the implementation.
Having some issues trying to figure this out.
import math
import random
class BinaryHeap:
def __init__(self, array, direction=1, size=100):
if(size > len(array)):
self.size = len(array)
else:
self.size = size;
self.bBinaryHeap = array[:]
if 0 < direction:
self.compare = self.greater
else:
self.compare = self.less
self.buildBinaryHeap()
def node(self, index):
return (index << 1) + 1
def parent(self, index):
return (index - 1) >> 1
def bBinaryHeapifyDown(self, index):
swap = self.bBinaryHeap[index]
while self.node(index) < self.size:
node = self.node(index)
if node + 1 < self.size and self.compare(self.bBinaryHeap[node], self.bBinaryHeap[node + 1]) > 0:
node += 1
if self.compare(swap, self.bBinaryHeap[node]) > 0:
self.bBinaryHeap[index] = self.bBinaryHeap[node];
else:
break
index = node
self.bBinaryHeap[index] = swap
def upheapify(self, index):
while 0 < index and self.compare(self.bBinaryHeap[index], self.bBinaryHeap[self.parent(index)]) < 0:
parent = self.parent(index)
swap = self.bBinaryHeap[parent]
self.bBinaryHeap[parent] = self.bBinaryHeap[index]
self.bBinaryHeap[index] = swap
index = parent
def buildBinaryHeap(self):
indices = range(0, int(self.size / 2))
reversed(indices)
for index in indices:
self.bBinaryHeapifyDown(index)
def insert(self, value):
self.shrink()
index = self.size
self.bBinaryHeap[index] = value
self.size += 1
self.upheapify(index)
def search(self, value):
for index in range(self.size):
if self.bBinaryHeap[index] == value:
return index
def delete(self, value):
index = self.search(value)
self.size -= 1
self.bBinaryHeap[index] = self.bBinaryHeap[self.size]
parent = self.parent(index)
if (index == 0) or (self.compare(self.bBinaryHeap[parent], self.bBinaryHeap[index]) < 0):
self.bBinaryHeapifyDown(index)
else:
self.upheapify(index)
def shrink(self):
capacity = len(self.bBinaryHeap)
if capacity == self.size:
self.bBinaryHeap.extend([0] * capacity)
def greater(self, value1, value2):
if value1 == value2:
return 0
elif value1 < value2:
return 1
elif value1 > value2:
return -1
def less(self, value1, value2):
if value1 == value2:
return 0
elif value1 < value2:
return -1
elif value1 > value2:
return 1
def getLevel(self, index):
return int(math.floor(math.log(index + 1, 2)))
def displayBinaryHeap(self):
printBinaryHeap = str(self.bBinaryHeap)
height = self.getLevel(self.size)
previous = -1
for index in range(self.size):
getLevel = self.getLevel(index)
n = height - getLevel
indent = int(math.pow(2, n + 1) - 2)
spacing = 2 * indent
if getLevel != previous:
printBinaryHeap += '\n'
printBinaryHeap += ' ' * indent
previous = getLevel
else:
printBinaryHeap += ' ' * spacing
printBinaryHeap += '%4d' % self.bBinaryHeap[index]
print(printBinaryHeap)
if __name__ == "__main__":
size =10
array = [random.randint(0, 100) for i in range(size)]
bBinaryHeap = BinaryHeap(array, 1, 100)
print('Binary bBinaryHeap:')
bBinaryHeap.displayBinaryHeap()
Your code has numerous indentation errors. In python, indentation counts.
As for this code:
if 0 < direction:
self.compare = self.greater
else:
self.compare = self.less
self.greater and self.less don't exist. You are doing the equivalent of this:
x = elephant
That's nice, but unless you've set the variable elephant to some value prior to that line, that is an error.
how do I Give the class a max value
class BinaryHeap:
pass
BinaryHeap.max = 10
print(BinaryHeap.max)
--output:--
10
and check it in the insert
class BinaryHeap:
max = 10
def insert(self):
print(self.max)
bh = BinaryHeap()
bh.insert()
--output:--
10
then remove the least significant element
x = 0b1111
print(x) #15
y = x >> 1
print("{:b}".format(y)) #111
print(y) #7
Then figure out what is the least significant element in the implementation
x = 0b1110
print(x) #=>14
b_str = "{:b}".format(x)
print(repr(b_str)) #=> '1110'
for direction in [1, -1]:
if direction > 0:
least_signif = b_str[-1]
else:
least_signif = b_str[0]
print(least_signif)
--output:--
0
1
The purpose of this code is to create the shortest path that connect each point. I've tried to implement the Kruskals algorithm in Python, but there is a problem and it occurs when the function findSet(x) is called. It seems like the program enters a infinite loop. I've tried to print x, x.dad and x.dad.dad and x in the crucial moment returns the initial x. I really don't know where is the problem.
class Point:
def __init__(self,x = None, y = None):
self.x = x
self.y = y
self.dad = None
self.rank = None
class Edge:
def __init__(self, firstPoint = None, secondPoint = None, value = None):
self.firstPoint = firstPoint
self.secondPoint = secondPoint
if self.firstPoint != None and self.secondPoint != None:
self.value = abs(firstPoint.x-secondPoint.x) + abs(firstPoint.y - secondPoint.y)
else:
self.value = float("inf")
def makeSet(node):
node.dad = node
node.rank = 0
def findSet(x):
print x, x.dad,x.dad.dad
if x == x.dad:
return x
x.dad = findSet(x.dad)
return x.dad
def unionSet(node1,node2):
root1 = findSet(node1)
root2 = findSet(node2)
if root1.rank < root2.rank:
root1.dad = root2
if root1.rank > root2.rank:
root2.dad = root1
else:
root2.dad = root1
root1.rank += 1
def merge(A, p, q, r):
L = A[p:q+1]
R = A[q+1:r+1]
infinite = Edge()
L.append(infinite)
R.append(infinite)
temp = []
i = 0
j = 0
for k in range(p,r+1):
if L[i].value <= R[j].value:
temp.append(L[i])
i += 1
else:
temp.append(R[j])
j += 1
A[p:r+1] = temp
def mergeSort(A,p,r):
A2 = A
if p < r:
q = int((p+r)/2)
mergeSort(A2, p, q)
mergeSort(A2, q+1, r)
merge(A2, p, q, r)
def readPoint(A):
temp = []
for i in range(0,len(A), 2):
tempPoint = Point(A[i],A[i+1])
makeSet(tempPoint)
temp.append(tempPoint)
return temp
def calculateEdges(A):
tempArray = []
for i in range(0,len(A)):
for j in range(i+1,len(A)):
edge = Edge(A[i], A[j])
tempArray.append(edge)
return tempArray
def Kruskal(N, E):
mergeSort(E,0,len(E)-1)
j = 0
i = 0
total = 0
while j < N:
if findSet(E[i].firstPoint) != findSet(E[i].secondPoint):
unionSet(E[i].firstPoint,E[i].secondPoint)
j += 1
total += E[i].value
if i < len(E) - 1:
i += 1
return total
Ar = readPoint([18, 2, 99, 68])
E = calculateEdges(Ar)
print Kruskal(len(Ar),E)
I moved this from code review because folks over there suggest this should be posted here
I'm trying to do 8-puzzle using pycharm, I will first generate a 3x3 list and then shuffle it to get the initial board state example:
[1 , 2 , 3 ]
[4 , 5 , 6 ]
[7 , 8 , 9 ]
then I'll do some random moves on it to get the goal board state:
[ 3 , 2 , 1 ]
[ 6 , 5 , 4 ]
[ 9 , 8 , 7 ]
when I set the size to be 3(3x3) it never complete the search, and when I set the size to be 2 it solves but sometimes it will exhaust the frontier list and returns nothing, which should not be possible.
EDIT
I changed the
return Solution (start_node, numExplored, memoryRequired)
to
return Solution (fr_node, numExplored, memoryRequired)
and it always return an solution for 2x2 , 3x3 is still very slow though
I have these code in Python:
def breadthFirstSearch(problem):
"""Search the shallowest nodes in the search tree first."""
frontier = util.Queue()
explored = []
numExplored = 0
memoryRequired = 0
# generate start node
start_node = Node(problem.getStartState(), None, 0, None)
# return immediately if start node is the goal state
if problem.isGoalState(start_node.state):
return Solution(start_node, 0, 0)
# push start node into frontier
frontier.push (start_node)
# while frontier list is not empty
while not frontier.isEmpty():
# get the first-in frontier node from frontier list
fr_node = frontier.pop()
explored.append(fr_node)
# get successor nodes
successors = problem.getSuccessors(fr_node.state)
numExplored += 1
# append into explored list
# if len(successors) >0:
# explored.append(fr_node)
# else:
# explored.append(fr_node)
# for each successor node
for sc_state, sc_action, sc_cost in successors:
# generate successor node
sc_node = Node(sc_state, sc_action, sc_cost, fr_node)
# check for goal state immediately after generate
if problem.isGoalState(sc_node.state): # if found solution
return Solution (sc_node, numExplored, memoryRequired)
# insert successor node into frontier list (if not found in explored and frontier)
if sc_node not in explored and sc_node not in frontier.list:
frontier.push(sc_node)
memoryRequired = max ([memoryRequired, len(frontier.list)+len(explored)])
print ('Frontier size = %d, Explored size = %d, Total size = %d ,Successor Length= %d' %(len(frontier.list), len(explored), len(frontier.list)+len(explored), len(successors)))
return Solution (start_node, numExplored, memoryRequired)
Node is defined as:
class Node:
def __init__(self, state, action, cost, parent):
self.state = state
self.cost = cost
self.action = action
self.parent = parent
if parent is None:
self.totalCost = cost
self.depth = 0
else:
self.totalCost = parent.totalCost + cost
self.depth = parent.depth + 1
def __eq__(self, other):
return hasattr(other,'state') and self.state == other.state
and then there's the file that defines NPuzzle and Puzzle state.
class ActionType:
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
Actions = [ActionType.UP, ActionType.DOWN, ActionType.LEFT,
ActionType.RIGHT]
class PuzzleState (SearchState):
def __init__ (self, n, board = None):
self.n = n
self.board = [[j for j in range(n*i,n*i+n)] for i in range(n)]
self.blankCellPos = self.getBlankCellPos()
def __eq__ (self, other):
if self.board == other.board:
return True
else:
return False
def deepCopy(self):
state = copy.deepcopy(self) #PuzzleState(self.n)
return state
def getBlankCellPos (self):
for i in range(self.n):
for j in range(self.n):
if self.board[i][j] == 0:
return (i,j)
def isValidAction (self, action):
(r,c)= self.blankCellPos
if action == ActionType.UP:
if r - 1 < 0:
return False
else:
return True
elif action == ActionType.DOWN:
if r + 1 > self.n-1:
return False
else:
return True
elif action == ActionType.LEFT:
if c - 1 < 0:
return False
else:
return True
elif action == ActionType.RIGHT:
if c + 1 > self.n-1:
return False
else:
return True
def getValidActions (self):
ValidActions = []
for action in Actions:
if(self.isValidAction(action) == True):
ValidActions.append(action)
return ValidActions
def move (self, action):
(r,c) = self.blankCellPos
if action == ActionType.UP:
self.blankCellPos = (r-1,c)
self.board[r][c], self.board[r-1][c] = self.board[r-1][c], self.board[r][c]
elif action == ActionType.DOWN:
self.blankCellPos = (r+1,c)
self.board[r][c], self.board[r+1][c] = self.board[r+1][c], self.board[r][c]
elif action == ActionType.LEFT:
self.blankCellPos = (r, c-1)
self.board[r][c], self.board[r][c-1] = self.board[r][c-1], self.board[r][c]
elif action == ActionType.RIGHT:
self.blankCellPos = (r, c+1)
self.board[r][c], self.board[r][c+1] = self.board[r][c+1], self.board[r][c]
def randomMove (self, numMoves):
#(r,c) = self.board.blankCellPos
ValidActions = []
actions = []
tmp = -1
for num in range(numMoves):
ValidActions = self.getValidActions()
tmp = random.choice(ValidActions)
#remove loopy choices#
if num > 0:
if actions[-1] == ActionType.UP and tmp == ActionType.DOWN:
ValidActions.remove(ActionType.DOWN)
tmp = random.choice(ValidActions)
elif actions[-1] == ActionType.DOWN and tmp == ActionType.UP:
ValidActions.remove(ActionType.UP)
tmp = random.choice(ValidActions)
elif actions[-1] == ActionType.LEFT and tmp == ActionType.RIGHT:
ValidActions.remove(ActionType.RIGHT)
tmp = random.choice(ValidActions)
elif actions[-1] == ActionType.RIGHT and tmp == ActionType.LEFT:
ValidActions.remove(ActionType.LEFT)
tmp = random.choice(ValidActions)
actions.append(tmp)
self.move(tmp)
def randomInitialize (self):
random.shuffle(self.board)
for ii, sublist in enumerate(self.board):
random.shuffle(self.board[ii])
self.blankCellPos = self.getBlankCellPos()
def display (self):
print( ' ',)
#for c in range (self.n):
print (self.board)
#print (' %d' %(c),)
class NPuzzle (SearchProblem):
def __init__ (self, n, startState = None, goalState = None):
self.n = PuzzleState(n)
self.startState = self.n.deepCopy()
self.goalState = self.n.deepCopy()
def randomStartState (self):
self.startState.randomInitialize()
def randomGoalState(self, numMoves):
self.goalState.randomMove(numMoves)
def setStartState (self, startState):
self.startState = startState
def setGoalState (self, goalState):
self.goalState = goalState
def getStartState (self):
return self.startState
def getGoalState (self):
return self.goalState
def isGoalState(self, state):
if state == self.goalState:
return True
else:
return False
def getSuccessors (self, state):
successorlist = []
validActions = state.getValidActions()
for action in validActions:
#if not deep copy what will happen?
successor = state.deepCopy()
successor.move(action)
self.cost = 1
successorlist.append([successor, action, self.cost])
return successorlist
According to what I read and what my lecturer told me , the machine should punch out something around thousands of searches every second but when I run it it only appear to be very fast at the first few thousand nodes and then slows down terribly after that.
I have no idea what's wrong. Any hint will be greatly appreciated.