[Tutor] Livewires questions

Luke Paireepinart rabidpoobear at gmail.com
Thu Jul 26 06:42:58 CEST 2007


As promised, here's some comments on your code.

> from livewires import *
> begin_graphics()
> allow_moveables()
> def place_player():
>     global player_x
>     global player_y
>     global player_shape
>     player_y = random_between(0,47)
>     player_x = random_between(0,63)
>     player_shape = circle(10*player_x, 10*player_y, 5, filled=1)
>   
In general, you should try to avoid global usage like this.
You'd want to  have a player class, probably.
However, the way this tutorial is going, it seems like this is what it 
expects you to do.
It mentions classes further near the end of the tutorial, so don't worry 
about it.
for now, we'll just go with what you've got.
> def place_robot():
>     global robot_x
>     global robot_y
>     global robot_shape
>     robot_y = random_between(0,47)-0.5
>     robot_x = random_between(0,63)-0.5
>   
I'm not too clear why you're subtracting 0.5 here.
Doesn't this make the robot's center on the grid lines, rather than 
having the robot occupy a full square on the grid?
I guess that's the intended behavior, huh?
>     robot_shape = box(10*robot_x, 10*robot_y,10*robot_x+10,10*robot_y+10)
> def move_player():
>     while 1:
>         global player_x
>         global player_y
>   
>         if 't' in keys:
>             place_player()
>             break
>   
You can't reuse your place_player function here, because you put the 
initialization (the creation) of the graphics that represent the player 
_inside_ of the place_player function.  Well, technically you could, but 
it would be better instead to use move_to(player_shape, x, y) because 
this doesn't overwrite the old player_shape circle.
Also, will this work if the player presses "T"?
>         if '8' in keys:
>             move_to(player_shape,player_x*10 ,player_y*10 + 10)
>             player_y = player_y + 1
>             if player_y > 47:
>                 player_y = player_y -1
>             else:
>                 pass
>   
'if' statements don't have to have an 'else' clause.
else:
    pass
is just a waste of 2 lines.  'pass' does nothing, and since the 'else' 
is not required, you may as well leave it off.
>             break
>         if '7' in keys:
>             move_to(player_shape,player_x*10 - 10,player_y*10 +10)
>             player_x = player_x -1
>             player_y = player_y + 1
>             if player_x < 1 or player_y > 47:
>                 player_x = player_x+1
>                 player_y = player_y-1
>             else:
>                 pass
>             break
>         if '9' in keys:
>             move_to(player_shape,player_x*10 + 10,player_y*10 + 10)
>             player_x = player_x +1
>             player_y = player_y +1
>             if player_x > 63 or player_y >47:
>                 player_x = player_x -1
>                 player_y = player_y -1
>             else:
>                 pass
>             break
>         if '4' in keys:
>             move_to(player_shape,player_x*10 - 10,player_y*10)
>             player_x = player_x - 1
>             if player_x < 1 :
>                 player_x = player_x+1
>             else:
>                 pass
>             break
>         if '5' in keys:
>             break
>         if '6' in keys:
>             move_to(player_shape,player_x*10+10,player_y*10)
>             player_x = player_x + 1
>             if player_x > 63:
>                 player_x = player_x-1
>             else:
>                 pass
>             break
>         if '1' in keys:
>             move_to(player_shape,player_x*10-10,player_y*10-10)
>             player_x = player_x -1
>             player_y = player_y -1
>             if player_x < 1 or player_y < 1:
>                 player_x = player_x +1
>                 player_y = player_y +1
>             else:
>                 pass
>             break
>         if '2' in keys:
>             move_to(player_shape,player_x*10,player_y*10-10)
>             player_y = player_y -1
>             if player_y < 1:
>                 player_y = player_y+1
>             else:
>                 pass
>             break
>         if '3' in keys:
>             move_to(player_shape,player_x*10+10,player_y*10-10)
>             player_x = player_x +1
>             player_y = player_y -1
>             if player_x > 63 or player_y < 1:
>                 player_x = player_x -1
>                 player_y = player_y +1
>             else:
>                 pass
>             break
>   
This big block of movement code can be shortened into a few lines.
I am not sure how much python you know, so if any of this doesn't make 
sense, let me know.
Think of it this way:
step 1: look to see if they pressed a key that we want to process.
step 2: if so, figure out how we need to move the player (based on input)
step 3: check if this movement will move him out of bounds.
step 4: perform the movement.

Now that we have this pattern of evaluating our problem, we can reduce 
the code.
First, what kind of data structures are we going to need?
This is how I'm going to do it:
movement = {}
for x in range(3):
   for y in range(1,4):
        #this goes from 0 - 9, I was just too lazy to puzzle out a more 
efficient
        #way to do it.
        movement[str(3*x+y)] = [ [-1,0,1][y-1], [-1,0,1][x] ]

this code creates the following data structure:
 {'1': [-1, -1], '3': [1, -1], '2': [0, -1], '5': [0, 0], '4': [-1, 0], 
'7': [-1, 1], '6': [1, 0], '9': [1, 1], '8': [0, 1]}

You could just assign this to movement right off the bat, I just wanted 
to generate it programmatically.
(for some reason I thought it would take a long time to type out )

So now that we have that, we know what offset to add to the player position.

okay, so now that we have all our offset data, we can start.

#step 1: look to see if the key they pressed is one we want to process.
for key in keys:
   if key in movement.keys():
      #step 2: how much do we need to move the player?
      newx = player_x + movement[key][0]
      newy = player_y + movement[key][1]
      #step 3: check to see if movement will still be in bounds.
      if newx >= 0 and newx < 64:
         #step 4: perform the movement 
         player_x = newx
      if newy >= 0 and newy < 48:
         player_y = newy


So our new code is this:
movement = {'1': [-1, -1], '3': [1, -1], '2': [0, -1], '5': [0, 0],
                     '4': [-1, 0], '7': [-1, 1], '6': [1, 0], '9': [1, 
1], '8': [0, 1]}
for key in keys:
   if key in movement.keys():
      newx = player_x + movement[key][0]
      newy = player_y + movement[key][1]
      if newx >= 0 and newx < 64:   player_x = newx
      if newy >= 0 and newy < 48:   player_y = newy

As you can see, it's a bit shorter :)
> def move_robot():
>     while 1:
>         global robot_x
>         global robot_y
>         if robot_x + 0.5< player_x and robot_y +0.5< player_y:
>             move_to(robot_shape,robot_x*10+10,robot_y*10+10)
>             robot_x = robot_x +1
>             robot_y = robot_y +1
>             break
>         if robot_x+0.5< player_x and robot_y+0.5 == player_y:
>             move_to(robot_shape,robot_x*10+10,robot_y*10)
>             robot_x = robot_x +1
>             break
>         if robot_x+0.5 < player_x and robot_y+0.5 > player_y:
>             move_to(robot_shape,robot_x*10+10,robot_y*10-10)
>             robot_x = robot_x +1
>             robot_y = robot_y -1
>             break
>         if robot_x +0.5== player_x and robot_y +0.5> player_y:
>             move_to(robot_shape,robot_x*10,robot_y*10-10)
>             robot_y = robot_y -1
>             break
>         if robot_x+0.5> player_x and robot_y +0.5> player_y:
>             move_to(robot_shape,robot_x*10-10,robot_y*10-10)
>             robot_x = robot_x -1
>             robot_y = robot_y -1
>             break
>         if robot_x +0.5> player_x and robot_y +0.5== player_y:
>             move_to(robot_shape,robot_x*10-10,robot_y*10)
>             robot_x = robot_x -1
>             break
>         if robot_x +0.5> player_x and robot_y +0.5< player_y:
>             move_to(robot_shape,robot_x*10-10,robot_y*10+10)
>             robot_x = robot_x -1
>             robot_y = robot_y +1
>             break
>         if robot_x +0.5== player_x and robot_y+0.5 < player_y:
>             move_to(robot_shape,robot_x*10,robot_y*10+10)
>             robot_y = robot_y +1
>             break
>   
This is slightly different than the above, because you're checking 
against the player position instead .
but if we think about it, let's say that the robot is up and to the 
right of the player.
robot = 5, 5
player = 4, 6
now if you observe this, you can come to the following conclusions:
the operation playerx - robotx will have 3 possible outcomes:
1) positive, if player is to the right of robot.
2) negative, if (which is the case here) player is to the left of robot.
3) 0, if player is vertically aligned with robot.

A similar situation exists for the y-axis.
playery - roboty
1) positive if player is below robot,
2) negative if player is above robot,
3) 0, if player is horizontally aligned with robot.

Note that you could use the equations robotx - playerx, and roboty - 
playery, but the equations we chose here have
a special property:  if they are positive, that means you need to ADD to 
the offset of the robot, if they are negative you need to SUBTRACT
from the offset of the robot, and if they are 0 you need to do neither.
So this big block of code reduces to
offsetx = player_x - robot_x +0.5
offsety = player_y - robot_y+0.5
if offsetx > 0:      robot_x += 1
elif offsetx < 0:    robot_x -= 1

if offsety > 0:      robot_y += 1
elif offsety < 0:    robot_y -= 1

note here that we don't have to check if the robot is in bounds here,
because he's moving toward the player at all times, so he can't go out 
of bounds.
> def collided():
>     player_x == robot_x+0.5 and player_y == robot_y+0.5
>   
as stated before, this should be:
def collided():
    return player_x == robot_x+0.5 and player_y == robot_y+0.5
> def really_place_player():
>     place_player()
>     while collided():
>         place_player
>   
this is not a function call.  You need to change this to place_player().
> def check_collisions():
>     if collided() == 1:
>   
This is the same as
if collided():
>         print 'You have been caught' 
>   
> place_robot()
> really_place_player()
> while 1:
>     global keys
>     keys = keys_pressed()
>     if '1'in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '2' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '3' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '4' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '5' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '6' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '7' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '8' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>     if '9' in keys:
>         move_player()
>         move_robot()
>         check_collisions()
>   
Similar to above, you can reduce this in a few ways:
first,
for key in keys:
   if key in ['1', '2', '3', '4', '5', '6', '7', '8', '9']:
      move_player()
      move_robot()
      check_collisions()

secondly, you could reuse movement:
for key in keys:
   if key in movement.keys():
   # ... etc ...

third, you could try to convert it to an int
for key in keys:
   try: key = int(key)
   except ValueError:  continue
   if key != 0:
      move_player()
      move_robot()
      check_collisions()
>     if 'q' in keys:
>         break
>     time.sleep(0.5)
> ##finished=0
> ##while not yet finished:
> ##    move_player()
> end_graphics()
>   
Also, I just realized that you're using a while loop inside of your 
move_player and move_robots function.
But you only call these functions if you KNOW that a movement key was 
pressed.
Basically, this means that one of your 'if' conditions will ALWAYS be 
true inside of your while: loops, and you'll break out of it.

The only reason why you might want this is that it would immediately 
exit as soon as it finds the first key that was pressed, but the
same thing could be performed using an if-elif chain.  But I doubt you 
want this to happen.

Also there are other problems - eg. your keys is assigned to the keys 
that were currently pressed, so if during the time.sleep(0.5) I might
press and then release a key, and it would be lost in your code.

A great first attempt, though. :)
Always good to see more people pickin' up Python.



The code with the changes I mentioned included is attached to this e-mail.
Also, note that I didn't test this code ( I don't have livewires 
installed) so if any of it doesn't work, let me know.

-Luke
-------------- next part --------------
A non-text attachment was scrubbed...
Name: temp.py
Type: text/x-python
Size: 1981 bytes
Desc: not available
Url : http://mail.python.org/pipermail/tutor/attachments/20070725/0de2db01/attachment.py 


More information about the Tutor mailing list