Desert world: Oasis code check


#1

This code seems to work fine, but I’m new to Python and not sure of the best practices. Is the below code good? I’m assuming the variables are contained within the statements so if is isolated from else and so on.

And if not, any particular reason why I should explicitly reset the pos = variable for both if/else?

# Move right to reach the oasis,
# but move left to avoid nearby yaks.
loop:
    enemy = self.findNearestEnemy()
    # Set the position first + coordinates
    pos = self.pos; x = pos.x; y = pos.y
    
    if enemy and self.distanceTo(enemy) < 10:
        # Move to the left by subtracting 10 from your X coordinate.
        x -= 10
        self.moveXY(x, y)
    else:
        # Move to the right by adding 10 to your X coordinate.
        x += 10
        self.moveXY(x, y)

#2

Hello @badlydrawnrob and welcome to the forums! Feel free to reuse existing topics (related to this level) to ask your question next time.


First of all, your code seems to be OK, and properly indented :wink:

I don’t exactly understand what do you mean by “reset” here. What you put in your if/else statement (correctly) is that you add/remove 10 to/from your current X-coordinates, and after that you move to these new coordinates. Thus you move left/right, based on the enemy’s distance.


#3

Thanks @ant! Ok so I probably didn’t make as much sense as I thought, so I’ll try again:

Any particular reason why I should explicitly reset the pos = variable for both if/else?

It’s good to hear my code is right. These are some of my observations so far:

  1. Some functions don’t work if you set the variable outside the if statement, distanceTo for instance (as enemy is not found yet). I guess much depends on the function you’re using to whether you can set it outside or not? And is it better practice to set nearer the code it’s affecting for readability?
  2. I was unsure at first if the else: x variable would inherit the if: x variable’s properties; i.e. else: x would read 0 (x = 0 - 10 + 10) — can an else or elif statement ever inherit the if variables properties? Or is it always contained within it’s own block (I remember reading about inheritance but I’m still not sure on it)

I’m a bit tired, so not sure if this makes it clearer what I was asking or if it further confounds matters!


#4

I think you confused some concepts there. Variables are (in the context of this game) usually not inherited.

Also you should look at the concepts of loops again.


It might happen that distanceTo gives you an error simply because you can’t see an enemy. If self.findNearestEnemy() doesn’t find an enemy, it assigns a special value that says that there is nothing stored in the variable. We call this value null.
If you now try to find the distanceTo(null) your program will throw an error, because you can’t get the distance to nothing. This is because you have to check if enemy actually exists.

Because programmers are extremely lazy they build a shortcut. Instead of

if enemy != null and self.distanceTo(enemy) < 10:

you can use (6 characters shorter, yes we are that lazy)

if enemy and self.distanceTo(enemy) < 10:

Regarding the readability:
This is a lot of personal style. If you can, you should set all variables in one block close to the top. You can then immediately see which variables are in use, and don’t have to ask where that strange variable with the cryptic name came from. You did this good in your code.
The other way (a bit more performance-oriented, so currently uninteresting for you) is regarded to lazy initialization (see, lazy again). This is basically when you set a variable only when you need it. This way a variable is always close to where it is set, but you can not see all variable with a quick look.

The first variant is usually better readable, less error-prone and I generally recommend it if you’re not yet confident in you program-analysis-skills. You should never try to optimize for performance if you don’t exactly know what you’re doing and what it will affect.


If you ever set a variable in your program, this variable will last as long as the world runs (so approximately 30 seconds on average). You can of course overwrite it with new values, but the program will remember that this variable is there and which value it had last.

At the beginning your program doesn’t know any variable. You then set enemy, pos, x and y. From now on these variables will be known to the system.
You then enter the if/else. You can only go one path, never both!. This means that (in your program) x will either be decreased or increased. Whatever happens, the x from line 6 is used and receives a new value after the computation, and the old value is just forgotten.

Then your loop starts again. Unimportant what the previous values of the four variables were, you override them with new values, completely forgetting the old values. But if you wanted to you could use them for something different after they have been set for the first time, for example after the loop (you’ll learn how to escape an infinite loop later).
If you forget to set the variables to new (updated) values you use data that is wrong. If you forgot to search for a new nearest enemy you might miss a yak that sneaks upon you, and run directly into it.


#5

Thanks @J_F_B_M I think I’ve got most of that down already but it helps to have a more human explanation of what the process is actually doing. I understood that you have to check the enemy exists first when using distanceTo (from trial and error) but this makes it clearer. Initially I assumed setting a variable distance = distanceTo could be reused in an if and it would reference the enemy when required. I guess it’s enough to know that you must check if enemy exists first, before using the distance function.

I’ll take a closer look at loops (I haven’t used them yet in Codecademy Python track), am I right in thinking that loop is just shorthand for the actual Python command? I’ve seen for and while so expect I’ll be learning them soon.

Everything else makes sense, thanks!


#6

And I’m all for being lazy :wink:


#7

I don’t know if Python has a natural loop-construct. In some languages it was explicitly introduced as an alternative to while(true), because the while-loop caused understanding-problems with new players. They often produced errors which they had no chance to understand.
If the player gets told "Write loop and everything will be good he is much more understanding than when told "Write while(true), and in about 20 levels we tell you why.


#8

Yeah agreed. As far as I can see, I don’t think it does. But I think some concepts do take a little building to … I found Ruby a little tough to grasp (same with jQuery) so switched to Python as I think on the whole it’s clearer — Codecombat is definitely a nice break from the academic learning!