Multiplayer Treasure Grove with Python


#1

I was wondering why my code doesn’t work in this level:

while True:
    enemy = hero.findNearestEnemy()
    item = hero.findNearestItem()
    
    def attackIfClose():
        distance = hero.distanceTo(enemy)
        if enemy and distance < 10:
            hero.attack(enemy)
    
    if item:
        while True:
            if item.value == 3:
                hero.moveXY(item.pos.x, item.pos.y)
                attackIfClose()
        while True:
            if item.value == 2:
                hero.moveXY(item.pos.x, item.pos.y)
                attackIfClose()
        while True:
            if item.value == 1:
                hero.moveXY(item.pos.x, item.pos.y)
                attackIfClose()

I wanted the hero to prioritise coins by value by using several while loops and thought that if the first nested while loop returns “False” (i.e. there is no gold coin) the code would continue to go to the next nested while loop. Instead, the hero just stands there :smile: Where is the flaw in my approach?


#2

A few things. You can’t define a function within the while True loop. It must be outside the loop. I see what you’re trying to do with the nested while True loops but this isn’t the way it’s done. If it did work, what would happen (I think - not 100% sure on this) is that your code would get stuck inside the nested loop and stay there, unable to move to the next one. Just use if statements in the main while True loop. Remember that you’ll have to define your variables in both the while True loop and the function. Also, the way you’ve defined the variable, “distance” within the function doesn’t work. It isn’t necessary to do this anyway. Just eliminate the variable and change your if conditional to if enemy and hero.distanceTo(enemy) < 10: With these corrections the code will work fine and complete the level successfully.


#3

Hi, thanks a lot for pointing me into the right direction. All of your remarks made sense to me, but I was wondering: why doesn’t the way I defined the variable “distance” work? This part of the code actually worked (whenever the enemy was within 10 meters, the hero attacked him).

Your comments made me restructure my code a little:

def attackIfClose(target):
    distance = hero.distanceTo(target)
    if target and distance < 5:
        hero.attack(target)

while True:
    enemy = hero.findNearestEnemy()
    item = hero.findNearestItem()
    
    if item and item.value == 3 or 2:
        hero.moveXY(item.pos.x, item.pos.y)
        attackIfClose(enemy)
    elif item and item.value == 1:
        pet.fetch(item)

Since I couldn’t make the prioritisation by value work, I tried a different approach. The hero is to collect all gold and silver coins and my pet is to collect all bronze coins. However, with the code above, my pet just follows my hero and the hero only collects the nearest item, no matter its value. Why is that?

PS: I finished the level successfully already, but I would really like to make the code work how I intended it to :slight_smile:


#4

I believe that the reason the variable distance isn’t working as defined is because target is a function parameter that is not defined.

def someFunction(parameter):

I removed the parameter and just had

def attackIfClose():

Then, defined enemy in the function and used it. It worked fine that way.

The reason your pet isn’t doing what you want is because of the way you’re putting the code for it in an elif conditional along with the rest of your code. Personally, I would create another function with just the pet code and call the function inside the while True loop. I like functions. :crazy_face:


#5

I gave it a try and created another function with just the pet code. Turns out that the pet can’t fetch coins in general (it says “I can’t carry that!”). What a bummer.

Still, for some reason the hero still collects just the nearest coins instead of only those with values 3 (gold coins) or 2 (silver coins).

My current code:

def attackIfClose(target):
    distance = hero.distanceTo(target)
    if target and distance < 5:
        hero.attack(target)

def petCollectsItem():
    if item and item.value == 1:
        pet.fetch(item)

while True:
    enemy = hero.findNearestEnemy()
    item = hero.findNearestItem()
    
    if item and item.value == 3 or 2:
        hero.moveXY(item.pos.x, item.pos.y)
        attackIfClose(enemy)
    petCollectsItem()

I’m at a loss :stuck_out_tongue:


#6

Remember to define variables in every function. A variable defined in one function can’t be seen by another function.

At this point I’m wondering if it’s an equipment problem. What you’re trying to do is a bit advanced for this level so it could be that or a limitation within the level itself. It works fine when the code is simple. I can’t get the code work if I restrict the hero from gathering coins that have a value of 1 and the pet isn’t fetching coins either (I’ve tried the wolf and the griffin) so I’m leaning towards a level limitation. If you’re a subscriber, use the contact form and ask. I’m sure that they’d be glad to help.


#7

Good idea, and glad to hear I am not the only one facing this issue. I will contact the support team. Thank you!


#8

BTW, this level was designed to use flags so that could be an issue as well. I know without them, the hero keeps running into and getting stuck on a fence with takes a few seconds of standing still to get free. It really slows him down.


#9

You don’t need to contact the support. Pets don’t fetch coins. image .Simply remove the pet’s code. Your main goal is to collect coins - you don’t need to fight to pass the level. I played with you code and used only ‘bash’ when the enemy is really closer , but you can pass without it.
" getting stuck on a fence with takes a few seconds of standing still to get free" - this is a problem with moveXY
( the boots) . I also had problems with the right fence. You can take the coins even if you are a bit farther from them: See the logic for the left and apply it for the right fence:

    if item and item.pos.x > 7 and item.pos.x < 71  :
        hero.moveXY(item.pos.x, item.pos.y)
    else:
        if item.pos.x < 8:
            hero.moveXY(item.pos.x + 2, item.pos.y)
        # code for the right fence

#10

I didn’t know this. I’ve never tried it before. Learned something today.

When I originally did this level I just used flags like it said to do in the directions and didn’t run into any of these problems.


#11

Hey, thanks for having a look at this. I figured that they couldn’t fetch coins. That part of the code was an experiment to see if the hero could collect coins even quicker with the help of its pet. For this, I don’t need the help of support since it seems it’s just a general thing that pets cannot do.

However, I still don’t know why the hero cannot collect items based on their value. With my code above, he should only collect gold and silver coins, shouldn’t he?

 if item and item.value == 3 or 2:
        hero.moveXY(item.pos.x, item.pos.y)

Instead, he just collects the nearest item (no matter if it’s a gold, silver, or bronze coin). For this, I still need support to figure out what is going on :slight_smile:


#12

see the execution of the following code at http://www.pythontutor.com

a = False 
b = 2
if a or b:
    print( 'What am I doing?')
else:
    print( "'if a or b' will never be False")

Do you see your error?


#13

It’s true that pets can’t collect coins, but if you’re the right level and have enough gems you can buy: “The Mimic”
which can’t fetch coins but it does act like a kind coin magnet and pulls coins towards it quite strongly.
So if you want your pet to help with collecting coins, i’d keep that in mind.
Btw I like your code and carry on coding!
:lion: :lion: :lion: Deadpool198


#14

Here are some troubleshooting tips. Test one thing at a time. Comment out your pet code and test your movement code.

while True:
    enemy = hero.findNearestEnemy()
    item = hero.findNearestItem()
    
    if item and item.value == 3 or 2:
        hero.moveXY(item.pos.x, item.pos.y)
        attackIfClose(enemy)
    petCollectsItem()

You find the nearest item and check its value
and then in the next loop you find the nearest item and check its value
and then in the next loop you find the nearest item and check its value
and then in the next loop you find the nearest item and check its value
and then in the next loop you find the nearest item and check its value
etc …

What happens if the same item is nearest every time and it’s not worth 2 or 3?

Also – are you sure about this syntax?

if item and item.value == 3 or 2:

2 == 2, so or 2 is always true. Your if statement says:

if item exists and has a value or 3 OR if 2 has a value of 2.

Maka


#15

Maybe I just can’t see the forest through the trees but I don’t get it. Even when I break up the if conditional like this:

if item:
    if item.value == 3
        hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 2:
       hero.moveXY(item.pos.x, item.pos.y)

and omit,

if item.value == 1

in an attempt to only collect coins that have a value of 2 or 3, it still doesn’t work. The hero just stands in one spot and doesn’t collect anything. I’m not understanding why. When I add,

if item:
    if item.value == 3
        hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 2:
       hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 1:
        hero.moveXY(item.pos.x, item.pos.y)

it works fine.

Por qué?


#16

In:

if item:
    if item.value == 3
        hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 2:
       hero.moveXY(item.pos.x, item.pos.y)

Which item is being checked? If a 1 value coin spawns next to you, it is the nearest Item – it remains the nearest item until something spawns even closer.

    if item.value == 3
        hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 2:
       hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 1:
        hero.moveXY(item.pos.x, item.pos.y)

Here, you check the nearest item – is it worth 3? Is it worth 2? Is it worth 1? It’s going to be one of these, so your hero moves.

What you want to do is check ALL items. Wooden Glasses (which are what @Reenow is wearing) don’t have the ability to do that – you’ll need Fine Wooden Glasses. This is the ability:

findItems :Returns an array of all items (example types ‘coin’, ‘gem’, ‘health-potion’) within eyesight ( visualRange m and line-of-sight).

(edit: got distracted and didn’t end the answer, here’s more)

After you get the array of all items, you can make a for loop that will check each item, one at a time, in the array, until it finds one worth 3, then move to get that item. But you’d still want your program to do something if there were no coins worth 3.


#17

Now I get it. Thanks.


#18

At least half of all programming is figuring out the logic of what you want to do. A good practice is to write it out in pseudo code – short native language versions of what you want to do

A simple version of this level might be

in a loop:
    look for nearest enemy
    look for nearest coin

    check if a there is an enemy and the distance < 10 meters
        attack them if they are
    
    check for an item
        get it

Then the code is

    enemy = hero.findNearestEnemy()
    item = hero.findNearestItem()
    
    if enemy and hero.distanceTo(enemy) < 10:
        hero.attack(enemy)

    if item:
        hero.moveXY(item.pos.x,item.pos.y)

But you do the planning first.


#19

Hey @maka, thanks a lot for these tips.

What happens if the same item is nearest every time and it’s not worth 2 or 3?

If the nearest item is not 2 or 3 the hero stands still because he doesn’t have an order for when there are value 1 coins and the pet cannot collect them because it just can’t. I think I understood that part.

Also – are you sure about this syntax?
if item and item.value == 3 or 2:
2 == 2, so or 2 is always true. Your if statement says:
if item exists and has a value or 3 OR if 2 has a value of 2.

I am confused what you mean by

2 == 2, so or 2 is always true.

I thought my if statement says: “If there is an item and if the value of this item is either 3 or 2 then…”

I like the way @MunkeyShynes split up the if statements so that it is clearer to read. I guess this is the difference to how the codes work. Can someone explain to me the differences between these two?

 if item and item.value == 3 or 2:
        hero.moveXY(item.pos.x, item.pos.y)

vs.

if item:
    if item.value == 3
        hero.moveXY(item.pos.x, item.pos.y)
    if item.value == 2:
       hero.moveXY(item.pos.x, item.pos.y)

And yes! I think I expected to see all items, when actually I just saw the nearest with Wooden Glasses. I haven’t learnt about for loops yet by the way.

Thanks as well for the pseudo code suggestion and for your patience. I feel sometimes I don’t understand things quickly enough but I’m still learning :slight_smile:


#20

or means also check this. So, it is actually checking:

if item and item.value == 3
or
if 2 == 2

You’d have to use parentheses to do have all this in one line:

I believe this is the correct syntax for Python:
if item and (item.value == 3 or item.value == 2)

But it’s confusing, especially for new learners. I’d suggest instead that you spread it out:

if item:
    if item.value == 3:
        hero.moveXY(item.pos.x,item.pos.y)

etc …

Maka