Freezing then Infinite loop in Sarven Shepherd and Bookkeeper


#1

Reported in github here, but perhaps I’m doing something dumb.

When playing Sarven Shepherd and Bookkeeper with Python the game freezes and I get an “infinite loop” error.
In both cases the play freezes mid-animation until the loop detection error kicks in.
Video of the bug occurring: https://www.youtube.com/watch?v=aCC17gneaNY

Code for Sarven Shepherd:

while True:   
    # Wrap this logic in a while loop to attack all enemies.
    # Find the array's length with:  len(enemies)
    enemies = hero.findEnemies()
    enemyIndex = 0
    while enemyIndex < len(enemies):
        enemy = enemies[enemyIndex]
        # "!=" means "not equal to."
        if enemy.type != "sand-yak":
            # While the enemy's health is greater than 0, attack it!
            while enemy.health > 0:
                hero.attack(enemy)
        enemyIndex =+ 1
    # Between waves, move back to the center.
    hero.moveXY(40, 33) 

Code for Bookkeeper (not complete for level goals, but shouldn’t freeze and fail):

# Fight enemies for 15 seconds.
# Keep count whenever an enemy is defeated.
death = 0
bob = hero.now()
hero.moveXY(58, 33)
while hero.now() - bob < 15:
    #hero.say(hero.now() - bob)

    enemy = hero.findNearest(hero.findEnemies())

    if enemy:
        if enemy.health <= 0:
            death += 1
    if enemy:
        hero.attack(enemy)
# Tell Naria how many enemies you defeated.
hero.say(bob) # I understand that this is the wrong variable to say, but I don't think this is my issue.
# Collect coins until the clock reaches 30 seconds.

# Tell Naria how much gold you collected.

# Fight enemies until the clock reaches 45 seconds.
# Remember to reset the count of defeated enemies!

# Tell Naria how many enemies you defeated.

#2

I updated with more details on the github issue linked in the first line.

tl;dr

The Sarven Shepherd issue is a =+ instead of a +=.

The Bookkeeper is a little weirder. It appears that there is some sort of timing effect in the while surrounding testing the enemy.health. Adding an extra hero.say command to introduce a delay allows the level to succeed.

Code below succeeds, but commenting out the hero.say on line 13 freezes again.

# Fight enemies for 15 seconds.
# Keep count whenever an enemy is defeated.
death = 0
bob = hero.now()
hero.moveXY(58, 33)
while hero.now() < 15:
    enemy = hero.findNearest(hero.findEnemies())

    if enemy:
        while enemy.health > 0:
            hero.attack(enemy)
        death += 1
    hero.say("and stay down")
# Tell Naria how many enemies you defeated.
hero.say(death)
# Collect coins until the clock reaches 30 seconds.
while hero.now() < 30:
    coin = hero.findNearest(hero.findItems())
    coin_count=0
    if coin:
        hero.moveXY(coin.pos.x, coin.pos.y)
        coin_count += 1
# Tell Naria how much gold you collected.
hero.moveXY(58, 33)
hero.say(hero.gold)
    
# Fight enemies until the clock reaches 45 seconds.
# Remember to reset the count of defeated enemies!
death=0
while hero.now() < 45:
    enemy = hero.findNearest(hero.findEnemies())

    if enemy:
        while enemy.health > 0:
            hero.attack(enemy)
        death += 1
    hero.say("and stay down")

# Tell Naria how many enemies you defeated.
hero.moveXY(58, 33)
hero.say(death)

#3

Due to parser reasons, you can’t always create a loop that is expected to last over time unless you use a while True loop; this is because only while True loops get converted into generators that can paused and resumed manually by the game engine (and prevent infinite loops).

The sample code for Bookkeeper uses a if statement to check if the time limit has been reached and breaks out of the loop if so, so you might want to use that instead.

It’s why it infinite loops in your original code for Sarven Shepherd, not entirely because of the =+, but rather because enemyIndex wouldn’t be incremented and the loop becomes an infinite loop.

Also, the =+ seems to normally work just fine and shouldn’t have an error, because it’s an assignment to a positive number. (It’s just enemyIndex = +1, but with spaces in different positions). But maybe a warning would be nice.