Play Home Contribute Github Join Us! Discourse Staff Members Github Contribution Guides Team

Having trouble with Agrippa defense

While indentations save lives, more indentations won’t save more lives :wink:

You indented the if, but at this point it is unnecessary (and actually causes an error).
The correct line-up is:

loop:
    enemy = self.findNearestEnemy()
    if enemy:
        distance = self.distanceTo(enemy)
        if distance < 5:
            self.cleave(enemy)
        else:
            self.attack(enemy)

At this point I want to add that cleave only does 15 damage, your sword does 30 damage. If you know that you only engage one enemy, it makes more sense to only attack. Just a general hint.

2 Likes

The solution we are trying to suggest for this level is:

loop:
    enemy = self.findNearestEnemy()
    if enemy:
        # Find the distance to the enemy with distanceTo.
        distance = self.distanceTo(enemy)
        
        # If the distance is less than 5 meters...
        if distance < 5:
            # ... if "cleave" is ready, cleave!
            if self.isReady("cleave"):
                self.cleave(enemy)
            # ... else, just attack.
            else:
                self.attack(enemy)

So it’s supposed to be a nested if where you only attack when you are within 5m, but you cleave if cleave is ready. I think this is too complex for this level, so we need to figure out something else.

2 Likes

@J_F_B_M LOL!!!

“Indentions don’t save lives people … people do”

With the initial code you guys did she would:

First Group:

  • wait until they all got close and
  • she’d cleave.
  • They’d all die.

Second Group:

  • she’d sit there until cleave was ready
  • then she’d attack with cleave

Final Group:

  • she’d move to the next group
  • waaaait for it… cleave

… END SUCCESS!

With the code below she’d start off with 515 and end with 55.

loop:
    enemy = self.findNearestEnemy()
    if enemy:
        distance = self.distanceTo(enemy)    
    if distance < 5:
        if self.isReady("cleave"):
            self.cleave(enemy)
    else:
        self.attack(enemy)

I didn’t like that.

So I wanted her to:

  • cleave
  • check for cleave ready
  • no cleave ready (then attack)
  • cleave ready (cleave)

So I changed the code… but this is what she did istead:

First Group:

  • same as above.

Second Group:

  • she’d attack one by one (before cleave was ready)
  • then she’d cleave (although no one was there)

Final Group:

  • she’d move to the next group
  • hit them one by one and then cleave

So I added self.say “This is Code Combat!” to try to catch what was happening in the loop.

After I did that she wouldn’t cleave anymore after defeating the second group in hand to hand combat. She’d go to the next group and when they were w/in 5 she would cleave.

Here’s the code I used.

loop:
    enemy = self.findNearestEnemy()
    if enemy:
        distance = self.distanceTo(enemy)    
    if distance < 5:
        if self.isReady("cleave"):
            self.say("This is Code Combat!")
            self.cleave(enemy)
            self.shield()
        else:
            self.shield()
            self.attack(enemy)
    else:
        self.shield()
        self.attack(enemy)

I do not feel this was the most efficient way, but she started with 515 health and ended with 275.

1 Like

@nick thank you!!! That makes sense!

So in my code above… the last part (the second else) wasn’t needed. Unfortunately I cannot see inside the loops yet, but I’m hoping with practice I can.

Sifting through arrays and loops are my nemesis!

1 Like

Indentations again!

Your if distance < 5: is not indented relative to your if enemy:. This means that you potentially attack enemies that are not actually present.

This is of course unless your Copy-Paste missed some spaces again.


Regarding loops:
I wrote a longer post here

http://discourse.codecombat.com/t/shine-getter-javascript/2542/4?u=j_f_b_m

1 Like

lol!

Did I detect a wee bit of snark?! :smiley: #lovesIT

I promise any errors you see this time are not copy and paste related. :relaxed:

I am going to take you up on your longer post though. I can tell this is going to destroy me unless I get a handle on it.

Oh! and also I don’t get what you said. I’m inside of a loop. So why is it attacking enemies that are not present since it is in the loop where ‘if enemy’ is true? #confused

Thanks so much @J_F_B_M !!!

1 Like
loop:
    enemy = self.findNearestEnemy()
    if enemy:                                # First if
        distance = self.distanceTo(enemy)    
    if distance < 5:                         # Second if
        #cleave maybe
    else:                   # this else corresponds to the second if
        #attack

Let’s say there is an enemy. The first if is true, so distance is now 4.5 (because I say so).
The second if is now true aswell (because there is an enemy). You cleave the enemy, and he’s dead now.

The loop starts again. Because of your awesome cleave, all enemies are dead now. enemy is now undefined. The first if becomes false. distance stays the same value as before, which is still 4.5
The second if sees that 4.5 < 5 and enters. You now try to target an undefined-enemy. This results in … I actually don’t know what this results in, most likely the result you saw. I thought this just throws an error…

But your code would still be problematic. Given you didn’t found an enemy, but somehow distance is greater than 5. You then would enter the else-path. What happens? You self.attack(undefined). Still strange behaviour.


Now comes the twist… I have no idea why the code runs through. This is most likely related to some kind of error-catching-mechanism, that catches the error silently and simply continues your code. Do you have by any chance a red circle with a white cross below your feet?



EDIT: I just tested your code… completly error-free. But as soon as I add a self.say(enemy) after enemy = self.findNearestEnemy() or a self.say(distance) just before the second if, I get

Say what?

That’s it, I ask @nick to explain.

2 Likes

cripes… well … i should probably stop until it’s explained then because what you said makes total sense and because it didn’t error out and I’m building my own theory based on this experience; it would be a bad idea to continue based on what you just said.

i want the code to error out and not tell me it’s ok if it’s not.

thanks @J_F_B_M

1 Like

I think what’s happening is that your distance variable is still defined from earlier iterations through the loop even later on when there is no enemy.

1 Like

Well that would explain why when the bad guys were down (and before I put in “This is Code Combat!”) it would use cleave.

After I added the say there it no longer saw enemies < 5 and she proceeded towards the final group.

1 Like

The way I fixed this was adding a && operator so my code was

if(cleave is ready and enemy is less then 5m away){
      cleave
} 

pseudo code btw

1 Like

Thank you so much!! this was killing me :slight_smile: adding the shield and attack within the cleave made a difference!!

1 Like

I tried adding { … I get the same result. I don’t think my character is fighting back at all. I will try to get better armor, but I also want my code to work.

loop {
    var enemy = this.findNearestEnemy();
    if (enemy) {
        var distance = this.distanceTo(enemy);
        if (distance < 5) {
            if (this.isReady("cleave")) {
                this.cleave(); 
            }
        }
    }
    else {
        this.attack(enemy);
    }
}
1 Like

Always try to say your code as a (or multiple) sentence.

Find the nearest enemy.
If there is an enemy, check the distance to it. [Cleave maybe].
If there is no enemy, attack that enemy.

If you spell it out like this, you see the problem (seriously, this is how I debug sometimes).

You probably want that else somewhere else.

loop {
    var enemy = this.findNearestEnemy();
    if (enemy) {
        var distance = this.distanceTo(enemy);
        if (distance < 5 && this.isReady("cleave")) {
            this.cleave(enemy); 
        }
        else {
            this.attack(enemy);
        }
    }
}

This code says:

Find the nearest enemy.
If there is an enemy, get the distance to it. If the distance is smaller than 5 and cleave is ready, cleave the enemy. If either distance is greater or equals than 5 or cleave is not ready, attack the enemy.
If there is no enemy, do nothing.

2 Likes

This seemed to work for me. (I’m still new to coding in general so it might not be the best way.)

loop {
    var enemy = this.findNearestEnemy();
    if(enemy) {
        var distance = this.distanceTo(enemy);
        if (distance < 5) {
            if (this.isReady("cleave")) {
                this.cleave(enemy);
            }
            else {
                this.attack(enemy);
            }
        }
    }
}
1 Like

This is really helpful! Thanks! :grinning:

1 Like

I have no idea what I’m doing wrong. I’m getting and error on line 5 “Undefined is not a function” (LUA)

1 Like

Hey eddietwang, I just loaded up your code on my end and it seems to work fine–you beat the level. If you’re still seeing this bug, can I get you to open up the JS console and look for some stack trace details on what is leading to that error in the error logs?

1 Like

Has anyone beaten this level using clojure?

As best as I can figure out it should go something like this:

(dotimes [n 1000]
    (let [enemy (.findNearestEnemy this)]
        (if enemy
            ;; Find the distance to the enemy with distanceTo
            (let [distance (.distanceTo this enemy)]
                ;; If the distance is less than 5 meters...
                (if (< distance 5)
                    ;; ... if "cleave" is ready, cleave!
                    (if (.isReady this "cleave")
                        (.cleave this enemy)
                        ;; ... else, just attack.
                        (.attack this enemy))
                    (.moveXY this (+ (- (mod n 3) 1) 40) 31)    ;; um, "borrowed" from Vlevo
                )
            )
            (.moveXY this 40 (+ (- (mod n 3) 1) 31))
        )
    )
)

I run up and down, so the last move command must be working. Then as soon as the enemies spawn I just stand there doing nothing.

2 Likes
loop:
    enemy = self.findNearestEnemy()
    if enemy:
        distance = self.distanceTo(enemy)
        if self.isReady("cleave") and distance < 5:
                self.cleave(enemy)
            else:
                self.attack(enemy)
1 Like