Need help with Library Tactician


#1

Can Someone help me with my code?

# 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)
    self.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 = self.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            bestTarget = enemy
        # Only focus archers' fire if there is a big ogre.
    if bestTarget and bestTarget.health > 15:
        return bestTarget
    else:
        return None

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

loop:
    # 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 = self.findFriends()
    soldiers = self.findByType("soldier")
    for i, soldier in enumerate(soldiers):
        commandSoldier(soldier, i, len(soldiers));
    archers = self.findByType("archer")
    # use commandArcher() to command your archers
    for i, archer in enumerate(archers):
        commandArcher(archer, i, len(archers))


#2

I haven’t been able to give your code a full run through, but, you have a line
enemy.health >= mostHealth
which I don’t think is what you meant.


#3

I removed that line but still nothing has changed.


#4

Ok, i noticed it won’t run this command

self.command(archer, "attack", archerTarget)

although i don’t see where i can fix it.


#5

@Archlium Take a look at where the function is being declared and where you are calling it

here

def commandArcher(archer):

and here

for i, archer in enumerate(archers):
    commandArcher(archer, i, len(archers));

and ask yourself how many arguments are you sending to the function.


#6

Sorry, here’s what it actually said in my code

def commandArcher(archer, archerIndex, numArchers):

#7

So how many arguments are you sending to this function?

[ignore post]
I was reading too many lines of code before this and didn’t realize that you matched the number of arguments.


#8

I believe 3 arguments


#9

@Archlium Ok. I am looking at the correct code now.

Looking at:

# Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            enemy.health >= mostHealth
            enemy = bestTarget

When @Serg talked about enemy.health >= mostHealth he was asking you to evaluate the code.

What do you think this statement does?

For instance if you changed it to

# Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            hero.say(enemy.health >= mostHealth)
            enemy.health >= mostHealth
            enemy = bestTarget

what does the hero say ?


 


Also remember that enemy = bestTarget is not the same as bestTarget = enemy. The order of the variables is important.

enemy = bestTarget - says store the value of bestTarget in enemy
bestTarget = enemy - says store the current enemy that we are looking at into bestTarget

Make sure you are using the correct version or you will not get the result you expect.


 


Also the original code shows the following for the commandArcher function

# 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)

I would recommend removing: archerTarget = findStrongestTarget() from your version of the function as archerTarget is already being calculated in the main loop.


#11

I had already removed

enemy.health >= mostHealth
also a big problem was that it would only target nearest and not archerTarget


#12

@Archlium I am getting odd errors with the level when I regenerated the code and tried to submit the solution again in python. There are issues with your current code, but I am not sure about the level at the moment.

Try copying your code off to Notepad or such and resetting the code to get a clean code base.

You were missing the needed:

archerTarget = None

as well.


#14

Okay, so i fixed everything i was advised, but there is one point where the archers will not attack the second ogre on the bottom left. And yes, that is the only ogre this happens to.


#15

can you repost your code or update the code posted above


#17

There you go, it should be fixed to the code i have now.


#18

@Archlium Your code is almost there, there is just one last part that needs to be worked on.

Before that however I will recommend that you move the following code outside your loop.

friends = self.findFriends()
soldiers = self.findByType("soldier")
for i, soldier in enumerate(soldiers):
    commandSoldier(soldier, i, len(soldiers));
archers = self.findByType("archer")

Take it out of the loop and place it before:

loop:
    # If archerTarget is dead or doesn't exist, find a new one.

This will help to speed up the code and help to lessen the infinite loop errors.


 


Final piece to look at:

    mostHealth = 0
    bestTarget = None
    enemies = self.findEnemies()
    # Figure out which enemy has the most health, and set bestTarget to be that enemy.
    for enemy in enemies:
        if enemy.health > mostHealth:
            bestTarget = enemy

If you check if the enemy.health is greater than mostHealth and find that it is different you update bestTarget which is good, however if you do not also update mostHealth the next enemy you check will still be checking against the old value of mostHealth and not the updated version to reflect the current selected enemy. This should fix the targeting issue of the second large ogre on the bottom left.

Think of it this way if you are going down a line of ogres and asking each their health and if the health of ogre is larger then the current value you are holding, you want to make sure to retain both the ogre and its health to compare with ogres further down the line. Right now you just keep track of the ogre.


#19

Okay, so i added this to my code

    for enemy in enemies:
        if enemy.health > mostHealth:
            bestTarget = enemy
            mostHealth = 0

which i thought would fix it, however it did not. did i misinterpret?
EDIT
I see where it went wrong, as i duped
"mostHealth = 0"


#20

So, i added

mostHealth = bestTarget.health

and it will work, but the tiny people will kill the bottom left guy, will let you know if switching seeds fixes it.
EDIT
I have beaten the level, so thanks for the help!