Problem with .health on Summit's Gate


#1

I’m having an issue with an infinite loop on Summit’s gate in regards to the catapult health:

def attackCatapults():
    catapults = self.findByType("catapult")
    for catapult in catapults:
        while catapult.health > 0:
            self.attack(catapult)

def moveForward():
    self.move({'x': self.pos.x + 1, 'y': self.pos.y})

loop:
    attackCatapults()
    moveForward()

After the hero defeats the catapults, he gets stuck in self.attack(catapult) even though the catapult health is not greater than 0.

Edit: It looks like .health isn’t the issue, the hero is trying to attack a catapult that is not visible to me (likely near the end of the level?) It’s difficult to debug this one without knowing what my hero is seeing since it’s not visible or within line-of-sight.


#2

Your code looks fine. If I recall correctly, there are only two catapults in this level.

Isn’t it the moveForward() function where you are getting stuck at? That will move the hero forward until they walk against a wall, and keep forcing their way against the wall without success.


#3

The hero never gets to moveForward. Even substituting in:

def moveForward():
    targetPos = {'x': 328, 'y': 35}
    self.move(targetPos)

results in the same problem. I ended up circumventing this issue with the following code:

# Fight your way into the Inner Sanctum of the ogre chieftain, and kill her.
self.toggleFlowers(False)
def commandArchers():
    for archer in self.findByType("archer", self.findFriends()):
        nearestEnemy = archer.findNearestEnemy()
        if nearestEnemy:
            self.command(archer, "attack", nearestEnemy)

def commandSoldiers():
    for soldier in self.findByType("soldier", self.findFriends()):
        nearestEnemy = soldier.findNearestEnemy()
        if nearestEnemy:
            self.command(soldier, "attack", nearestEnemy)         

def commandGriffins():
    for griffin in self.findByType("griffin-rider", self.findFriends()):
        enemies = griffin.findEnemies()
        nearestEnemy = self.findNearest(enemies)
        if nearestEnemy:
            self.command(griffin, "attack", nearestEnemy)
        else:
            self.command(griffin, "defend", self)

def weakestFriend():
    weakestFriend = None
    weakestHealth = 999
    for friend in self.findFriends():
        if friend.health < friend.maxHealth and friend.health < weakestHealth:
            weakestHealth = friend.health
            weakestFriend = friend
    if weakestFriend:
        return weakestFriend
            
def commandPaladins():
    for paladin in self.findByType("paladin", self.findFriends()):
        if paladin.canCast("heal", self):
            if self.health < 3000:
                self.command(paladin, "cast", "heal", self)
            else:
                weakestFriend2 = weakestFriend()
                if weakestFriend2:
                    self.command(paladin, "cast", "heal", weakestFriend2)
        else:
            self.command(paladin, "move", {'x': self.pos.x - 4, 'y': self.pos.y})

def summonGriffin():
    if self.gold >= self.costOf("griffin-rider"):
        self.summon("griffin-rider")

def moveForward():
    targetPos = {'x': 328, 'y': 35}
    self.move(targetPos)

def pickTarget():
    enemies = self.findEnemies()
    target = None
    minDistance = 9999
    for enemy in enemies:
        if enemy.type is not "door":
            if enemy.type is "catapult":
                target = enemy
                break
            elif enemy.type is "warlock":
                target = enemy
                break
            elif enemy.type is "witch":
                target = enemy
                break
            elif enemy.type is "chieftain":
                target = enemy
                break
            else:
                if self.distanceTo(enemy) < minDistance:
                    minDistance = self.distanceTo(enemy)
                    target = enemy
    if target:
        return target

       
def commandHero():
    target = pickTarget()
    if target:
        while target.health > 0:
            if self.isReady("bash") and target.health > 116:
                self.bash(target)
            else:
                self.attack(target)
    else:
        moveForward()

loop:
    summonGriffin()
    commandArchers()
    commandSoldiers()
    commandGriffins()
    commandPaladins()
    commandHero()

#4

For future reference:
self.say(catapults)
Would have let you see what your hero was seeing.

My guess is that you were having a problem with a empty list. You ran through the code once and your second loop you tried to run it through again, but there were no catapults. This led your hero to do crazy things, as you told him to attack a non-existent catapult.

You can try:

def attackCatapults():
    catapults = self.findByType("catapult")
    if len(catapults):
        for catapult in catapults:
            while catapult.health > 0:
                self.attack(catapult)

To see if it works, but your current code is better anyway (I wish I would have used that for summit’s gate)


#5

Iterating over an empty list should be a no-op (i.e. run zero iterations, do nothing) so the length check shouldn’t make much difference.


#6

Yep, I tried something similar and iterating an empty list is a no-op. Learn something new every day.