Help with sarven-shepherd


#1

what is wrong? It keeps telling me “unreachable while after return”

loop {
    var enemies = this.findEnemies();
    var enemy = this.findNearest(enemies);
    // Wrap this logic in a while loop to attack all enemies.
    while (enemy.health>0){
    // "!=" means "not equal to."
    if (enemy && enemy.type != "sand-yak") {
     // While the enemy's health is greater than 0, attack it!
            this.attack(enemy);
            this.attack(enemy);
            this.attack(enemy);
    }
    else if (enemy && enemy.type == "sand-yak") {
        this.wait(0.1);
        }
    // Between waves, move back to the center.
}
this.moveXY(33, 40);
}

#2

Try to write your code with a better indentation:

    loop {
        var enemies = this.findEnemies();
        var enemy = this.findNearest(enemies);
        // Wrap this logic in a while loop to attack all enemies.

        while (enemy.health>0){
            // "!=" means "not equal to."
            if (enemy && (enemy.type != "sand-yak")) {
                // While the enemy's health is greater than 0, attack it!
                this.attack(enemy);
                this.attack(enemy);
                this.attack(enemy);
            }
            else {
                this.wait(0.1);
            }
            // Between waves, move back to the center.
        }
        this.moveXY(33, 40);
    }

It will help you and us to fix your code. And see pinned post on how to display code correctly (using ` three times before and after the code)
I made few changes, maybe it could helps. See the () around the condition, and I removed the condition for the else.
I advice you to remove the three attacks, only one needed, it will be repeated by the while loop.
I also let you check what the while condition will be if there is no enemy. Maybe the test to check if enemy exist should be done sooner.

Edit : change the way to display code


#3

Fixed the code formatting issue in the first post, but didn’t checked indentations.

Always remeber, correct indentations save lives!


#5

I have another question, not sure if I’m doing this level wrong (in Python):

# Use while loops to pick out the ogre

loop:
    enemies = self.findEnemies()
    enemyIndex = 0

# Wrap this logic in a while loop to attack all enemies.
while len(self.findEnemies()) > enemyIndex:
    enemy = enemies[enemyIndex]
    # "!=" means "not equal to."
    if enemy.type != "sand-yak":
        enemyIndex = enemyIndex + 1
        # While the enemy's health is greater than 0, attack it!
        while enemy.health > 0:
            self.attack(enemy)
        

    # Between waves, move back to the center.
    self.moveXY(40, 33)
    

Not sure what I’m doing wrong … the character doesn’t start attacking, just stands their … no errors tho.

Any help would be appreciated!


#6

As viewed in another post, what happened to enemyIndex if enemy.type is “sand-yak” ?


#7

The problem is your top-most loop.
Your code looks like this to the computer:

Do forever:
    Find all enemies
    Set a variable

# Here is after forever

As long as enemyIndex is smaller than the amount of enemies:
    # do something

The critical point is the comment. You will never reach it, because forever is longer than you’ll be willing to wait.
This can simply be solved by indenting the complete while-loop so it will run inside the outer loop:

loop:
    enemies = self.findEnemies()
    enemyIndex = 0
    
    while len(...) > enemyIndex:
        # engage enemies
        # don't forget to indent this as well!
    
    # Once you defeated all enemies, move back
    self.moveXY(40, 33)

Now the second problem, which you didn’t encounter yet, because of the first error.
Vettax is right with his post that once that you encounter a sand-yak, you will for the rest of the code look at that sand-yak. A better construct would be:

# stuff before while

while len(...) > enemyIndex:
    enemy = enemies[enemyIndex]
    enemyIndex += 1             # Increase enemyIndex in every case.
    if enemy.type != "sand-yak":
        # engage enemy

# stuff after while

Note the order: you have to fetch the enemy first, and then increase the enemyIndex. If you increase the enemyIndex first, you actually skip the enemy at enemies[0], because enemyIndex would already be 1 at this place.


#8

OK, I understand the second problem; I should have added to enemyIndex every time, not just if the enemy is not a sand-yak. But the 1st problem: how would I change it? Why will the enemyIndex never be smaller the the amount of the enemies? Does enemyIndex change as enemies die, or is that len()? I think my mistake is that I do not know what enemyIndex really is, and how it works (i get that it has all the enemies, but does it know if the enemy dies? does len() know?).

Sorry for the outbursts of questions, but I’m not sure how len() and enemy.index are related. Thanks for helping me!


#9

The first problem is solved by indenting the while loop and everything within it.

loop: #Loop 1
    enemies = self.findEnemies() # get a collection of the enemies visible right now.
    enemyIndex = 0 # reset the enemyIndex back to 0 each time through the loop.
    
    while len(enemies) > enemyIndex: # Loop 2 nested within Loop 1
        # don't forget to indent this as well!
        # Find enemy number enemyIndex.
        currentEnemy = enemies[enemyIndex]
        if currentEnemy.type != "sand-yak":
            # engage the current enemy
            # don't forget indenting for the if statement.

        #when we're done engaging the current enemy:
        enemyIndex += 1 # increment the index into the enemy collection by one so the next time through the loop we get the next enemy.

    # Once you've defeated all enemies, move back and get another collection of enemies at the top of the loop.
    self.moveXY(40, 33)

The Python programming language is sensitive to white-space. If you want to nest the second loop within the first loop, it’s necessary to indent the second loop exactly as shown here. Hence:

If the enemies collection is a street and each enemy was a house on that street, enemyIndex would be the house number.

allyIndex = 0
allies = ["Alice", "Bob"]

allies[allyIndex] # Alice
allies[0] # Alice, note that the numbering starts from zero, also known as zero-based 
allyIndex += 1
allies[allyIndex] # Bob
allies[1] # Bob
allyIndex += 1
allies[allyIndex] # This would result in an error. We've just walked off the end of the side walk.
allies[2] # This would result in an error, probably something about index out of bounds. In some languages this will result in reading the contents of some random chunk of memory.
allies[-1] # This will get you another error. The only valid values in this example are 0 and 1.
if allyIndex < len(allies):
    allies[allyIndex] # This line would not be executed because of the if statement, so no error.

EnemyIndex will usually be smaller than the number of enemies, i.e. len(enemies) since it’s initialized to zero. We initialize it to zero because we want to start at the first item in the collection and work our way down the line.

enemyIndex = 0

Say you have a collection of three allies that you need to warn:

allies = ["Alice", "Bob", "Eve"]
i = 0 # It's very common to see an indexer named i.
while i < len(allies):
    self.say("Watch out " + allies[i] + "!")
    i += 1

if i == len(allies):
    self.say("Everybody has been warned.")

If I haven’t messed something up, this will output:

Watch out Alice!
Watch out Bob!
Watch out Eve!
Everybody has been warned.

Once i is equal to the len(allies), e.g. when i = 3 in this instance, then i < len(allies) or 3 < 3 will be false and the while loop will stop looping.

An enemy dying will not directly impact enemyIndex nor len(enemies). enemyIndex is just a number and in this example, it only changes when it’s incremented or reset to zero. len(enemies) won’t change until the next time the enemies collection is updated:

enemies = self.findEnemies()

After an enemy dies, the collection might look something like:

enemies = [<dead enemy>, <a sand-yak>, <living enemy>, <another sand-yak>, <living enemy>]

There will still be the same number of items in the collection, it just happens that one of them is no longer a concern. :smile:


#10

Umm…What does Unreachable ‘while’ after ‘return’ means?


#11

my solution

loop:
    enemies = self.findEnemies()
    enemyIndex = 0

    # 將下面的程式碼用 wihle 迴圈包住來攻擊所有的敵人
    
    enemy = enemies[enemyIndex]
    # "!=" 代表 "不等於"
    for enemy in enemies:
    if enemy.type != "sand-yak":
        if enemy.health >0:
            self.attack(enemy)
        else:
            enemyIndex =enemyIndex +1
    if enemy.type = "sand-yak":
        enemyIndex = enemyIndex +1