solving 8 puzzle problem with BFS DFS (Using Python. Needs some suggestion) - python

My final state is
0 1 2 3 4 5 6 7 8
my graph would look like this
graph = {0 :[1, 3],
1 :[0, 4, 2],
2 :[1, 5],
3 :[0, 4, 6],
4 :[1, 3, 5, 7],
5 :[2, 4, 8],
6 :[3, 7],
7 :[4, 6, 8],
8 :[5 ,7]
}
1 - I was wondering if I should try some other methods such as list, if else statement than graph(above).
2 - Is anything wrong with the graph?
The problem given -
Example [1,5,3,2,0,4,7,8,6] <- more like this 1 5 3 2 0 4
7 8 6
I am supposed to find final state with given state
Thank You

So, there are 4 corner cases:
Top row
Bottom row
Most left column
Most right column
(And combinations)
We can handle them easy like this:
data = [1, 5, 3,
2, 0, 4,
7, 8, 6]
width = 3
height = 3
graph = {number: list() for number in data}
for idx, number in enumerate(data):
current_height = int(idx / width)
current_width = idx % width
if current_width != width - 1: # if next element in same row
graph[number].append(data[idx + 1])
if current_width != 0: # if prev element in same row
graph[number].append(data[idx - 1])
if current_height != 0: # if there is top element
graph[number].append(data[idx - 3])
if current_height != height - 1: # if there is bottom element
graph[number].append(data[idx + 3])
import pprint
pprint.pprint(graph)
This code will construct graph, but is this all for that puzzle?.

Related

Loop stuck while calculating the nearest neighbour

I am trying to print out the list of nearest neighbours. I should be getting a list of length 12; however, the list I am getting is of shorter length. When I print out the values for the variable 'a', it is getting stuck at the last element of the list 'path'. I've been trying to debug it, but couldn't find why the value of 'a' is not following the same pattern and why I can't get the other elements.
G is a graph with 11 nodes in total, and what I should be getting is G.NNA(3) = [3, 4, 0, 10, 2, 8, 1, 7, 5, 11, 6, 9]. I am getting the list up until the eighth index [3, 4, 0, 10, 2, 8, 1, 7, 5].
I put print statements inside the two 'if' statements, and the value 'a' clearly gets stuck. It would be amazing if I could fix it. Thanks in advance!
def NNA(self, start):
path = [start] # Initialize the path that starts with the given point
usedNodes = [start] # List for used nodes
currentNode = start
a = 1
while len(path) < self.n and a < self.n:
distances = self.dists[currentNode] # self.dists[3] = [4, 3, 3, 0, 1, 3, 3, 2, 3, 3, 4, 2] and the indeces correspond to the nodes
nextNode = distances.index(sorted(distances)[a]) # Gets the next node
if nextNode not in usedNodes :
a = 1
path.append(nextNode)
usedNodes.append(nextNode)
currentNode = nextNode
print(currentNode, a)
elif nextNode in usedNodes:
a = a + 1 # Check the next smallest value
print(currentNode, a)
self.perm = path
print(path)
# Here is the output
4 1
4 2
0 1
10 1
10 2
2 1
8 1
8 2
1 1
7 1
5 1 # gets stuck at 5
5 2
5 3
5 4
5 5
5 6
5 7
5 8
5 9
5 10
5 11
5 12
[3, 4, 0, 10, 2, 8, 1, 7, 5] # expecting [3, 4, 0, 10, 2, 8, 1, 7, 5, 11, 6, 9]

When to reset temp variable in this Python procedure?

I'm trying to find the column wise combinations for given m x n 2d matrix. For example if the matrix is 3 x 3, it might be,
1 2 3
4 5 6
7 8 9
And I want the combinations, 3 at time, like -
1, 4, 7
1, 4, 8
1, 4, 9
1, 5, 7
.
.
1, 6, 7
I've tried the following recursive procedure in Python 3:
def getKeys(keychars):
temp = []
create(keychars, 0, 0, temp)
def create(kc, i, j, temp):
if i == 3:
print(temp)
del temp[-1]
return
temp.append(kc[i][j])
for j in range(3):
create(kc, i+1, j, temp)
def main():
keychars = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
getKeys(keychars)
main()
(If running the snippet gives you an error, please try in an IDE.)
But the problem is that, I'm not sure how or when to clear the temp variable. The outputs are like - 1,4,7 1,4,7,8 1,4,7,8,9 1,4,7,8,9,5
That is the temp variable retains the previous results. Any help would be appreciated.

Splitting a heap at given key

Given a list: [10, 4, 9, 3, 2, 5, 8, 1, 0]
that has the heap structure of below:
8
9
5
10
2
4
0
3
1
What is a good algorithm in python to get [4,3,2,1,0] which is basically the left child of 10.
parent is (index+1)//2
left child is 2i+1, right child is 2i+2
L = [10, 4, 9, 3, 2, 5, 8, 1, 0]
index = 1
newheap = []
newheap.append(L[index])
leftc = 2 * index + 1
rightc = 2 * index + 2
while(leftc < len(L)):
newheap.append(L[leftc])
if(rightc < len(L)):
newheap.append(L[rightc])
leftc = 2 * leftc + 1
rightc = 2 * rightc + 2
print(newheap)
which outputs
[4,3,2,1]
but I need [4,3,2,1, 0], so not what I wanted. I started the index at 1 which points to 4.
Would recursion be better? Not sure how to go about this.
You can try something like that :
L = [10, 4, 9, 3, 2, 5, 8, 1, 0]
index = 0
offset = 1
newheap = []
while index < len(L):
index += offset
for i in range(offset):
if index+i == len(L):
break
newheap += [L[index+i]]
offset = 2 * offset
print(newheap)

Reducing execution time Python

given that I have a list like this (river discharge tree):
String type (11 elements).
From;To
1;2
2;3
5;4
3;4
4;-999
9;6
6;5
10;7
8;7
7;5
If you imagine it as a tree, it should be like (direction from top to bottom):
1 9 8 10
| | \/
2 6 7
| \ /
3 5
| /
4
|
I just want to expand the list so I would have all the combinations like
From;To
1;2
2;3
5;4
3;4
4;-999
9;6
6;5
10;7
8;7
7;5
1;3
1;4
6;4
9;4
9;5
7;4
8:4
8:5
10:5
10:4
There must be connection in the tree and the order must be from top to bottom.
What is the best way to do this?
I wrote a code for this but this would take me about 6 days of executing for 6000 rows.
should_restart = False
for b in range(1, lengthchange):
row1 = str(tree[b])
position2 = row1.find(delimeter)
position3 = row1.find(end)
from1 = (row1[0:position2])
to1 = row1[position2+1:position3]
for c in range(1, lengthchange):
row2 = str(tree[c])
position4 = row2.find(delimeter)
position5 = row2.find(end)
from2 = (row2[0:position4])
to2 = row2[position4+1:position5]
if to1 == from2 and not to2 == "-999":
append1 = str(from1)+";"+str(to2)+"\n"
seen = set(tree)
if append1 not in seen:
seen.add(append1)
tree.append(append1)
should_restart = True
count_test = count_test+1
print(count_test)
lengthchange = len(tree)
Could you check my code and give me some advices?
Thank you very much!
So the key to doing this efficiently is ensuring we don't have to revisit nodes over and over again. We can do this by starting with the output and working our way back:
crivers = rivers[:] # copy the rivers list, as this process is destructive
ckeys = set(river.split(";")[0] for river in crivers) # make a set for O(1) lookup
result = {}
while crivers:
for river in crivers[:]:
key, value = river.split(";")
if value in ckeys:
continue # skip rivers that are flowing into unprocessed rivers
result[int(key)] = [int(value)] + result.get(int(value), [])
ckeys.remove(key)
crivers.remove(river)
If the rivers list is sorted properly, this is O(n), if it's not sorted (or, in the worst case, reverse sorted), it's O(n**2). "Sorted properly", in this case, means they are sorted from root to leaf in our upside down tree... as our processing order is: 4, 5, 3, 6, 7, 2, 9, 10, 8, 1
The final result is:
{1: [2, 3, 4, -999],
2: [3, 4, -999],
3: [4, -999],
4: [-999],
5: [4, -999],
6: [5, 4, -999],
7: [5, 4, -999],
8: [7, 5, 4, -999],
9: [6, 5, 4, -999],
10: [7, 5, 4, -999]}
Which can be converted to your final format via:
fmt_lst = []
for key in result:
for val in result[key]:
fmt_lst.append("%s;%s" % (key, val))
['1;2', '1;3', '1;4', '1;-999',
'2;3', '2;4', '2;-999',
'3;4', '3;-999',
'4;-999',
'5;4', '5;-999',
'6;5', '6;4', '6;-999',
'7;5', '7;4', '7;-999',
'8;7', '8;5', '8;4', '8;-999',
'9;6', '9;5', '9;4', '9;-999',
'10;7', '10;5', '10;4', '10;-999']

Python - Recursive Date Sorting Algorithm

My assignment states that I get a list of birthdays and that I have to arrange them chronologically. I must write my own, so I can't use Python's predefined functions, such this:
import datetime
d = ['09-2012', '04-2007', '11-2012', '05-2013', '12-2006', '05-2006', '08-2007']
sorted(d, key=lambda x: datetime.datetime.strptime(x, '%m-%Y'))
Here is what I'm thinking of doing.
Step 1: Red all dates and put them into a list dd/mm/yyyy
date_list = [[1,2,1991],[2,1,1991],[3,4,1992],[5,6,1993],[4,5,1992],[8,5,1993]]
For better visualization, I will rearrange them like so:
1 / 2 / 1991
2 / 1 / 1991
3 / 4 / 1992
5 / 6 / 1993
4 / 5 / 1992
8 / 5 / 1993
Step 2: Sort the entire list by year (col 2)
1 / 2 / 1991
2 / 1 / 1991
3 / 4 / 1992
4 / 5 / 1992
5 / 6 / 1993
8 / 5 / 1993
Step 3: For each unique year, sort that sublist by the column near it (col 1)
2 / 1 / 1991
1 / 2 / 1991
3 / 4 / 1992
4 / 5 / 1992
8 / 5 / 1993
5 / 6 / 1993
Step 4: Do the same for the sublist of each unique month of that year (col 0)
1 / 1 / 1991
2 / 2 / 1991
3 / 4 / 1992
4 / 5 / 1992
8 / 5 / 1993
5 / 6 / 1993
And that should be it. I've used the following functions to try and it:
#Sorts the sublist date_list[position..position+length] by the col
def insertion(date_list, position, length, col):
for i in range (position + 1, pozition + lenght - 1):
aux = date_list[i]
j = i - 1
while j >= 0 and aux[col] < date_list[j][col]:
date_list[j+1] = date_list[j]
j -= 1
date_list[j+1] = aux
return date_list
def sortDateList(date_list, position, lenght, col):
# Nothing to do here
if col < 0:
return date_list
# If it's the first sort, sort everything
if col == 2:
date_list = insertion(date_list, 0, len(date_list), 2)
for i in range (position, position + length - 1):
# Divides the list into sublists based on the column
if date_list[i][col] == date_list[i][col]:
length += 1
else:
# Sorts the sublist, then sorts it after the previous column in it
date_list = insertion(date_list, position, length, col)
date_list = sortDateList(date_list, position, length, col - 1)
position += length
length = 1
date_list = insertion(date_list, position, length, col)
return date_list
I'm not sure exactly what the problem is here, I'm pretty sure it's something really basic that slipped my mind, and I can't keep track of recursion in my brain that well. It gives me some index out of bound errors and such.
For debug, I've printed out info as such:
col position position + length
date_list[position:position+length] before insertion()
date_list[position:position+length] after insertion()
Here is what the console gives me:
2 0 6
2 0 7
[[1, 2, 1991], [2, 1, 1991], [3, 4, 1992], [4, 5, 1992], [5, 6, 1993], [8, 5, 1993]]
[[1, 2, 1991], [2, 1, 1991], [3, 4, 1992], [4, 5, 1992], [5, 6, 1993], [8, 5, 1993]]
1 0 7
[[1, 2, 1991], [2, 1, 1991], [3, 4, 1992], [4, 5, 1992], [5, 6, 1993], [8, 5, 1993]]
[[2, 1, 1991], [1, 2, 1991], [3, 4, 1992], [4, 5, 1992], [8, 5, 1993], [5, 6, 1993]]
0 0 7
[[2, 1, 1991], [1, 2, 1991], [3, 4, 1992], [4, 5, 1992], [8, 5, 1993], [5, 6, 1993]]
[[1, 2, 1991], [2, 1, 1991], [3, 4, 1992], [4, 5, 1992], [5, 6, 1993], [8, 5, 1993]]
0 7 8
[]
[]
0 8 9
[]
[]
0 9 10
[]
[]
0 10 11
[]
[]
0 11 12
Any help is greatly appreciated!
Just write a simple sort algorithm and a compare function, such as this:
date_list = [[1,2,1991],[2,1,1991],[3,4,1992],[5,6,1993],[4,5,1992],[8,5,1993]]
# first compare years, if equal compare months, if equal compare days
def compare(date1,date2):
if date1[2] != date2[2]:
return date1[2]<date2[2]
if date1[1] != date2[1]:
return date1[1]<date2[1]
return date1[0] < date2[0]
for i in range(len(date_list)):
for j in range(i+1,len(date_list)):
if not compare(date_list[i],date_list[j]):
date_list[i],date_list[j] = date_list[j],date_list[i]
print date_list
The time complexity is O(n^2) but you can improve it by using a more efficient sort algorithm.
If you convert it to YYYYMMDD string format you can easily sort it. Try to sort string concatinated data instead of spiting it to 3 part.

Categories