python method breaks code - python

i have written some code that i want to convert into something i can import instead of it being used as the main.
floorMap = [[000,000,000,000,000,999,999,999,999,999],
[000,000,999,000,999,000,000,000,999,999],
[000,000,999,000,999,000,000,000,999,999],
[000,000,000,000,999,000,000,000,999,999],
[999,000,000,000,999,000,999,999,999,999],
[999,000,000,000,000,000,999,000,000,999],
[999,000,000,000,999,999,999,000,000,999],
[999,000,999,000,000,000,999,000,000,999],
[999,000,999,999,999,000,000,000,000,999],
[999,999,999,999,999,999,999,999,000,000]]
currentNum=0
wall=999
uncalculated=000
robotX=0
robotY=0
goalX=9
goalY=9
floorMap[goalY][goalX]=1
def changeSurroundings(X, Y):
#left
if(floorMap[X-1][Y]==uncalculated and X > 0):
floorMap[X-1][Y]=currentNum
#right
if(X < len(floorMap[0])-1 and floorMap[X+1][Y]==uncalculated):
floorMap[X+1][Y]=currentNum
#up
if(floorMap[X][Y-1]==uncalculated and Y > 0):
floorMap[X][Y-1]=currentNum
#down
if(Y < len(floorMap)-1 and floorMap[X][Y+1]==uncalculated):
floorMap[X][Y+1]=currentNum
def printMap():
i=0
floorMap[goalY][goalX]='G'
floorMap[robotY][robotX]='R'
while(i<len(floorMap)):
print floorMap[i]
print ""
i+=1
print ""
print ""
#------------------MOST IMPORTANT CHUNK OF CODE--------------
while(floorMap[robotY][robotX]==uncalculated):
x=0
while(x<len(floorMap[0])):
y=0
while(y<len(floorMap)):
if(floorMap[x][y] > uncalculated and floorMap[x][y] < wall):
currentNum=floorMap[x][y]+1
changeSurroundings(x,y)
y+=1
x+=1
printMap()
my problem is that whenever i try to put the most important chunk of code at the bottom into a method like so;
def calcMap():
while(floorMap[robotY][robotX]==uncalculated):
x=0
while(x<len(floorMap[0])):
y=0
while(y<len(floorMap)):
if(floorMap[x][y] > uncalculated and floorMap[x][y] < wall):
currentNum=floorMap[x][y]+1
changeSurroundings(x,y)
y+=1
x+=1
printMap()
it breaks my code. why? I dont seem to get any errors, it just gets stuck on one of the nested loops. i dont see any reason it should be doing this, but you guys probably will ;)
Thanks, Logan

Your problem comes from your global variables, in particular currentNum. This is basically what you're doing :
current = 0
def f():
current = 1
g()
def g():
print(current)
f() # Output: 0
What you need to do is:
current = 0
def f():
global current
current = 1
g()
def g():
print(current)
f() # Output: 1
Or better :
def f():
current = 1
g(current)
def g(current):
print(current)
f() # Output: 1
Also, you should consider using a more pythonic synthax for your calcMap function, something like :
def calc_map():
while floor_map[robot_x][robot_y] == uncalculated :
for x,array in enumerate(floor_map):
for y,element in enumerate(array):
if uncalculated < element < wall:
current_num = element + 1
change_surroundings(x, y, current_num)

Related

List append MemoryError

So I have this piece of code I'm trying to make generate level layouts for a grid of rooms. The first time through the mainloop it runs perfectly it runs and does exactly what it should but the second time through it pauses just after the first print error and gives me the attached error and I cant figure out what's wrong with it.
(the y/n prompt is only to slow down the program so I can see what's happening)
userInput = ""
roomChance = 0.5
world = [[0,0,0], \
[0,1,0], \
[0,0,0]]
possibleWorld = []
newX = []
def check_neighbours(xy):
possibleWorld.clear()
yLoops = 0
for y in xy:
print(" y:", y)
xLoops = 0
for x in y:
print(" x:", x)
#Check left cell
if(xLoops-1 >= 0):
if(y[xLoops-1] == 1):
possibleWorld.append([xLoops, yLoops])
print("x-1:", y[xLoops-1])
#Check right cell
if(xLoops+1 < len(y)):
if(y[xLoops+1] == 1):
possibleWorld.append([xLoops, yLoops])
print("x+1:", y[xLoops+1])
#Check above cell
if(yLoops-1 >= 0):
if(xy[yLoops-1][xLoops] == 1):
possibleWorld.append([xLoops, yLoops])
print("y-1:", xy[yLoops-1][xLoops])
#Check above cell
if(yLoops+1 < len(xy)):
if(xy[yLoops+1][xLoops] == 1):
possibleWorld.append([xLoops, yLoops])
print("y+1:", xy[yLoops+1][xLoops])
print("\n")
xLoops += 1
yLoops += 1
def assign_neighbours(possible, world, chance):
for i in possible:
if(random.random() < chance):
world[i[1]][i[0]] = 1
possible.clear()
def border_expand(world):
for x in world[0]:
if(x == 1):
for i in world[0]:
newX.append(0)
world.insert(0, newX)
newX.clear
break
def print_world(world):
for y in world:
print(y)
# ==================== Mainloop ====================
while(True):
userInput = input(print("Generate Level? Y/N?"))
check_neighbours(world)
print(possibleWorld)
assign_neighbours(possibleWorld, world, roomChance)
print_world(world)
border_expand(world)
print("\n")
print_world(world)
File "C:\Users\Potato\Desktop\Level gen_query.py", line 96, in <module>
border_expand(world)
File "C:\Users\Potato\Desktop\Level gen_query.py", line 67, in border_expand
newX.append(0)
MemoryError```
You're not calling newX.clear, so it is continually growing. When you run world.insert(0, newX) you are inserting a reference to newX into world[0], even if you did call newX.clear() you would not get the behaviour you want as the first element in world would be empty.
You need to create a new list on every call to border_expand so that it is a new list every time
def border_expand(world):
newX = []
for x in world[0]:
if(x == 1):
for i in world[0]:
newX.append(0)
world.insert(0, newX)
break

local variable 'n' referenced before assignment. Closures

def fibonacci_closure(n):
def fibonaci():
if n == 0: """in this line error occured idk why because in watches i see n=4"""
return 0
elif n == 1 or n == 2:
return 1
else:
i = 1
j = 1
tmp = 1
while n != 2:
n -=1
tmp = i
i = j + i
j = tmp
return i
return fibonaci
a = fibonacci_closure(4)
a()
Task:
Return a closure that will generate elements of the Fibonacci sequence when called repeatedly.
Example:
g = fibonacci_closure()
g() # 1
g() # 1
g() # 2
g() # 3
UnboundLocalError: local variable 'n' referenced before assignment
Fibonacci numbers are a typical example for generators. It's only irritating why the function should return a function instead of a generator.
def fibonacci_closure():
def fibonacci():
i = j = 1
while True:
yield i
i, j = j, i + j
return fibonacci().__next__
The task you are trying to accomplish could be done by creating a class. (Or you could look into creating a 'generator' object, which is its own separate thing.)
What you need in order to preserve the value of n from one call to the next is some sort of global variable. Global variables in Python are possible, but are bad practice. The same thing can be accomplished from within a class where n is stored and encapsulated within that class.
Have a look at the changes I made and see if the function now works as you intended. Cheers!
class fibonacci_closure():
def __init__(self):
self.n = 0
def fibonaci(self):
if self.n == 0:
self.n+=1
print(0)
elif self.n == 1 or self.n == 2:
self.n+=1
print(1)
else:
i = 1
j = 1
tmp = 1
hold = self.n
while hold != 2:
hold -=1
tmp = i
i = j + i
j = tmp
self.n+=1
print(i)

Cannot get this code to work, simple Python else if statement

When I run the code below I keep getting a syntax error and it is highlighted where shown.
sf_population, sf_area = 864816, 231.89
rio_population, rio_area = 6453682, 486.5
sf_area = (int(sf_area))
rio_area = (int(rio_area))
def x= sf_population/sf_area
def y= rio_population/rio_area
if x<y:
print"True"
if x>y:
print"False"
Working example:
sf_population, sf_area = 864816, 231.89
rio_population, rio_area = 6453682, 486.5
sf_area = int(sf_area)
rio_area = int(rio_area)
x = sf_population/sf_area
y = rio_population/rio_area
if x < y:
print"True"
if x > y:
print"False"
def is used in python to define functions, not variables. To set the value of x to sf_population/sf_area simply drop the def in lines 5 and 6.
sf_population, sf_area = 864816, 231.89
rio_population, rio_area = 6453682, 486.5
sf_area = (int(sf_area))
rio_area = (int(rio_area))
x = sf_population/sf_area
y = rio_population/rio_area
if x<y:
print "True"
if x>y:
print "False"
Unless you want to define a function, there is no need for def
Beside of this, consider using elif for the second condition
if x<y:
print "True"
elif x>y:
print "False"

How is my variable not defined?

Currently, what I have is
ntries = 0
def test_guess(code,guess):
if guess == code:
return True
ntries += 1
else:
return False
blackpegs = 0
whitepegs = 0
code_remainder = ''
guess_remainder = ''
ntries += 1
for x, y in zip(code,guess):
if x==y:
blackpegs += 1
elif not x==y:
code_remainder += x
guess_remainder += y
for i in guess_remainder:
if code_remander.find(i) != -1: #if i is found in the remainder of the code
whitepegs += 1
code_remainder = code_remainder.replace(i, 'X', 1)
return code_remainder
return guess_remainder
return blackpegs
return whitepegs
Right below, I have
if test_guess(code,guess)==True:
print 'You won!"
elif test_guess(code,guess)==False:
print 'Not quite. You get',blackpegs,'black pegs,',whitepegs,'white pegs.'
blackpegs in my final print statement keeps coming up as undefined. Why is it not set to be equal to the blackpegs counter?
if guess == code:
return True
ntries += 1
if your guess == code, then return true, next step can't be executed!
You can only have one return statement.
return code_reminder
Causes the function to immediately exit. You will want to do something like
return code_remainder, guess_remainder, blackpegs, whitepegs
and then when you call the function, use:
code_remainder, guess_remainder, blackpegs, whitepegs = test_guess(code,guess)
General Tip:
Variables/references declared within a function only exist within that function. You will need to explicitly return those variables/references if you want to use them outside of the function. Of course there are also some exceptions to this rule, but it is best that you stick to this method for now.
blackpegs doesn't have a value unless the else statement is reached. i.e. if guess == code, blackpeg is not defined.
It needs to be set to zero before the if else statements or otherwise addressed prior to being called in the return statement.

Loop function in python

Could any one tell me whats wrong in the following code? (In Python 2.7)
def echo(msg):
print msg
def loop(x,y):
a = 0
while (a < x + 1):
a = a + 1
y
loop(5,echo("ok"))
I should be getting "ok" five times, but instead I just get "ok" once, no matter what
amount I set x to be.
echo("ok") is being evaluated before passing it to the function maybe, this is what you really want
def loop(x,y, *args):
a = 0
while (a < x + 1):
a = a + 1
y(*args)
def echo(msg):
print msg
loop(5,echo, "ok")
It's because you're evaluating echo("ok") when you call loop.
What you probably want to do is call echo("ok") on each iteration.
def echo(msg):
print msg
def call_echo_ok():
echo("ok")
def loop(x,y):
a = 0
while (a < x + 1):
a = a + 1
y()
loop(5, call_echo_ok)
Note that this can be done more concisely with lambda functions.
def echo(msg):
print msg
def loop(x,y):
a = 0
while (a < x + 1):
a = a + 1
y()
loop(5, lambda: echo('ok'))
You can try this:
def loop(times,message):
for i in range(times):
print message
loop(5,"Ok")

Categories