Why is this wrong? (python)

loop:
    enemies = self.findEnemies()
    enemyIndex = 0
    while enemyIndex < len(enemies):
        enemy = enemies[enemyIndex]
        if enemy:
            if enemy = self.findNearest(enemies):
                if enemy.type != 'sand-yak':
                    while enemy.health > 0:
                        if self.isReady("bash"):
                            self.bash(enemy)
                        elif self.isReady("power-up"):
                            self.powerUp()
                        else:
                            self.attack(enemy)
                    enemyIndex = enemyIndex + 1
                else:
                    enemyIndex = enemyIndex + 1
            else:
                enemyIndex = enemyIndex + 1

I don’t know why is this not working propperly.
Can you help me please?
Thanks

Just a general hint for formatting: You dont use ` ` ` but ``` (without spaces).

You have a lot of unnecessary if-checks in there. If there are no enemies, len(enemies) will return 0. As you ask if enemyIndex is truly smaller than len(enemies) (which we know would be 0 if there are no enemies), and enemyIndex is 0 at the beginning, you wouldn’t even enter the loop.

That is when there are no enemies. Let’s go into the loop. In the first line of the loop you get an element of the list. As your code does not enter the while if enemies[enemyIndex] does not exist, you know that enemy will contain a real enemy after this assignment. Therefore you don’t have to check if enemy: in line 6.

Then you find the nearest enemy (self.findNearest(enemies) does that), and assign it to enemy, overwriting what was inside it before. After this assignment, if checks if the newly assigned enemy does exist. We actually know that it must exist, because we are in the while-loop. To check if two things are equal, you use two equal-signs (==). However, this check is unnecessary, as enemies spawn in waves anyway. You can either decide to fight enemies one by one in order of appearance (Then you use while and enemyIndex), or you always fight the nearest one (using loop and self.findNearest(self.findEnemies()) ).

Whe innermost while-loop is good as it is.

Then you have a cascade of identical commands. As rule of thumb, when you can copy code to different places, you’re doing something wrong. In this case you don’t need an else, it is actually blocking you. You want to increase the enemyIndex in every case, no matter wether you fought an enemy or dodged a sand-yak.

Cleaned Code:

loop:
    enemies = self.findEnemies()
    enemyIndex = 0
    while enemyIndex < len(enemies):
        enemy = enemies[enemyIndex]
        #don't check if enemy exists, we already know this
        #don't reassign enemy, we're doing this another way
        if enemy.type != 'sand-yak':
            while enemy.health > 0:
                self.attack(enemy)    #Don't forget to hack, slash and bash as well
        enemyIndex = enemyIndex + 1   #You can also write "enemyIndex += 1"

Note the indentations. Because enemyIndex is on the same line as the if, it is not inside the if. It will be executed even when enemy.type == 'sand-yak' (that is the if won’t get executed), or in other words: enemyIndex will increase each run until all enemies have been looked at.

2 Likes

Its worth mentioning that it is more idiomatic to iterate over a list with
for item in items:
instead of
while index < len(items):

As far as I can tell this approach isn’t covered by CodeCombat, but it does work.

I think that the for-loop is covered in one of the mountain-levels (Nick mentioned something about it, but I was already pretty tired). To stay in the context of the level, I used while. For my personal code I use for-loops, because I’m far more common with them.

Thank you very much, this was really very helpfull!

@Yaur: you’re right, and the code backbone in levels uses an index, but the example one gets when hovering over self.findEnemies() etc. show i.e. for enemy in enemies: (at least with the hardened steel glasses I have) :slight_smile:

I guess you want to replace = by == in the following condition:

if enemy = self.findNearest(enemies):