Does Toil and Trouble have a bug?


#1

Here is my code:

# Ogre Witches have some unpleasant surprises ready for you.

# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend.
# Soldiers should attack the witches, archers should attack nearest enemy.
def chooseTarget(friend):
    enemies = self.findEnemies()
    enemy = self.findNearest(enemies)
    witches = self.findByType("witch", enemies)
    witch = self.findNearest(witches)
    if friend.type is soldier:
        self.command(soldier, "attack", witch)
    if friend.type is archer:
        self.command(archer, "attack", enemy)
loop:
    friends = self.findFriends()
    soldier = self.findByType("soldier", friends)
    archer = self.findByType("archer", friends)
    for friend in friends:
        # Use your chooseTarget function to decide what to attack.
        target = chooseTarget(friend)
        if target:
            if target.type is witch:
                self.command(friend, "attack", target)
            if target.type is enemy:
                self.command(friend, "attack", target)

I don’t get how this does not work. Please help me!!!


#2

@nick I might need your help if this actually is a bug!!:grinning:


#3

Please format your code correctly. I’ve formatted it for you this time.

As for the code problems:

  • findEnemies and findByType may return empty lists. Passing an empty list to findNearest returns None. You should check if the enemy exists before ordering your units to attack them—either by checking the length of the list returned by findEnemies / findByType or whether findNearest actually returned an unit.

  • The type values are strings so they should be quoted—i.e. you should compare target.type with "witch" instead of witch.

  • Your chooseTarget function does not return an enemy, it already orders the unit to attack it. So you can remove the target = part in target = chooseTarget(friend), and remove the whole if target: block as well.

  • These lines are dead code (unused code), you can safely remove them:
soldier = self.findByType("soldier", friends)
archer = self.findByType("archer", friends)

#4

What do you mean? I don’t get it. How do you do it? You made it kind of confusing.


#5
# When no enemies
enemies = findEnemies() # enemies is []
enemy = findNearest(enemies) # enemy == None, because no enemy in enemies
command(friend, "attack", enemy) # enemy == None, error occurs

You seem to already know this, as you account for the issue in the main loop. The main modification you’ll really need to make is to change chooseTarget() such that you aren’t commanding a friend, but rather using return to return the appropriate enemy target.


#6

I thought you were supost to attack the enemy directly from the chooseTarget()?


#7

here is my edited code:


# Ogre Witches have some unpleasant surprises ready for you.

# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend.
# Soldiers should attack the witches, archers should attack nearest enemy.
def chooseTarget(friend):
    enemies = self.findEnemies()
    if len(enemies) is not 0:
        enemy = self.findNearest(enemies)
        if friend and friend.type is "soldier" and enemy and enemy.type is "witch":
                self.command("soldier", "attack", "witch")
        elif enemy:
            self.command("soldier", "attack", enemy)
        if friend and friend.type is "archer" and enemy:
            self.command("archer", "attack", enemy)
loop:
    friends = self.findFriends()
    for friend in friends:
        # Use your chooseTarget function to decide what to attack.
        chooseTarget(friend)

but on this line:

elif enemy:
            self.command("soldier", "attack", enemy)

It says “Hero Placeholder needs something to command”.


#8

“soldier” is a string, a piece of text. You need an object to order just like you need an object to attack.
Only the name of the action “attack” is a string.

self.command(friend,"attack",enemy);

#9

ok thanks

hghghghghghg


#10

It’s still not working. Here is my code:

# Ogre Witches have some unpleasant surprises ready for you.

# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend.
# Soldiers should attack the witches, archers should attack nearest enemy.
def chooseTarget(friend):
    enemies = self.findEnemies()
    enemy = self.findNearest(enemies)
    if friend and friend.type is "soldier" and enemy and enemy.type is "witch":
            self.command(friend, "attack", enemy)
    if friend and friend.type is "archer" and enemy:
        self.command(friend, "attack", enemy)
loop:
    friends = self.findFriends()
    for friend in friends:
        # Use your chooseTarget function to decide what to attack.
        chooseTarget(friend)

#11

@UltCombo@trotod I need help!!! I’ve been stuck on it for like a month now!!!:unamused::unamused::unamused::unamused::worried::worried::cry::cry::cry:


#12

You are only ever commanding your friends to attack the nearest enemy to your hero. You will need to re-add the logic to find witches from the enemies array, or use the self.findByType('witch') method.


#13

O. Ok thx a lot.:grinning:

EDIT: Is this what you mean?:


# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend.
# Soldiers should attack the witches, archers should attack nearest enemy.
def chooseTarget(friend):
    enemies = friend.findEnemies()
    enemy = friend.findNearest(enemies)
    targets = friend.findByType("witch")
    if friend and friend.type is "soldier" and enemy and enemy.type is "witch":
            self.command(friend, "attack", enemy)
    if friend and friend.type is "archer" and enemy:
        self.command(friend, "attack", enemy)
loop:
    friends = self.findFriends()
    for friend in friends:
        # Use your chooseTarget function to decide what to attack.
        chooseTarget(friend)

Because it isn’t working. @UltCombo Are you there?:broken_heart:


#14

I’m on my working time here, so please have patience. :stuck_out_tongue_winking_eye:

Yes, that is what I meant, but you also have to update the code to command soldiers to attack the nearest witch if there are any witches still alive.


#15

ok thx

hghghghghghghgh


#16

IT DIDN’T WORK. I just can’t believe it. The archers can’t kill the ogres quickly enough and all the troops die leaving the ogres and witches alive. However, the soldiers go for only one witch and since the witches heal each other that witch doesn’t die.

Here is my code:

# Ogre Witches have some unpleasant surprises ready for you.

# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend.
# Soldiers should attack the witches, archers should attack nearest enemy.
def chooseTarget(friend):
    enemies = friend.findEnemies()
    enemy = friend.findNearest(enemies)
    witches = self.findByType("witch", enemies)
    witch = self.findNearest(witches)
    if friend and friend.type is "soldier" and enemy and witch and witch.health > 0:
            self.command(friend, "attack", witch)
    if friend and friend.type is "archer" and enemy:
        self.command(friend, "attack", enemy)
loop:
    friends = self.findFriends()
    for friend in friends:
        # Use your chooseTarget function to decide what to attack.
        chooseTarget(friend)

I really need help.


#17

Also I think there actually is bug. However, it is different than I thought.


#18

You’re very close to winning! :slight_smile:

Only one problem remains: you are telling all soldiers to attack the same witch (the nearest one to your hero). Command your soldiers to attack the nearest witch to them—that is, change self.findNearest(witches) to friend.findNearest(witches). After making this small change, your code should be able to win. Congratulations! :smile:


#19

I know :grinning::grinning: I changed it before I saw the post!! Thanks a lot. :smile:


#20

Actually Toil and Trouble may have a bug because this:

# Ogre Witches have some unpleasant surprises ready for you. 
# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend. 
# Soldiers should attack the witches, archers should attack nearest enemy. 
def chooseTarget(friend): 
    enemies = friend.findEnemies()
    enemy = friend.findNearest(enemies) 
    witches = self.findByType("witch", enemies) 
    witch = friend.findNearest(witches) 
    if friend and friend.type is "soldier" and enemy and witch and witch.health > 0: 
        self.command(friend, "attack", witch)
    else:
        self.command(friend, "attack", enemy)
    if friend and friend.type is "archer" and enemy: 
        self.command(friend, "attack", enemy) 
loop: 
    friends = self.findFriends() 
    for friend in friends:
    # Use your chooseTarget function to decide what to attack. 
        chooseTarget(friend) 
    # I have to say that these witches are tough to kill
    

And this:

# Define a chooseTarget function which takes a friend argument
# Returns a target to attack, depending on the type of friend. 
# Soldiers should attack the witches, archers should attack nearest enemy. 
def chooseTarget(friend): 
    enemies = friend.findEnemies()
    enemy = friend.findNearest(enemies) 
    witches = self.findByType("witch", enemies) 
    witch = friend.findNearest(witches) 
    if friend and friend.type is "soldier" and enemy and witch and witch.health > 0: 
        self.command(friend, "attack", witch)
    else:
        self.command(friend, "attack", enemy)
    if friend and friend.type is "archer" and enemy: 
        self.command(friend, "attack", enemy) 
loop: 
    friends = self.findFriends() 
    for friend in friends:
    # Use your chooseTarget function to decide what to attack. 
    chooseTarget(friend) 
    # I have to say that these witches are tough to kill
    

Both work! Unless you can persuade me that it isn’t a bug I have no other issues with it.