Why is my code slow?


#1
# Hushbaum has been ambushed by ogres!
# She is busy healing her soldiers, you should command them to fight!
# The ogres will send more troops if they think they can get to Hushbaum or your archers, so keep them inside the circle!

# Soldiers spread out in a circle and defend.
def commandSoldier(soldier, soldierIndex, numSoldiers):
    angle = Math.PI * 2 * soldierIndex / numSoldiers
    defendPos = {"x": 41, "y": 40}
    defendPos.x += 10 * Math.cos(angle)
    defendPos.y += 10 * Math.sin(angle)
    hero.command(soldier, "defend", defendPos);

# Find the strongest target (most health)
# This function returns something! When you call the function, you will get some value back.
def findStrongestTarget():
    mostHealth = 0
    bestTarget = None
    enemies = hero.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    findStrongestTarget()
    # Only focus archers' fire if there is a big ogre.
    if bestTarget and bestTarget.health > 15:
        return bestTarget
    else:
        return None


# If the strongestTarget has more than 15 health, attack that target. Otherwise, attack the nearest target.
def commandArcher(archer):
    nearest = archer.findNearestEnemy()
    if archerTarget:
        hero.command(archer, "attack", archerTarget)
    elif nearest:
        hero.command(archer, "attack", nearest)

archerTarget = None

while True:
    # If archerTarget is dead or doesn't exist, find a new one.
    if not archerTarget or archerTarget.health <= 0:
        # Set archerTarget to be the target that is returned by findStrongestTarget()
        archerTarget = findStrongestTarget()

    friends = hero.findFriends()
    soldiers = hero.findByType("soldier")
    # Create a variable containing your archers.
    archers = hero.findByType("archer")
    for i in range(len(soldiers)):
        soldier = soldiers[i]
        commandSoldier(soldier, i, len(soldiers));

    # use commandArcher() to command your archers
    commandArcher()

#2

@LordCthulhu can you use the code format button on the code so the indents are clear.


#3

Done. Is that better?


#4

@LordCthulhu worse actually. Try it once more, the goal is to get the code to look like the good code below.

You can also use 3 " ` " characters above and below the code to turn it into a well formatted code block. The ` character should be on the keyboard under the Tilde. ~


GOOD


friends = hero.findFriends()
soldiers = hero.findByType("soldier")
# Create a variable containing your archers.
archers = hero.findByType("archer")
for i in range(len(soldiers)):
    soldier = soldiers[i]
    commandSoldier(soldier, i, len(soldiers));

# use commandArcher() to command your archers
commandArcher()`Preformatted text`

BAD


friends = hero.findFriends() soldiers = hero.findByType("soldier") # Create a variable containing your archers. archers = hero.findByType("archer") for i in range(len(soldiers)): soldier = soldiers[i] commandSoldier(soldier, i, len(soldiers));

use commandArcher() to command your archers

commandArcher()Preformatted text


#5

There, I think I got it.


#6

@LordCthulhu Ok that is what I thought I saw. Does your code actually run?

# This function returns something! When you call the function, you will get some value back.
def findStrongestTarget():
    mostHealth = 0
    bestTarget = None
    enemies = hero.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    findStrongestTarget()

This looks like you are recursively calling the same function. I am at a bit of a loss at how it wouldn’t just enter into an infinite loop. (did I miss something?)


#7

What’s wrong with that part of the section? “recursively calling the same function” ? Oh, and not only can the code be slow but it can also be in an infinite loop, and I don’t understand why.


#8

@LordCthulhu when you create the function

def findStrongestTarget():

and then call

findStrongestTarget()

inside of the function 5 lines down it should, once called, loop from those two points and never end. So you would want to remove the function call findStrongestTarget() and instead work out the logic for the comment:

# Figure out which enemy has the most health, and set bestTarget to be that enemy.

And don’t get caught up in the idea that one line means one piece of code. They are asking you to write out many lines of code to solve the above comment.

Questions to ask to build the logic:

  1. What kinds of programming constructs have we learned up to now?
  2. How would I look through each enemy and determine which has the most health?
  3. How would I store that information so I could reference it later?

#9
# Hushbaum has been ambushed by ogres!
# She is busy healing her soldiers, you should command them to fight!
# The ogres will send more troops if they think they can get to Hushbaum or your archers, so keep them inside the circle!

# Soldiers spread out in a circle and defend.
def commandSoldier(soldier, soldierIndex, numSoldiers):
    angle = Math.PI * 2 * soldierIndex / numSoldiers
    defendPos = {"x": 41, "y": 40}
    defendPos.x += 10 * Math.cos(angle)
    defendPos.y += 10 * Math.sin(angle)
    hero.command(soldier, "defend", defendPos);

# Find the strongest target (most health)
# This function returns something! When you call the function, you will get some value back.
def findStrongestTarget():
    mostHealth = 0
    bestTarget = None
    enemies = hero.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            mostHealth = enemy.health
            bestTarget= enemy
    # Only focus archers' fire if there is a big ogre.
    if bestTarget and bestTarget.health > 15:
        return bestTarget
    else:
        return None


# If the strongestTarget has more than 15 health, attack that target. Otherwise, attack the nearest target.
def commandArcher(archer):
    nearest = archer.findNearestEnemy()
    if archerTarget:
        hero.command(archer, "attack", archerTarget)
    elif nearest:
        hero.command(archer, "attack", nearest)

archerTarget = None

while True:
    # If archerTarget is dead or doesn't exist, find a new one.
    if not archerTarget or archerTarget.health <= 0:
        # Set archerTarget to be the target that is returned by findStrongestTarget()
        archerTarget = findStrongestTarget()

    friends = hero.findFriends()
    soldiers = hero.findByType("soldier")
    # Create a variable containing your archers.
    archerTarget = findStrongestTarget()
    for i in range(len(soldiers)):
        soldier = soldiers[i]
        commandSoldier(soldier, i, len(soldiers));

    # use commandArcher() to command your archers
    commandArcher()

#10

Okay, I filled in that portion, but now it says I do not have an item equipped with the findnearestenemy skill. What does that mean?


#11

@LordCthulhu did you look at the glasses to ensure that you have every hero function you think you do?

Some of the functions get removed in higher cost glasses, which can be good or bad. You just need to change the code to use the functions available in the higher cost glasses.


#12

Uh, I used like 4 other glasses and none of them worked. And when I looked at the functions they had the findNearest command.


#13

So the Fine Wooden Glasses would be an example of an item that has both hero.findNearestEnemy() as well as hero.findNearest()

As we can see hero.findNearestEnemy() returns the closest living enemy within eyesight. So we would expect one enemy to be returned.

With the hero.findNearest() it returns the closest unit out of an array of units. So we need to send it an array of units. hero.findEnemies() will return a list/array of enemies that are within eyesight. So if we write the following code it would be equivalent.

enemy = hero.findNearestEnemy()

and

enemies = hero.findEnemies()
if enemies:
    enemy = hero.findNearest(enemies)

Depending on the glasses your character has equipped you should have either hero.findNearestEnemy() or both the hero.findNearest() and the hero.findEnemies().

Now your code also uses archer.findNearestEnemy() in it. So if that is the only place where this function is being called, perhaps the error is misleading? And you are not able to run the command off of the archer?

def commandArcher(archer):
    nearest = archer.findNearestEnemy()

what happens if you change out the archer.findNearestEnemy() with an equivalent from the the examples I listed above using hero. instead of archer.?


#14

Okay, but now it says “Line 38: command’s argument minion should have type unit, but got null. Hero Placeholder needs something to command.”


#15

So the next challenge can be solved by looking at the commmandSoliders() function.

How do we tell each soldier to do something?

If we just call commandArcher() will it do anything? Or do we need to send it something like what we sent commandSoldier() ?

And if its called commandArcher it most likely commands a single archer right? So we would want to use this command for each archer individually some how by using the programming structures we were already introduced to.

Questions:

  1. How can I cycle through all of the archers and command each like what was done for the soldiers?
  2. What do I need to send to commandArcher() to ensure it works?

#16
# Hushbaum has been ambushed by ogres!
# She is busy healing her soldiers, you should command them to fight!
# The ogres will send more troops if they think they can get to Hushbaum or your archers, so keep them inside the circle!

# Soldiers spread out in a circle and defend.
def commandSoldier(soldier, soldierIndex, numSoldiers):
    angle = Math.PI * 2 * soldierIndex / numSoldiers
    defendPos = {"x": 41, "y": 40}
    defendPos.x += 10 * Math.cos(angle)
    defendPos.y += 10 * Math.sin(angle)
    hero.command(soldier, "defend", defendPos);

# Find the strongest target (most health)
# This function returns something! When you call the function, you will get some value back.
def findStrongestTarget():
    mostHealth = 0
    bestTarget = None
    enemies = hero.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            mostHealth = enemy.health
            bestTarget= enemy
  
    # Only focus archers' fire if there is a big ogre.
    if bestTarget and bestTarget.health > 15:
        return bestTarget
    else:
        return None


# If the strongestTarget has more than 15 health, attack that target. Otherwise, attack the nearest target.
def commandArcher(archer):
    nearest = hero.findNearestEnemy()
    if archerTarget:
        self.command(archer, "attack", archerTarget)
    elif nearest:
        self.command(archer, "attack", nearest)

archerTarget = None

while True:
    # If archerTarget is dead or doesn't exist, find a new one.
    if not archerTarget or archerTarget.health <= 0:
        # Set archerTarget to be the target that is returned by findStrongestTarget()
        archerTarget = findStrongestTarget()

    friends = hero.findFriends()
    soldiers = hero.findByType("soldier")
    # Create a variable containing your archers.
    archerTarget = findStrongestTarget()
    for i in range(len(soldiers)):
        soldier = soldiers[i]
        commandSoldier(soldier, i, len(soldiers));

    # use commandArcher() to command your archers
    def commandArcher(archer, archerIndex, numArchers):
        for i in range(len(archers)):
            archers = archers[i]
            hero.command(archer, "defend", defendPos);

#17

I also filled in that portion, and I played around with it a little bit, but the same thing happens. I’m still not getting the picture. Any more hints possibly? I really want to progress forward.


#18

Humm…

Try reading through this tutorial on w3schools about Javascript functions. I believe that you are getting some programming constructs confused.

http://www.w3schools.com/js/js_functions.asp

Let me know if that helps.