Reputation: 177
it doesn't matter what the input is, the output is always 0, like the global variables NEVER change. please help me I'm going crazy because i don't see any reason for this to show only 0
x=0
y=0
import math
import operator
def move(steps,op_func,z):
if z == "x":
global x
x = op_func(x, int(steps))
else:
global y
y = op_func(y, int(steps))
def main():
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
while user_direct != " ":
steps=user_direct[-1]
direction=user_direct[:-1]
directions = {"UP":move(steps,operator.add,"x"),
"DOWN":move(steps,operator.sub,"x"),
"RIGHT":move(steps,operator.add,"y"),
"LEFT":move(steps,operator.sub,"y")}
directions[direction.replace(" ","")]
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
global x
global y
distance=math.sqrt(x**2+y**2)
print distance
main()
Upvotes: 1
Views: 829
Reputation: 21220
You are doing these things wrong:
Additionally, storing that information globally isn't really what you want to be doing, but rather storing it within the scope of the while loop.
Lets look at what your dictionary definition is doing:
directions = {"UP":move(steps,operator.add,"x"),
"DOWN":move(steps,operator.sub,"x"),
"RIGHT":move(steps,operator.add,"y"),
"LEFT":move(steps,operator.sub,"y")}
Each of these assignments calls move with the appropriate values, and sets them to the value. However, move()
returns None
because there is no return
statement set for those: the globals are updated inside the function. So after one while
loop, your directions
array looks like this:
{"UP": None, "DOWN": None, "RIGHT": None, "LEFT": None}
And your x
and y
global values have been incremented and decremented once each. You can prove this by replacing your move
function with the following:
def move(steps,op_func,z):
if z == "x":
global x
x = op_func(x, int(steps))
print("x is now {}".format(x))
else:
global y
y = op_func(y, int(steps))
print("y is now {}".format(y))
In the REPL this is what you see:
>>> y= 0
>>> x= 0
>>> steps = 1
>>> directions = {"UP":move(steps,operator.add,"x"),
>>> "DOWN":move(steps,operator.sub,"x"),
... "RIGHT":move(steps,operator.add,"y"),
... "LEFT":move(steps,operator.sub,"y")}
... x is now 1
x is now 0
y is now 1
y is now 0
However, partials can help:
>>> f = partial(move, op_func=operator.add, z="x")
>>> f(1)
>>> x is now 1
Using the above, you want do define your directions
map like so:
directions = {"UP":partial(move, op_func=operator.add, z="x"),
"DOWN":partial(move, op_func=operator.sub, z="x"),
"RIGHT":partial(move, op_func=operator.add, z="y"),
"LEFT":partial(move, op_func=operator.sub, z="y")}
What this does is replace each "key" in your dictionary with a "partial function". A partial function as some of it's parameters 'filled in', and later on you can call that function with only the remaining value. Formally:
partial(f(a, b, c), b, c) -> g(a)
Whenever you call g
, b
, and c
will be consistently defined for a function call to f
.
Now all you have to do is change this line:
directions[direction.replace(" ","")]
To this:
move_func = directions[direction.replace(" ","")]
move_func(steps)
Re-writing and cleaning up the program a bit yields:
import math
import operator
from functools import partial
# Always do imports first then global vars
x=0
y=0
def move(steps,op_func,z):
if z == "x":
global x
x = op_func(x, int(steps))
else:
global y
y = op_func(y, int(steps))
def main():
# We only need to define this once
directions = {"UP":partial(move, op_func=operator.add, z="x"),
"DOWN":partial(move, op_func=operator.sub, z="x"),
"RIGHT":partial(move, op_func=operator.add, z="y"),
"LEFT":partial(move, op_func=operator.sub, z="y")}
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
while user_direct != " ":
steps=user_direct[-1]
direction=user_direct[:-1].replace(" ","")
move_func = directions[direction]
move_func(steps)
user_direct=raw_input("Enter the way that you want the plane to move and how many steps you want it to move\n")
global x
global y
distance=math.sqrt(x**2+y**2)
print distance
main()
Upvotes: 1
Reputation: 5515
As my comment says, your dict initialization is actually running those functions and setting values as the return values (NoneType
). Do something like this instead.
1.) Initiate your dict OUTSIDE your while loop because you dont need to reinitialize every time.
2.) change it so the value is a tuple of your parameters like:
directions = {"UP":(operator.add,"x"),
"DOWN":(operator.sub,"x"),
"RIGHT":(operator.add,"y"),
"LEFT":(operator.sub,"y")}
note that the dict
does not include steps because you are going to use that as a variable for every call.
3.) change your function call by using this line:
move(steps,directions[direction][0],directions[direction][1])
in place of your current dict init/dict call.
The problem with this is that if your command is NOT a valid command, it will cause errors so I would put everything in a Try block like:
try:
move(steps,directions[direction][0],directions[direction][1])
except KeyError:
print('Not a valid key, try again')
else:
#here is where you put the math code you do to edit the globals
Upvotes: 2