Bookkeeper Help : Something Wrong With My Code


#1

For some reason, when I make an “if self.now = 16:”, my hero goes and does the things inside that “if” statement before it is really 16 seconds.

Also, do you have to finish the code for the code to really work correctly?

For help, I will show you my code. I would really appreciate the help.

# Fight enemies for 15 seconds.
# Keep count whenever an enemy is defeated.
enemiesDead = 0
coinsCollected = 0
while self.now < 16:
    enemy = self.findNearest(self.findEnemies())
    if enemy:
        while enemy.health > 0:
            self.attack(enemy)
        enemiesDead = enemiesDead + 1
    else:
        self.moveXY(54, 33)
# Tell Naria how many enemies you defeated.
elif self.now = 16:
    self.moveXY(59, 33)
    self.say(enemiesDead)
# Collect coins until the clock reaches 30 seconds.
while self.now < 31 & self.now > 16:
    coin = self.findNearest(self.findItems())
    if coin:
        pos = coin.pos
        x = coin.pos.x
        y = coin.pos.y
        self.moveXY(x, y)
# 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.

P.S. : I am not finished with the code yet, I am just solving this problem right now.


#2

This means you are creating a new variable called self.now and you are giving it the value 16
Writing a=16 will always evaluate to true so the program immediately jumps inside the elif

What you need:

# first loop 
while self.now() <= 15:
     # first loop stuff here
     # kill enemies, increase counters, etc.
# first loop finished when self.now() is more than 15
# observe the line indentation - the lines start directly from the margin
# so they are not part of the first loop
# go to Naria tell her stuff
# initialize the counters for the second loop
while self.now() <= 30:
    # and so on
    # these lines are indented so they are inside the second loop

#3

Oh, thanks. I just forgot the (). Now I realize my mistake.


#4

For some reason, my code now makes me cannot collect coins at all.


#5

Loop and while(True) are are changed in code combat to add a wait at the end of the loop, preventing a loop execution that will take 0 time. Such a loop execution will crash your code because it creates an infinite cycle

Just add a move to the center to make sure your hero always does something (and thus make the time pass)

while self.now()<=16:
    if coin:
        # collect coin
   else:
       # move to the  center OR
       self.wait(0.001)

#6

Can you tell me the line of code I am supposed to fix?


#7

It is not hard. Just you your existing code and add an else wait to it:

    if coin:
        pos = coin.pos
        x = coin.pos.x
        y = coin.pos.y
        self.moveXY(x, y)
    else 
       self.wait(0.001)

#8

Now this is my code. For some reason, I am not collecting coins when I run this code, even if I put a wait.

# Fight enemies for 15 seconds.
# Keep count whenever an enemy is defeated.
enemiesDeadFirstWave = 0
enemiesDeadSecondWave = 0
coinsCollected = 0
while self.now() < 16:
    enemy = self.findNearest(self.findEnemies())
    if enemy:
        while enemy.health > 0:
            self.attack(enemy)
        enemiesDeadFirstWave = enemiesDeadFirstWave + 1
    else:
        self.moveXY(54, 33)
# Tell Naria how many enemies you defeated.
if self.now() == 16:
    self.moveXY(59, 33)
    self.say(enemiesDeadFirstWave)
# Collect coins until the clock reaches 30 seconds.
while self.now() < 31 & self.now() > 16:
    coin = self.findNearest(self.findItems())
    if coin:
            pos = coin.pos
            x = coin.pos.x
            y = coin.pos.y
            self.moveXY(x, y)
            coinsCollected = coinsCollected + 1
    else: 
        self.wait(0.001)
# Tell Naria how much gold you collected.
if self.now() == 31:
    self.moveXY(54, 33)
    self.say(coinsCollected)
# Fight enemies until the clock reaches 45 seconds.
# Remember to reset the count of defeated enemies!
while self.now() < 46 & self.now() > 30:
    enemy = self.findNearest(self.findEnemies())
    if enemy:
        while enemy.health > 0:
            self.attack(enemy)
        enemiesDeadSecondWave = enemiesDeadSecondWave + 1
    else:
        self.moveXY(54, 33)
# Tell Naria how many enemies you defeated.
if self.now() == 46:
    self.moveXY(54, 33)
    self.say(enemiesDeadSecondWave)

#10

@AdrianCgw
Now this is my code. For some reason, I am not collecting coins when I run this code, even if I put a wait.

# Fight enemies for 15 seconds.
# Keep count whenever an enemy is defeated.
enemiesDeadFirstWave = 0
enemiesDeadSecondWave = 0
coinsCollected = 0
while self.now() < 16:
    enemy = self.findNearest(self.findEnemies())
    if enemy:
        while enemy.health > 0:
            self.attack(enemy)
        enemiesDeadFirstWave = enemiesDeadFirstWave + 1
    else:
        self.moveXY(54, 33)
# Tell Naria how many enemies you defeated.
if self.now() == 16:
    self.moveXY(59, 33)
    self.say(enemiesDeadFirstWave)
# Collect coins until the clock reaches 30 seconds.
while self.now() < 31 & self.now() > 16:
    coin = self.findNearest(self.findItems())
    if coin:
            pos = coin.pos
            x = coin.pos.x
            y = coin.pos.y
            self.moveXY(x, y)
            coinsCollected = coinsCollected + 1
    else: 
        self.wait(0.001)
# Tell Naria how much gold you collected.
if self.now() == 31:
    self.moveXY(54, 33)
    self.say(coinsCollected)
# Fight enemies until the clock reaches 45 seconds.
# Remember to reset the count of defeated enemies!
while self.now() < 46 & self.now() > 30:
    enemy = self.findNearest(self.findEnemies())
    if enemy:
        while enemy.health > 0:
            self.attack(enemy)
        enemiesDeadSecondWave = enemiesDeadSecondWave + 1
    else:
        self.moveXY(54, 33)
# Tell Naria how many enemies you defeated.
if self.now() == 46:
    self.moveXY(54, 33)
    self.say(enemiesDeadSecondWave)

#11

From what I’ve seen so far:

while self.now() < number:
    #block of code

results in an infinite loop (not sure why).
However, you can do this:

while True:
    #block of code
    if self.now() >= number:
        break  #breaks out of the current loop

This looks like it has the same effect (terminating the outer loop when the time reaches number), but it doesn’t result in an infinite loop.
Also check the level’s guide if you’re stuck or need more information. I think it outlines the same method.


#12

If your loop takes zero frames to execute, it will execute indefinitely preventing the game from advancing. That is, your code will be stuck running in the same game frame forever with the same outcome in all iterations.

That is because CodeCombat’s interpreter applies special treatment to the loop: and while True: constructs—if an iteration takes zero frames to execute, the interpreter will automatically wait for the next game frame before running the next iteration. You can read more about this in this GitHub issue.

This also means that the “automatically wait for next game frame” behavior is only applied when you explicitly input loop: or while True:, not when the while condition expression evaluates to true (e.g. while 1==1:, while self.now() < 9000: etc) which can then result in an infinite loop that may prevent the game state from advancing if all loop iterations take zero frames to execute.

I believe this is all very tricky for the target audience which is people that are learning to code. Even regular contributors like @zuf didn’t know about these intricacies. In my humble opinion, the game engine should handle this problem so the players don’t need to. But, in fact, this is pretty tricky to do as it may result in an unwanted delay in your loops, as you can see from the comments in the linked issue.

I also found that several people (including me!) have run into this issue while playing the Bookkeper level, as you can see in the relevant thread.

Perhaps it is time to try to address this, or maybe this will be solved by the new interpreter that is in the works?
/cc @nick