Brawl Levels and Coding Q&A


#1

First order of business, this thread had been made solely for the purpose of asking the community to help with problems with your code and helping those people. If there is a problem you do not know how to fix, post it here. If you have made some code you believe will pique somebody’s interest, post it here. If there is a certain obstacle you do not know how to get around, post your problem here. If you just want to have a good jaw about code and codecombat, post it here! Note: This forum is only in javascript!


#2

This entire forum and community is made for the purpose of asking the community to help with problems with your code and helping those people. I’m not quite sure this thread is needed.


#3

Hey, so, I have been completely immersing myself in the brawl levels, since I have always been fascinated by progressive gameplay. Each time I unlock something new, or learn how to do something new, I try it, and fix the bugs. Recently I have been having trouble with my hero focusing on a single enemy. I understood why, I knew that that was what I programmed it to do, but I couldn’t figure out how to make the hero attack enemies if there were a certain number or more of them within a certain distance. This was a problem since I made my hero prioritize shamans over throwers, throwers over scouts, scouts over ogres, and ogres over munchkins. I made her prioritize like this because I previously set up the code to attack the nearest enemy, but when throwers showed up, they would continue attacking her while she was only worried about the nearest enemies, the munchkins, so I made her attack the throwers before attacking anything else, then I added more enemies is the priority order I saw fit as I discovered them. I wrote this code to address this. For each enemy, it checks if electrocute is ready, and if it is, checks if the enemy can be electrocuted, and if it can, it electrocutes the enemy, but if either of those conditions aren’t met, it checks if cleave is ready, if it is, it cleaves the enemy, if it isn’t, it checks if bash is ready, if it isn’t, if just attacks the enemy, but if there is no enemy of that type, it moves on to the next type of enemy, and so on and so forth. The only problem though, is that if it detects an enemy, and none of the special moves are ready, she goes up to it to attack it, but if the enemy is far enough away, all the other enemies that are faster than me start following her and kill her on the way there since she is only targeting the one enemy. My code looked like this:

loop{
    enemies=this.findEnemies();
    shaman=this.findNearest(this.findByType("shaman", enemies));
    thrower=this.findNearest(this.findByType("thrower", enemies));
    scout=this.findNearest(this.findByType("scout", enemies));
    ogre=this.findNearest(this.findByType("ogre", enemies));
    sandyak=this.findNearest(this.findByType("sand-yak", enemies));
    enemy=(this.findNearest(enemies));
    if(shaman){
        if(this.isReady("electrocute")){
            if(this.canElectrocute(shaman)){
                this.electrocute(shaman);
                continue;
            }
        }else{
            if(this.isReady("cleave")){
                this.cleave(shaman);
                continue;
            }else{
                if(this.isReady("bash")){
                    this.bash(shaman);
                    continue;
                }else{
                    this.attack(shaman);
                    this.attack(shaman);
                    this.attack(shaman);
                    continue;
                }
            }
        }
    }else{
        if(thrower){
            if(this.isReady("electrocute")){
                if(this.canElectrocute(thrower)){
                    this.electrocute(thrower);
                    continue;
                }
            }else{
                if(this.isReady("cleave")){
                    this.cleave(thrower);
                    continue;
                }else{
                    if(this.isReady("bash")){
                        this.bash(thrower);
                        continue;
                    }else{
                        this.attack(thrower);
                        continue;
                    }
                }
            }
        }else{
            if(scout){
                if(this.isReady("electrocute")){
                    if(this.canElectrocute(scout)){
                        this.electrocute(scout);
                        continue;
                    }
                }else{
                    if(this.isReady("cleave")){
                        this.cleave(scout);
                        continue;
                    }else{
                        if(this.isReady("bash")){
                            this.bash(scout);
                            continue;
                        }else{
                            this.attack(scout);
                            this.attack(scout);
                            this.attack(scout);
                        }
                    }
                }
            }else{
                if(ogre){
                    if(this.isReady("electrocute")){
                        if(this.canElectrocute(ogre)){
                            this.electrocute(ogre);
                            continue;
                        }
                    }else{
                        if(this.isReady("cleave")){
                            this.cleave(ogre);
                            continue;
                        }else{
                            if(this.isReady("bash")){
                                this.bash(ogre);
                                continue;
                            }else{
                                this.attack(ogre);
                                this.attack(ogre);
                                this.attack(ogre);
                                this.attack(ogre);
                                this.attack(ogre);
                                this.attack(ogre);
                                continue;
                            }
                        }
                    }
                }else{
                    if(sandyak){
                        continue;
                    }
                    if(enemy){
                        if(this.isReady("electrocute")){
                            if(this.canElectrocute(enemy)){
                                this.electrocute(enemy);
                                continue;
                            }
                        }else{
                            if(this.isReady("cleave")){
                                this.cleave(enemy);
                                continue;
                            }else{
                                if(this.isReady("bash")){
                                    this.bash(enemy);
                                    continue;
                                }else{
                                    this.attack(enemy);
                                    this.attack(enemy);
                                    this.attack(enemy);
                                    continue;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

So, after I finally thought I new how to use arrays, I changed the first section of the code, like this:

loop{
    enemies=this.findEnemies();
    enemiesArray=[];
    if(enemies){
        enemiesDistance=this.distanceTo(enemies);
    }
    while(enemiesDistance<5){
        enemiesArray.push(enemies);
    }
    if(enemiesArray.length>2){
        if(this.isReady("cleave")){
            this.cleave(this.findNearest(enemies));
            continue;
        }
    }else{
        enemies=this.findEnemies();
        shaman=this.findNearest(this.findByType("shaman", enemies));
        thrower=this.findNearest(this.findByType("thrower", enemies));
        scout=this.findNearest(this.findByType("scout", enemies));
        ogre=this.findNearest(this.findByType("ogre", enemies));
        sandyak=this.findNearest(this.findByType("sand-yak", enemies));
        enemy=(this.findNearest(enemies));
        if(shaman){
            if(this.isReady("electrocute")){
                if(this.canElectrocute(shaman)){
                    this.electrocute(shaman);
                    continue;
                }
            }else{
                if(this.isReady("cleave")){
                    this.cleave(shaman);
                    continue;
                }else{
                    if(this.isReady("bash")){
                        this.bash(shaman);
                        continue;
                    }else{
                        this.attack(shaman);
                        this.attack(shaman);
                        this.attack(shaman);
                        continue;
                    }
                }
            }
        }else{
            if(thrower){
                if(this.isReady("electrocute")){
                    if(this.canElectrocute(thrower)){
                        this.electrocute(thrower);
                        continue;
                    }
                }else{
                    if(this.isReady("cleave")){
                        this.cleave(thrower);
                        continue;
                    }else{
                        if(this.isReady("bash")){
                            this.bash(thrower);
                            continue;
                        }else{
                            this.attack(thrower);
                            continue;
                        }
                    }
                }
            }else{
                if(scout){
                    if(this.isReady("electrocute")){
                        if(this.canElectrocute(scout)){
                            this.electrocute(scout);
                            continue;
                        }
                    }else{
                        if(this.isReady("cleave")){
                            this.cleave(scout);
                            continue;
                        }else{
                            if(this.isReady("bash")){
                                this.bash(scout);
                                continue;
                            }else{
                                this.attack(scout);
                                this.attack(scout);
                                this.attack(scout);
                            }
                        }
                    }
                }else{
                    if(ogre){
                        if(this.isReady("electrocute")){
                            if(this.canElectrocute(ogre)){
                                this.electrocute(ogre);
                                continue;
                            }
                        }else{
                            if(this.isReady("cleave")){
                                this.cleave(ogre);
                                continue;
                            }else{
                                if(this.isReady("bash")){
                                    this.bash(ogre);
                                    continue;
                                }else{
                                    this.attack(ogre);
                                    this.attack(ogre);
                                    this.attack(ogre);
                                    this.attack(ogre);
                                    this.attack(ogre);
                                    this.attack(ogre);
                                    continue;
                                }
                            }
                        }
                    }else{
                        if(sandyak){
                            continue;
                        }
                        if(enemy){
                            if(this.isReady("electrocute")){
                                if(this.canElectrocute(enemy)){
                                    this.electrocute(enemy);
                                    continue;
                                }
                            }else{
                                if(this.isReady("cleave")){
                                    this.cleave(enemy);
                                    continue;
                                }else{
                                    if(this.isReady("bash")){
                                        this.bash(enemy);
                                        continue;
                                    }else{
                                        this.attack(enemy);
                                        this.attack(enemy);
                                        this.attack(enemy);
                                        continue;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

The only problem with it though, is that I apparently don’t know how to use the distanceTo command. Every time, it says, Line 9: Find the distance to a target unit. Plz help me! How do you use distance with arrays?


#4

Erm, well, I’ll edit it. This one is specifically for javascript, and in most threads, you can’t just talk about interesting things, you have to talk about the individual problem, so this forum was also created for that.


#5

Don’t mean to be overly rude, but how have you been on the forums for over a month and not learned how to format your code? I’m sure Chronoist is going to end up fixing it for you, because from my observations he’s a nice guy who does that sometimes. But that doesn’t excuse you for not doing it yourself.


#6

Yes, as BigPanda says, please learn how to format your code. I can’t be watching over you every hour of the day, and it’s a good skill to have anyway.

The problem is, you can only use distanceTo on a single object, e.g an enemy, an item, etc. An array is a list of objects. I’ve told you this before, but you need to loop over the array using a while-loop and an index to go over each thing inside.


#7

Aghh! So much duplicated code! It Burns! It Burns us… It freezes… Take it off us!

  1. distanceTo needs to be called with a single enemy as argument, not as a list. Here’s an incomplete example that figures if there are enough enemy nearby to warrant a cleave
cleave_count=0;
for(i=0;i<enemies.length;i++)
     if(this.distanceTo(enemies[i] <= CLEAVE_RANGE)
            // count enemies here
  1. If you use this.moveXY to chase enemies, then your hero will go all the way to destination before any other instruction is executed. If the destination is far away, then new near enemies can appear but the hero will not know about them because he is still trying to complete his move.

The solution is to use this.move which only instructs the hero to move for one game engine frame (1/30 seconds). If he reaches the destination, good. If not, after 1/30 the code skips to the next instruction. This might be the start of your next loop code where the nearest enemies are searched for again, giving the hero a change to change its destination.

The advanced coding approach is to compute a move vector of shorter magnitude. Example: if you want to move from (0,0) to (3,4) at 5m/s it will take a second. But you can move in (0.6, 0.8) steps and each step will take 0.2seconds only.

  1. Do not repeat code, use a general array which decides every strategic decision in your game.
enemyDef=[];
enemyDef.type=["muchkin","thrower","shaman"];
enemyDef.priority=[1,3,2];
enemyDef.engage_distance=[7,5,5];
enemyDef.chase_distance=[10,20,20];

you can keep adding as much strategic data as you want (health, dps, …)
Again, incomplete code:

for(i=0;i<enemies.length;i++)
    distance=this.distanceTo(enemies[i]);
    index=enemyDef.type.indexOf(enemies[i].type);
    //index will decide the data used for all your decision code    
    if(distance < enemyDef.chase_distance[index]) 
    //he is near
           if(priority < enemyDef.priority[index])
                     //annoying type also
                     if( nearestdistance < distance)
                              //and so on

#8
  1. You have a repeated this.attack(enemy);
    The number of hits a enemy take depends on your hero, current weapon, allies damage so your code fail easily.
    Just attack once. If the enemy is still around you’ll find it again in the next loop iteration.

#9

Ok, thx for all the help. I didn’t know that I didn’t need to repeat the attack command, and I didn’t know that there were move and priority commands, and I forgot that DistanceTo only focused on a single target at a time. Now, BigPanda, I actually don’t know how to format my code, this is only my third ever topic, and the only one that I’ve put code in, and ChronistGilver, I don’t know how to use arrays, and I didn’t know what you meant when you told me the first time! I am not very good at that. I need to see the actual code, because I have no idea how to use arrays! This is kinda why I put this topic here, to help people who have no idea how to use certain kinds of code, so plz, someone post a thorough tutorial on how to use arrays on here, along with code examples of arrays, plz! Thx. If I’m sounding overly dramatic, plz tell me, because I don’t want to be overdramatic.


#10

Everything you need to know about arrays:
Disclaimer: there is a bit more but you can do absolutely everything by using just the info below

  1. What is an array?. An array is an indexed list of values. Indexed means that we can access a value by their number = position in the list
var myarray=["banana", "mango","apple"];
// myarray[0] will be "banana", the 1st value
// myarray[1] will be "mango", the 2nd value
// myarray[2] will be "apple", the 3rd value
// Yes, indexes start from 0. Might be confusing but you'll get used to it!
  1. You can access the array elements by indexing them. Most commonly, you will want to search through each element of the array.
    To do this know that the size of an array is given by the array_name.length and the indexes go from 0 to length-1 (do the math, there are length values in total).
    Here is a code that finds the nearest enemy:
minDistance=Infinity;
nearest=null;
for(i=0;i<enemies.length;i++) 
// notice enemies.length is the size of the enemies array
   distance=this.distanceTo(enemies[i]);
   //we are working with the enemies[i] value
   //since the for goes from i=0 to i=length-1, enemies[i] will go from 
   //enemies[0] to enemies[length-1] 
   //meaning that will be looking at each array value, one after another
  if(distance < minDistance){   
     // it is closer than any other enemy found so far
     minDistance=distance;
     nearest=enemies[i];
  }
}
  1. You can modify an array by adding or removing elements from any position in the array. I am showing you only 3 operations, there are enough to do everything:
    3.1) replace an array value with a new value
myarray=[5,6,7];
myarray[1]=10;
//remember indexes start from 0. 1 is actually the 2nd element
// now my array will be [5,10,7]

3.2) add an element to the back of the array:

myarray= [];
//this is how you declare an empty array
myarray.push(3); 
//push adds an element at the back of the list
//myarray is now [3]
myarray.push(5);
//myarray is now [3,5]

3.3) select elements from an array and generate a new one
Go though the first array and add everything nice to the new one

myarray={"muchkin","orgre","munchkin","thrower","ogre"}
newarray=[];
//this is how you declare an empty array
for(i=0;i<myarray.length;i++)
  if (myarray[i] != "ogre")
       // ogres are bad, lets throw them away
       newarray.push(myarray[i]);
      // if myarray[i] is not an ogre, then add it to the newarray
// now newarray will be {"muchkin","munchkin","thrower"}

See: W3Schools JavaScript Arrays
to learn about indexOf, pop, shift,unshift,concat, slice,splice and other intimidating things.
Thrust me, you can already do everything you what I already said.


#11

I like the subject, but the current discussion seems a bit off topic. To be back on topic, I share with you the best trick to learn:

  • beat a level (should not be a problem on the lowest difficulty)
  • go back to the map
  • click on the level name
  • click in the “difficulty” section
  • select a replay and watch!
screenshot

You will see the submitted code, and you can even change it and run it as if you were the person who submitted it (including hero, items, etc).

Note:

  • some levels’ “all time” leaderboard has bogus entries which will not load – in this case select the “this week” or the “damage dealt” board
  • this works for all levels!

Here is a an example replay:


Later, you may also want to learn about fleeing (warning: advanced trickery!) for example in this topic

Also, using the non-free heroes gives much more possibilities to fight (ranged weapons, spells, etc).

Cheers