"Buddy's Name" Level - hints inconsistent (+ other functions lvl pain)

I’m really new to this, and am finding some real pain with certain function levels, because I don’t have the experience to differentiate a bug in CC’s game and user error.

One thing I’m pretty sure is a bug:
Buddy’s Name level: pre-defined event handler appears to be onHear, but Hints also reference sayName. Calling sayName leads to an error, and user is advised not to change the function called (so the name matches.)

Final code, calling onHear worked, but documentation needs to be updated.

Added Note: the next level in the series, Buddy’s Name A, is also buggy. It goes back to referencing “sayName”, which is fine because it can be consistent with user’s code, but when the function is called, it only returns the first line, and never the second one.

# The peasant wants to know your pet's name.

# Use this function as the handler for "hear" events.
def sayName(event):
    # The pet will say these in order when this function is called.
    pet.say("My name is Furious Beast.")
    pet.say("But my friends call me Fluffy.")
    
# Use pet.on("eventName", functionName) to add an event listener to your pet.
# In this case use "hear" and sayName with pet.on()!
pet.on("hear", sayName)

# You don't need to say anything this time!
# The peasant will do the talking.

In a much more amorphous issue: Tomb Raider level would not actually run some called functions when player avatar was Arryn. Exact same code with Hattori worked perfectly. They both have the same gear.

# A forgotten tomb in the forest!
# But the ogres are hot on your heels.
# Break open the tomb, while defending yourself from the munchkins.

# This function should attack an enemy if it exists, otherwise attack the door!
def checkToDefend(target):
    # Check if the `target` exists
    if target:
        # If so, attack the `target`
        hero.attack(target)
    # Use an else to do something if there is no `target`
    else:
        # Otherwise attack the "Door"
        hero.attack("Door")


while True:
    enemy = hero.findNearestEnemy()
    checkToDefend(enemy)

I met with several function levels, right when the topic was introduced, that seemed to have bugs of this nature. It frustrated me greatly, not understanding what I was doing wrong… in some cases I still don’t. Would someone help me with this please?

2 Likes

Welcome to the forum @DoesNotCompute! :partying_face: This is a friendly place where you can ask help on levels, report bugs, or just chat with other coders! Don’t forget to read the guidelines if you haven’t yet. Have a great time!

I believe here, you should call the name of the function instead on line 14, I know the hints make a little confusion, but you should stick with what you have.

Hint

sayName is not defined in your code, that’s why it must be arising an error. You should use the function that is already there. Hint: onHear

1 Like

Hello Aya,

Thank you for taking the time to help me. :slight_smile: You are absolutely right, that calling the alternate function name, not in the hints fixes the problem. (Not saying it cuz spoilers.) I just wanted to encourage an update to the documentation.

It’s my own fault for burying the lead, but the real “bug” or issue I’m having was below that, when calling functions result in them only returning part of the defined function.

Ex. was second buddy name level, it kept repeating “My name is Furious Beast”, without ever saying “But my friends call me Fluffy.”

It was super weird because that happened on a couple of levels, and even more oddly, the behavior changed with different avatars - who were wearing the same gear. With Arryn in Tomb Raider, only the first part of the defined function was working, so she attacked the door, even when getting smacked by an ogre. When I swapped in Hattori without changing the code, it worked. Not sure how to fix that problem.

Thanks again, and have a good evening.

DNC

3 Likes

Oh, I see, maybe @Chaboi_3000 or @Bryukh can help, as it is most probably a bug.

Hi @DoesNotCompute.
First of all, that buddy’s name documentation is definitely incorrect, so if you want you could submit patch (or I could). If you don’t know how, you go to CodeCombat - Coding games to learn Python and JavaScript then search up the level name. You can then change the documentation under one of the tabs in the taskbar of the level editor and press the top right button to submit a patch: it should be accepted reasonably soon (but I have known them take like a year so, who knows, we can only hope).
The next bit I’m a bit confused by because my pet does say both lines, and then after that says the first line twice. I think that might be because the peasant says two things, so it interrupts and resets the function before it can run the second line. However, my pet did say both lines at first:
Screen Shot 2021-11-01 at 21.45.17
About Tomb raider. The code works for me. Well, at least, it does what the code that they’ve told you to write does, but it doesn’t do what the comments say (if you see what I mean).
They say:

# This function should attack an enemy if it exists, otherwise attack the door!

However, the code they’ve provided (and told you to write with the comments), pretty much says:
Attack the nearest enemy (which, bear in mind, includes the door. It is, after all, an enemy), and if there aren’t any, then attack the door specifically.
This point can be proven by removing the else: hero.attack(“Door”) because the code does exactly the same thing.
Interestingly, if you use one of the basic heroes, they prioritise killing the munchkins over the door more than the paid heroes. This must be to do with their size and special characteristics, because the only reason the hero would attack the munchkin over the door (which are both enemies) is if the munchkin approaches closer to the hero than the hero is to the door (hero.findNearestEnemy()). It was probably playtested with a basic hero, and the fact that the code worked purely by accident must not have occurred to them. (unless it was a sneaky trick to teach you dodgy coding).
Again this is proved by the fact that the else line doesn’t run (even when using a basic hero, where exactly what is described in the comments happens): Note the lack of a tick by the left of line 13, which signifies whether the line has been run or not:


I hope this made sense and helped, and wasn’t too boring to read!
Danny

4 Likes

“unless it was a sneaky trick to teach you dodgy coding” :laughing:
maybe sloppy is the more accurate word :slight_smile:
you can test what the code is doing by your pet:

def deDuck():
    while True:
        enemy = hero.findNearest(hero.findEnemies())
        if enemy:
            pet.debug(enemy.type,round(enemy.health))

pet.on("spawn",deDuck)

the default code has the same effect as:

while True:
    enemy = hero.findNearest(hero.findEnemies())
    if enemy:
        hero.attack(enemy)


Super minimal armour (22 maxHealth), no boots, no glasses, weakest sword.

If you really want to defend the hero initial position you can make it like this:

I notice the door is invincible until you kill five munchkins, so even this code will work:

I don’t like the default code because
1: it uses
it’s much better to write \

hero.attack(enemy) 
# or even 
hero.attack(enemy.id)

2: Never use hero.findNearestEnemy() when you have to prioritize one type over another - use findNearest() from an array of enemy type with hero.findByType(), a function you wrote or use the pattern

munchkin = hero.findNearest([e for e in hero.findEnemies() if e.type == "munchkin"])

because you have the enemy with all her/his/its properties and methods, even in the fist levels, when you have a basic equipment.

For the other level the visualization is wrong, the code is OK, the hints are wrong
the test code:

def sayName(event):
    message = event.message
    speaker = event.speaker
    if speaker == hero:
        if _.contains(message,"name"):
            pet.say("My name is Furious Beast.")
            pet.say(" ")  # repeat it 4 times
        if _.contains(message,"repeat"):
            pet.say("Furious Beast but my friends call me Fluffy.")
            pet.say(" ") # repeat it 4 times
            
pet.on("hear", sayName)

hero.say("What's you name, buddy?")
hero.say("Could you repeat it?")

Your pet needs to say 10 phrases.

sorry for the wall of pictures and text :slight_smile:

1 Like

Thanks to all three of you! @Aya @Deadpool198 @stormbringer All of you were helpful and friendly, and none of you were “boring”. (I noticed some apologies for giving too much in response, but they were precisely what I needed, so thank you.)

Aya: thanks for the welcome and prompt support. This is possibly the best forum experience I’ve ever had - others can be slow, unresponsive, or provide advice that doesn’t address the need - and that is assuming everyone is being friendly and trying their best. You (and all the others) are terrific.

First, Deadpool, I really appreciate you taking the extra time to teach a newbie to fish (or, at least to submit a patch for approval). :smile: Since changing the hints are unlikely to break anything downstream, and especially since you agreed it was incorrect, I felt confident enough to make the change myself. I will continue to do so when I feel like I have a handle on the appropriate solution. If you feel inspired to double-check my work for this case: CodeCombat - Coding games to learn Python and JavaScript (Under Settings < Documentation)

Hopefully, this resolves the problem I noted with “Buddy’s Name”.

For clarity, I will create other forum responses (in the same open thread) for the other issues.

Thanks for all you help. It’s much appreciated!

DNC

3 Likes

Wow, @stormbringer and also @Deadpool198 - this response is exactly what I needed!

Deadpool and Stormbringer - about Tomb Raider

Yes, I think you both were spot on about the root of the problem. The recommended code does not differentiate in any way among enemies, and “Door” is an enemy, even though the prompts imply otherwise.

Without being ready to delve into the source-code for each avatar’s behaviors, I agree with the suspicion that certain “beginner” or free avatars have some pre-defined affinity for attacking munchkins over doors, or some different attack radius which allows active attackers to move closer than the avatar-door distance when the avatar attacks.

I tried Storm’s code, which worked, however I am going through the lessons (mostly) in order, and the concept of “arrays” has not been broached, much less the appropriate treatment and syntax. With the example code Stormbringer sent, I could pretty much figure out what was happening, but do not feel prepared yet to create my own.

I think the changes needed here go well beyond my comfort level, knowing how disruptive it could be downstream. How can I get this to the right people to fix?

Possible Solutions to the underlying problem at CoCo’s end: (There may be other, better choices, but this can get the brainstorming started.)

Cheap, slow and cludgy, but probably reliable: Add prompts in code to make hero move to bottom of screen after each hit (on the door, or against a munchkin), and then search for hero.findNearestEnemy(). This should result in mobile enemies being identified as “nearest” so they can be killed. After a pre-defined number of enemies, a long (or infinite) interval without new spawns should be included in level design, to ensure that low-DPS heroes eventually get to target the door. It’s annoying and slow, but it relies only on code/concepts previously introduced, provides a novel - but easily understood - method to force a different “nearest” enemy identification, and helps learners recognize how both ogres and doors are treated as enemies.

Cheap, sloppy and maybe less reliable: Restrict avatars for this level to those whose pre-defined properties ensure the recommended code actually preferentially targets munchkins. It’s sloppy because it implies to learners that doors are NOT enemies, which is untrue. It’s “maybe” less reliable because it creates a dependency upon the “munchkin-preferred” attributes of certain avatars. If this special behavior is due to complex interactions and/or is not considered when patching these characters, it could later cause this “fix” to break… and it may not be as easy to identify at that time.

Expensive and messy, but pedagogically suitable: Set special attributes for all avatars to ensure “munchkin preferential attack” in this level. Ensure the learners know this is a special case they will get to later, so they don’t make assumptions about these behaviors. I expect that making a lot of special rules for individual levels is expensive (and messy), and can lead to level designers making incorrect assumptions about expected behaviors if they don’t know it is a special case.

Bigger change, with outcomes beyond my ability to predict: Redesign and move this level to an appropriate point in the course of study to implement arrays. It might leave a gap in the practice levels for defining simple functions.

How can we get this fix to happen? Any better ideas or comments?

Thanks,
DNC

1 Like