Infinite Loop on Clash of Clones*


#1

hopefully this is formatted correctly. Here is my code, using Python, get infinite loop error. code isn’t complete or tested, i just want to figure out where the infinite loop(s) is(are). Any help would be greatly appreciated.

Here is my code
return  #Commented out to stop infinite loop.

#that i need to find. i think the solution may lie in removing the extra arrays (though, i think it's
#a pretty damn genius way to handle who to 
loop:
   while self.now() < 1:
        self.moveXY(65, 64)
    
    friends = self.findFriends()
    enemies = self.findEnemies()    
    meeleeAlly = []
    archerAlly = []
    nearestFri = None
    nearestEne = None
    friendIndex = 0
    enemyIndex = 0    
    
    #while loop to seperate my allies into ranged and meelee based on "archer" type
    while friendIndex < len(friends):
        friend = friends[friendIndex]
        friendIndex += 1
        if friend.type == "archer":
            archerAlly.append(friend)
        else:
            meeleeAlly.append(friend)        
    
    #logic to dertermine if there is a living meelee ally, and if so, to move position to him
    #fight, and stay within 3m of said ally. trying to do it in a nested loop that breaks at 
    #ally health being <= 0
    if self.findNearest(meeleeAlly):
        nearestFri = self.findNearest(meeleeAlly)
        while nearestFri.health > 0:
            if self.distanceTo(nearestFri) > 3:
                self.moveXY(nearestFri.pos.x, nearestFri.pos.y)
                
            else:
                while enemyIndex < len(enemies):
                    enemy = enemies[enemyIndex]
                    enemyIndex += 1
                    
                if self.findNearest(enemies):
                    nearestEne = self.findNearest(enemies)
                    while nearestEne.health > 0 and nearestFri.health > 0:
                        if self.isReady("power-up") and self.distanceTo(nearestEne) <= 10:
                            self.powerUp()
                            self.attack(nearestEne)
                        else:
                            self.attack(nearestEne)
    enemyIndex = 0
    nearestFri = None
    nearestEne = None
    elif self.findNearest(archerAlly):
        nearestFri = self.findNearest(archerAlly)
        while nearestFri.health > 0:
            if self.distanceTo(nearestFri) > 3:
                self.moveXY(nearestFri.pos.x, nearestFri.pos.y)
            elif self.distanceTo(nearestFri) <= 3:
                while enemyIndex < len(enemies):
                    enemy = enemies[enemyIndex]
                    enemyIndex += 1
                    
                if self.findNearest(enemies):
                    nearestEne = self.findNearest(enemies)
                    while nearestEne.health > 0 and nearestFri.health > 0:
                        if self.isReady("power-up") and self.distanceTo(nearestEne) <= 10:
                            self.powerUp()
                            self.attack(nearestEne)
                        else:
                            self.attack(nearestEne)
    else:
        while enemyIndex < len(enemies):
            enemy = enemies[enemyIndex]
            enemyIndex += 1
            if self.isReady("power-up") and self.distanceTo(enemy):
                self.powerUp()
                self.attack(enemy)
            else:
                self.attack(enemy)

#2

It’s possible your infinite loop error comes from

while self.now() < 1:
    self.moveXY(65,64)

. You see, moveXY is a blocking command that always completes before moving on the the next part of the code. Your hero just is commanded to move to (65,64) a bunch of times, while they are already doing so. Remove that, and see if it helps.


#3

I have tried that (by blocking out that part in comments), but I still run into the infinite loop error. based on what you said though, could this:

if self.findNearest(meeleeAlly):
        nearestFri = self.findNearest(meeleeAlly)
        while nearestFri.health > 0:
            if self.distanceTo(nearestFri) > 3:
                self.moveXY(nearestFri.pos.x, nearestFri.pos.y)
                
            else:
                while enemyIndex < len(enemies):

where I make them move to the friendly unit? like if the unit keeps moving does my champ get stuck forever trying to stay within the 3 units of said friendly? thanks for replying!


#4

Is your code a complete copy/paste?

That first while is not indented properly, it seems to be 3 spaces long, while most of the other code is roughly using 4-space indentations.

If that’s not the problem, I suggest you initialize a different variable to 0 before every while loop, increment that variable inside each loop iteration, and prematurely break when that variable reaches 100 or something, and use self.say() to tell you roughly which of the loops is the issue.

I’m not familiar with the level being spoken of, but if your hero AI is simple enough, an obstacle can prevent moveXY() from ever reaching the intended destination. There is no pathfinding in this game, so if you are walking in a vector and encounter an obstacle that’s perpendicular to your walking angle, you’re stuck.


#5

It is a complete copy paste, and the indentation is off cuz i deleted an extra space when deleting the “#” to comment out the line of code before copy pasting. However, since i have commented-out those lines of code before, i know they are not the problem. I will now try your suggestions for figuring out where in my code the infinite loop is actually taking place. and in the level there is nothing for me to run into except for other friendly and enemy units. thanks for replying! :smile:


#6

So firstly, it’s the level Clash of Clones, not a wildly popular mobile game lol! Second, i tried your suggestion, and I still couldn’t figure out where the infinite loop is. The error is technically ‘your code didn’t finish, either it’s slow or there’s an infinite loop’.

Here is my updated code with the different variables to flag where the infinite loop is
return  #Commented out to stop infinite loop.

#that i need to find. i think the solution may lie in removing the extra arrays (though, i think it's
#a pretty damn genius way to handle who to  
loop:
    while self.now() < 1:
        self.moveXY(65, 64)
    
    friends = self.findFriends()
    enemies = self.findEnemies()    
    meeleeAlly = []
    archerAlly = []
    nearestFri = None
    nearestEne = None
#    friendIndex = 0
#    enemyIndex = 0    
    
    #while loop to seperate my allies into ranged and meelee based on "archer" type
    loop1Index = 0
    while loop1Index < len(friends):
        friend = friends[loop1Index]
        loop1Index += 1
        if friend.type == "archer":
            archerAlly.append(friend)
        else:
            meeleeAlly.append(friend)
        if loop1Index >= 100:
            self.say("It was the loop to seperate meelee and archers " + loop1Index)
            break
    
    #logic to dertermine if there is a living meelee ally, and if so, to move position to him
    #fight, and stay within 3m of said ally. trying to do it in a nested loop that breaks at 
    #ally health being <= 0
    loop2Index = 0
    if self.findNearest(meeleeAlly):
        nearestFri = self.findNearest(meeleeAlly)
        test1 = 0
        while nearestFri.health > 0:
            test1 += 1
            if self.distanceTo(nearestFri) > 3:
                self.moveXY(nearestFri.pos.x, nearestFri.pos.y)                            
            elif self.distanceTo(nearestFri) <= 3:
                while loop2Index < len(enemies):
                    enemy = enemies[loop2Index]
                    loop2Index += 1
                    
                    if self.findNearest(enemies):
                        nearestEne = self.findNearest(enemies)
                        test2 = 0
                        while nearestEne.health > 0 and nearestFri.health > 0:
                            test2 += 1
                            if self.isReady("power-up") and self.distanceTo(nearestEne) <= 10:
                                self.powerUp()
                                self.attack(nearestEne)
                            elif test2 >= 100:
                                self.say("it's the while enemy health > 0 loop " +test2)
                                break
                            else:
                                self.attack(nearestEne)
                    elif loop2Index >= 100:
                        self.say("It was enemy while loop in the meelee code " + loop2Index)
                        break
            elif test1 >= 100:
                self.say("it's the meelee while friend health > 0 " + test1)
                break
#    enemyIndex = 0
    loop3Index = 0
    nearestFri = None
    nearestEne = None
    elif self.findNearest(archerAlly):
        nearestFri = self.findNearest(archerAlly)
        test3 = 0
        while nearestFri.health > 0:
            test3 += 1
            if self.distanceTo(nearestFri) > 3:
                self.moveXY(nearestFri.pos.x, nearestFri.pos.y)
            elif self.distanceTo(nearestFri) <= 3:
                while loop3Index < len(enemies):
                    enemy = enemies[loop3Index]
                    loop3Index += 1
                    
                    if self.findNearest(enemies):
                        nearestEne = self.findNearest(enemies)
                        test4
                        while nearestEne.health > 0 and nearestFri.health > 0:
                            test4 += 1
                            if self.isReady("power-up") and self.distanceTo(nearestEne) <= 10:
                                self.powerUp()
                                self.attack(nearestEne)
                            elif test4 >= 100:
                                self.say("It was the archer enemy health > 0 " + test4)
                                break
                            else:
                                self.attack(nearestEne)
                    elif loop3Index >= 100:
                        self.say("It was the archer enemy while loop " + loop3Index)
                        break
            elif test3 >= 100:
                self.say("it's the archer while friend health > 0 " + test3)
                break
    else:
        loop4Index = 0
        while loop4Index < len(enemies):
            enemy = enemies[loop4Index]
            loop4Index += 1
            if self.isReady("power-up") and self.distanceTo(enemy):
                self.powerUp()
                self.attack(enemy)
            else:
                self.attack(enemy)
            if loop4Index >= 100:
                self.say("It was the final enemy loop " + loop4Index)
                break

Also, I should note that the whole level kinda just freezes after like 5 seconds. Any further help would be greatly appreciated!


#7

Hypothetically, what if self.findFriends() happens to return dead allies? You’ve got some protection against that in the lower part of your code, but if you are encountering such an issue, I recommend that you search for that while you are building your archerAlly and meleeAlly arrays.

The meat of your code is in an if-elseif-else statement, and the code can completely fall through without issuing a command to your hero (Which I believe causes the game to progress to the next frame). If that happens, and then you rebuild your arrays again, including the dead allies I suppose an infinite loop can happen, because you never advance to the next frame, and never hit a condition to advance the simulation.

So, it looks like you have the potential for infinite loops in 2 areas (one of the three is fine I think?)


#8

General Debugging tip:

which part of code is getting executed or not can be checked by using:
self.say(“any text here”).
If character avatar says this message, then it is running. If going on repeatedly, it may be in intentional/un-intentional loop.

In actual programming in python (for college courses), I have used print(“any text here”) to check various regions of code. It is the same as self.say.

Many regions of code can be checked like this with different " " content in the self.say lines.

P.S. : self.say takes 1 second I think to execute, so this slows down the program. Better not include this is final program… use it for checking.

Need any example anyone?

Cheers