Infinite loop where there wasn't one before (and shouldn't be)


#1

(we all say there shouldn’t be an inf. loop don’t we…) :blush:

Error: slow code or inf loop.

It happens between the first and second wave of attackers.
Well not “between” it happens as the second wave takes the field. So the code has been spinning it’s wheels waiting for them…

name: Vlevo
Level: Sacred Statue

there are the usual javascript console errors:

 ____________ couldn't find lc for Object of Array[55]

there is also a:

(program):645 Cannot show action build for Statue Stone Hooded because it DNE
http://codecombat.com/db/thang.type/grow Failed to load resource: the server responded with a status of 404 (Not Found)

also a: (i) |Eris’s Pam| Hushbaum had new Programmable problem: chooseAction Line 1: undefined is not a function 1

last error message in javascript console:

Lank.coffee:408 Cannot show action power-up for Captain because it DNE
jquery.js:8625 GET http://codecombat.com/db/thang.type/power-up 404 (Not Found)

Help! Only killing 1 Ogre in Patrol Buster with Clojure
#2

Are you using the new move boots? Is your code pretty complicated? Trying to figure out what might have changed here besides my fix to reduce the dropped frame in between hero actions.


#3

(new move boots) Nope, haven’t figured out how they work so I don’t know which/if so I haven’t purchased them.

No the code for this one is pretty straight forward.

The piece of code it claims is the infloop isn’t even a loop (it is a simple function with just an if and a moveXY).
At the point where it is failing the code (a function) it highlights shouldn’t even be being called.
I commented out the calls to the function and it still thinks the infloop is there (or I assume that is why it is highlighting that stretch of code.)

I just noticed that the Hero popup at bottom of the screen is not updating, is because of the inf loop? or ?? (it says she has full health and is still at 3,11 even as she walks around the screen getting beat on.)

Possibly related problem here.

testing a different problem I noticed this in the default text on the level (“Desert Combat”) I was using to test:

# Always take an action inside a while loop, or it'll go infinite!

So I rearranged my code a little and now it doesn’t go infinite. But I Boo-Hoo lost a couple of days of playing this level. <sniff><sniff> (and I’ve got prolly one (two tops) more win left in me before I can’t go any further because of the enemy tsunami!! What day do the testable-subscription levels turn to subscription only?)


#4

Oh, so were you using a while True loop and not taking an action in it? Only the simple loop will automatically yield each iteration if no action is taken.

The levels switch over on Tuesday nights or Wednesday mornings, but you can keep playing any adventurer-turned-subscriber level you started while it was an adventurer level.


#5

I had while foo < bar within while snafu < fubar :smile: I changed it to manually create a list of items and then “while” over that instead. I didn’t realize that the while loop would collapse into a singularity if it only contained “if False” (so to speak).

Cool, nice to know once started they keep being available.


#6

I am having similar problems since switching to the move() boots:

loop:
    bestCoin = None
    maxRating = 0
    coinIndex = 0
    coins = self.findItems()
    
    while coinIndex < len(coins) and coins and self.gold < 150:
        coin = coins[coinIndex]
        if self.distanceTo(coin) < 20:
            rating = coin.value / self.distanceTo(coin)
            if rating > maxRating:
                maxRating = rating
                bestCoin = coin
        coinIndex += 1
    enemy = self.findNearest(self.findEnemies()) 
    if enemy and self.distanceTo(enemy) < 15:
        self.attack(enemy)
    # elif bestCoin and self.isReady("jump"):
    #     self.jumpTo(bestCoin.pos)
    elif bestCoin:
        self.move(bestCoin.pos)
    else:
        pass

using this for generic loot/attack (e.g. treasure grove) and it works fine for a while, then it starts bogging down and then throws the infinite loop or slow code error.


Headhunter is vicious
#7

I can see that happening.

If there are coins but all are > 19 away and there is an enemy but it is > 14 away, your code could head “to infinity and beyond”

no coin closer than twenty means no best coin (so no move)
no enemy closer than 15 means no attack
no attack and no move means the loop contains no action…

for fun :smile: try this:

before the “loop:” add "maxDist = 20"
change the if coin distance check from “<20” to "<maxDist"
add a “maxDist=20” to the “elif bestCoin:” clause
add a “maxDist+=1” to the “else:” clause

now when it can’t find any coins <20 it will check <21, then <22, … until it finds one then it will go back to <20

in case that was confusing:

maxDist = 20
loop:
    bestCoin = None
    maxRating = 0
    coinIndex = 0
    coins = self.findItems()
    
    while coinIndex < len(coins) and coins and self.gold < 150:
        coin = coins[coinIndex]
        if self.distanceTo(coin) < maxDist:
            rating = coin.value / self.distanceTo(coin)
            if rating > maxRating:
                maxRating = rating
                bestCoin = coin
        coinIndex += 1
    enemy = self.findNearest(self.findEnemies()) 
    if enemy and self.distanceTo(enemy) < 15:
        self.attack(enemy)
    # elif bestCoin and self.isReady("jump"):
    #     self.jumpTo(bestCoin.pos)
    elif bestCoin:
        self.move(bestCoin.pos)
        maxDist = 20
    else:
        maxDist += 1

#8

good catch, but it’s still having trouble.

Also, I think that because the move() behavior is looped, it’ll start moving, then reset the maxDist, then start building it up again until the coin is within range again, then move the next tick. Except it should maintain the bestCoin until it has been picked up and returns null or another coin becomes better.

The irony is that the reason I implemented the maximum distance was to cut down on processor cycles by not calculating the rating of coins that are too far away…


#9

good point, the move command would cause a reset of the maxDist effect

I’m not sure how it decides who wins, but you might not want to stop at 150. I know it is possible (with moveXY anyway) to pickup coins after you hit 150. What if you hit 150 before your opponent but they end up with 151 before the code checks your scores – Oh – haha, getting my levels confused. :blush: but really there is no reason to check unless you are going to runAway like the dickens from any enemies so they can’t kill you in the last milliseconds (I have had that happen: enough gold to win but I didn’t survive)


#10

One thing i noticed is that with the new movement logic. if you have coin prioritizing logic the game goes through a lot more cycles now, thus spending more and more time on the coin logic. Thus eating up cpu and thinking its an infinite loop. I had to add in a “wait” of 5-7 cycles where it wouldnt re-run the logic and used the last chosen coin to go after unless the coin was null. This seemed to work magic.


#11

I tried putting in a time check so that it should only rank coins once per second:

    if self.now() - lastTime > 1:
        while coinIndex < len(coins) and coins:
            coin = coins[coinIndex]
            rating = coin.value / self.distanceTo(coin)
            if rating > maxRating:
                maxRating = rating
                bestCoin = coin
            coinIndex += 1
        lastTime = self.now()

but no luck (it makes it a little while farther into the level, but…)
edit:
I even tried putting my move() command in separate while loop so that it would only re-evaluate coins after I pick one up… still no luck.


#12

OK, I finally broke down and got new boots and . . . . :frowning:

As, sotonin says on the levels where you process coins you end up getting “inf-loop” errors (I assume the same will happen on levels with lots of mobs of various types where one process by type.)

Inserting a “wait” into my code is not a good solution as “not waiting” is the whole purpose of the “move()” command (in other words sotonin’s solution was to essentially make move() be partial-blocking (he processes new/changed enemies not new coins)).

@nick can the “inf-loop” detector be changed to count statements between actions instead of just counting them. (or if it is supposed to be doing that, change it so it considers non-blocking actions worthy of resetting the count. or X non-blocking actions queued up become blocking until < X are queued or …something…)


#13

The infinite loop fires when it takes more than 7.5 seconds to simulate a single frame. I think possibly the problem is that it simulates the frame quickly, but then takes a long time to serialize the data to send to the main thread. So I’ll have to dig into it and improve the performance; it shouldn’t be anywhere near this slow.


#14

I did not mean an actual “this.wait” in my code. I simply made the coin logic check a timestamp and not execute for like 5-7 cycles unless the currently targeted coin was gone, then recalculate. This does not make anything “blocking” it just slows down the coin calculating which is eating up the cpu like crazy when nothing has actually changed. IE. its blasting through frames and doing all that expensive calculation and the majority of the time nothing has changed.

Is it perfect? No. we shouldn’t have to do it. But we do. for now. :slight_smile: so that’s your options unfortunately.


#15

I didn’t mean a “wait()” action either . . your code does “block” the processing of coins (but as I said, processes other stuff which wouldn’t happen with a “wait()” action).

My :smile: option is to use moveXY boots on coin levels. (though I believe I can sometimes get the inf-loop with my “moveTowards(x,y)” on coin levels also.)


#16

Using moveXY doesnt seem like a good solution as that is fully blocking. :slight_smile: