Working on the google foo-bar challenges and I am stuck on one failing test case (which is a hidden one - so I can't directly see what the problem is)
basically the test is an implementation of a maze solver with a single breakable wall.
I'm doing a modified a* search - with a Boolean flag for paths that contain a broken wall, so that when it reaches the second wall (along a path with a broken wall) it skips it for that path.
I've gone over this code and I can't seem to see the error (if there even is one - at this point I'm almost convinced the test case is somehow wrong)
the parameters:
given a grid of height x,y filled with zero or 1, representing spaces and walls respectively: find the shortest path if you can break exactly 1 wall (if needed)
an example:
[
[0,1,0,0,0,1,0,0,0,0,0]
[0,0,0,1,0,0,1,0,1,1,0]
[1,1,1,1,1,0,1,0,1,0,1]
[0,0,0,0,0,0,0,0,1,1,0]
]
22 is the shortest path breaking 1 wall.
I want a pointer in the right direction: I feel like whatever I'm missing is trivial.
below is the code.
from math import sqrt, ceil
cardinal_moves=[(0,1), (0,-1), (1,0), (-1,0)]
class Node:
def __init__(self, pos ,parent =None):
self.parent = parent
self.pos = pos
self.g = 0
self.h = 0
self.f = 0
self.wall_broken = False
def __eq__(self, other):
return ((self.pos == other.pos) and (self.wall_broken == other.wall_broken))
def update_heuristic(self,parent,end):
self.g = parent.g + 1
self.h = ceil(sqrt((end.pos[0] - self.pos[0])**2 + (end.pos[1] - self.pos[1])**2))
self.f = self.g + self.h
def not_inside_maze(pos,maze):
return pos[0] < 0 or pos[0] >= len(maze) or pos[1] < 0 or pos[1] >= len(maze[0])
def astar_with_1_breakable_wall(maze):
start_pos = (0,0)
end_pos = (len(maze)-1, len(maze[0])-1)
start = Node(start_pos)
end = Node(end_pos)
not_visted = []
visited = []
not_visted.append(start)
while not_visted:
current_node = not_visted[0]
for node in not_visted:
if current_node.f > node.f:
current_node = node
not_visted.remove(current_node)
visited.append(current_node)
if current_node.pos == end.pos:
temp = current_node
path = []
while temp:
path.append(temp.pos)
temp = temp.parent
return path[::-1]
children = []
for position in cardinal_moves:
new_pos = (current_node.pos[0] + position[0], current_node.pos[1] + position[1])
if not_inside_maze(new_pos,maze):
continue
if maze[new_pos[0]][new_pos[1]] == 1:
if current_node.wall_broken:
continue
else:
check = Node(new_pos,current_node)
check.wall_broken = True
already_visited = False
for node in visited:
if check == node:
already_visited = True
break
if not already_visited:
children.append(check)
continue
already_visited = False
check = Node(new_pos,current_node)
check.wall_broken = current_node.wall_broken
for node in visited:
if check == node:
already_visited = True
break
if already_visited:
continue
children.append(check)
for child in children:
child.update_heuristic(current_node,end)
for open_node in not_visted:
if open_node == child:
if open_node.g > child.g:
idx = not_visted.index(open_node)
not_visted[idx] = child
continue
else:
continue
not_visted.append(child)
def shortest_path(maze):
if (astar_with_1_breakable_wall(maze)):
return len(astar_with_1_breakable_wall(maze))
else:
return -1
but every check I make on my machine says this is correct:
#imports added
import sys
#then added this below the maze solver
test = [
[0,1,0,0,0,1,0,0,0,0,0],
[0,0,0,1,0,0,1,0,1,1,0],
[1,1,1,1,1,0,1,0,1,0,1],
[0,0,0,0,0,0,0,0,1,1,0],
]
test2=[
[0,1,0,0,0,0,1,0,0,0,0],
[0,1,0,1,1,0,1,0,1,0,0],
[0,0,0,1,0,0,1,0,1,0,0],
[1,1,1,1,0,1,1,0,1,0,1],
[0,0,0,0,0,0,0,0,1,0,1],
]
print("first test")
print(shortest_path(test))
print("second test")
print(shortest_path(test))
#both of these tests give the correct result
def generate_matrix(h,w,n):
sequence = "{0:b}".format(n).zfill(h*w)
maze =[]
if(sequence[0]=="1" or sequence[len(sequence)-1]=="1"):
return -1
i=0
for y in range(h):
maze.append([])
for x in range(w):
maze[y].append(int(sequence[i]))
i=i+1
return(maze)
for i in range(20):
for j in range(20):
if(i < 6 or j <6):
continue
shortest=j+i
for k in range(2**(i*j)):
if not k%2==0:
continue
if k> 2**(i*j-1):
continue
maze = generate_matrix(i,j,k)
if(not maze == -1):
path = astar_with_1_breakable_wall(maze)
res = shortest_path(maze)
if(res > shortest):
print("\n",res, "shortest was ", shortest)
for index,line in enumerate(maze):
for indx,cell in enumerate(line):
if ((index,indx) in path):
print("\033[94m"+str(cell),end="")
else:
print("\033[92m"+str(cell),end="")
print("\n")
for point in path:
print(point ," ", end="")
print("\n\n")
else:
sys.stdout.write("\r")
the above code makes every matrix possibility, and prints (with highlighting the path) the matrix if the path is longer than the base case.
every result is as I expect - returning the correct shortest path... I have not found the issue with why only the 3rd test case fails...
the answer was something specific to python 2.7.13 apparently - it took a bit of debugging to figure it out, but the not_visited.remove(current_node) was the thing that was failing in certain cases.
I have a practice question that requires me to generate x number of alternating substrings, namely "#-" & "#--" using both recursion as well as iteration. Eg.string_iteration(3) generates "#-#--#-".
I have successfully implemented the solution for the iterative method,
but I'm having trouble getting started on the recursive method. How can I proceed?
Iterative method
def string_iteration(x):
odd_block = '#-'
even_block = '#--'
current_block = ''
if x == 0:
return ''
else:
for i in range(1,x+1):
if i % 2 != 0:
current_block += odd_block
elif i % 2 == 0:
current_block += even_block
i += 1
return current_block
For recursion, you almost always just need a base case and everything else. Here, your base case it pretty simple — when x < 1, you can return an empty string:
if x < 1:
return ''
After than you just need to return the block + the result of string_iteration(x-1). After than it's just a matter of deciding which block to choose. For example:
def string_iteration(x):
# base case
if x < 1:
return ''
blocks = ('#--', '#-')
# recursion
return string_iteration(x-1) + blocks[x % 2]
string_iteration(5)
# '#-#--#-#--#-'
This boils down to
string_iteration(1) + string_iteration(2) ... string_iteration(x)
The other answer doesn't give the same result as your iterative method. If you always want it to start with the odd block, you should add the block on the right of the recursive call instead of the left:
def string_recursion(x):
odd_block = '#-'
even_block = '#--'
if x == 0:
return ''
if x % 2 != 0:
return string_recursion(x - 1) + odd_block
elif x % 2 == 0:
return string_recursion(x - 1) + even_block
For recursive solution, you need a base case and calling the function again with some other value so that at the end you will have the desired output. Here, we can break this problem recursively like - string_recursive(x) = string_recursive(x-1) + string_recursive(x-2) + ... + string_recursive(1).
def string_recursion(x, parity):
final_str = ''
if x == 0:
return ''
if parity == -1: # when parity -1 we will add odd block
final_str += odd_block
elif parity == 1:
final_str += even_block
parity *= -1 # flip the parity every time
final_str += string_recursion(x-1, parity)
return final_str
odd_block = '#-'
even_block = '#--'
print(string_recursion(3, -1)) # for x=1 case we have odd parity, hence -1
# Output: #-#--#-
I'm now learning about software engineering and as a part of my studies i had to implement a dispatch function for a mutable pair type.
Here is my implementation:
def make_mutable_pair(*args):
x = None
y = None
numargs = len(args)
if (numargs == 1):
x = args[0]
elif (numargs == 2):
x = args[0]
y = args[1]
elif (numargs >= 3):
raise Exception("Too many arguements!")
else:
pass
def dispatch(msg, i=None, v=None):
if(msg == 'get'):
return get_item(i)
elif(msg == 'set'):
return set_item(i,v)
def get_item(i):
if(i == 0):
return x
elif(i == 1):
return y
else:
raise Exception("Wrong index!")
def set_item(i,v):
nonlocal x,y
if(i == 0):
x = v
elif(i == 1):
y = v
else:
raise Exception("Wrong index!")
return dispatch
I understand everything pretty well but there is something that is against everything i know in software and coding, the 'make_mutable_pair' is basically a function, here is some test i did:
test = make_mutable_pair(5,10)
print('({},{})'.format(test('get',0),test('get',1)))
test('set',0,3)
test('set',1,6)
print('({},{})'.format(test('get',0),test('get',1)))
As expected, the output will be:
(5,10)
(3,6)
What i don't understand is how the x and y are saved...
I mean from what i know, when i'm done with a function all the data in the stack memory will be deleted, and in the next call to that function i'm starting fresh.
In this case i called the function with some data for x and y, and later i changed it, and called it again, and it's still saved...
I will love to hear some explanation about it... Thanks!
I'm trying to make a program that checks to make sure that the text is balanced in terms of brackets (so (),[],{} and not (),[,{}). I can get it to work when it is balanced, and when it is not balanced when it is missing a closing bracket (like the previous example). What I can't get it to do is come back as unbalanced if I'm missing a bracket on the left ((),],{}). I know it's trying to pop from an empty stack but can't figure out how to counter act that. My teacher has it in her Stack class that if it's trying to pop to an empty stack, then an exception is raised automatically, and I can't change her class, which is the problem, otherwise I just would have made that as false anyways and not be in this mess. So does anyone have any ideas of how to do it before that error is raised?
Here's the code:
from ListNode import *
from Stack import Stack
ch = 0
s = 0
check = True
def parbalance():
stack = Stack()
user = input("Enter a file name: ")
file = open(user)
lines = file.readlines()
for char in lines:
for ch in char:
#print(ch)
if ch in "([{":
stack.push(ch)
if ch in ")]}":
popStack = stack.pop()
if ch == "(" and popStack != ")":
check = False
elif ch == "[" and popStack != "]":
check = False
elif ch == "{" and popStack != "}":
check = False
if stack.is_empty():
check = True
print("true")
else:
check = False
print("false")
parbalance()
In case it helps, here's her Stack class:
from ListNode import *
class Stack:
def __init__(self):
self.top = None
def push(self, item):
temp = ListNode(item)
temp.set_link(self.top)
self.top = temp
#self.top = ListNode(item, self.top)
def pop(self):
if self.top == None:
raise Exception("Trying to pop from an empty stack")
temp = self.top
self.top = temp.get_link()
return temp.get_item()
def destroy(self):
self.top = None
def is_full(self):
return False
def is_empty(self):
return self.top == None
Use try to capture an error:
try:
popStack = stack.pop()
except:
# Stack is empty, set failure and bail from the function.
check = False
return
Also, note that your tests are backwards:
if ch == "(" and popStack != ")":
ch is the closing bracket and popStack is the opening bracket, so this should be:
if ch == ")" and popStack != "(":
Without this change, your code will recognize the string "(}" as balanced.
As a side note, consider returning True or False from the function instead of setting a global variable. Using global variables to return values from functions is not a good idea.
You can put the code into a try except block. Once you catch an exception you know the stack underflows. Consequently there must be an unbalanced paranthesis.
By the way: I would not use the lengthy if else chain. Instead I would work it along the following lines:
pars = {'(':')', '[':']', '{':'}'}
....
try:
...
if ch in pars.keys():
stack.push(ch)
if ch in pars.values():
if ch != pars[stack.pop()]:
return False;
except:
return False;
return stack.is_empty()
That way you could easily add other bracket symbols if required.