The Two Flowers (JavaScript) Problem


#1

Heyo. I’ve been struggling with this level for over an hour now. I cannot figure out why the soldiers will not attack the enemies. They just stand there. That tells me there is a problem with the commandSoldiers function, as the other two functions appear to be working correctly: the hero collects coins and summons units. It appears that the enemy variable is not being populated for some reason, because if I try to say the contents of the enemy variable (commented out in provided code), I get a “Say what?” error message.

Any assistance would be appreciated.

// If the peasant is damaged, the flowers will shrink!
this.summonSoldiers = function() {
    if (this.gold >= this.costOf("soldier")) {
        this.summon("soldier");
    }
};
// Define the function: commandSoldiers
this.commandSoldiers = function() {
    for (var soldier in soldiers) {
        var enemy = soldier.findNearestEnemy();
        if (enemy) {
            //this.say(enemy)
            this.command(soldier, "attack", enemy);
        }
    } 
};
// Define the function: pickUpNearestCoin
this.pickUpNearestCoin = function() {    
    var coin = this.findNearest(this.findItems());
    if (coin) {
        this.move(coin.pos);
    }
};   
var peasant = this.findByType("peasant")[0];
var soldiers = this.findByType("soldier");
var coins = this.findItems();
loop {
    this.summonSoldiers();
    this.commandSoldiers();
    this.pickUpNearestCoin();
}

#2

In this.commandSoldiers, you have a for-loop for (var soldier in soldiers) {. However, soldiers is not defined. That is most likely your problem.


#3

soldiers is defined further below in the code. The problem is that you were not updating it. So, the soldiers variable contains the list of soldiers before you ever start the loop … so it is empty and remains so.

I’m pretty sure you need to update your soldiers array each time you summon. Alternatively, have you thought of using the self.built() array [ok - that’s python. I’m guessing it would be this.built() in javascript.] to iterate through the soldiers?


#4

ChronistGilver & Msakr – Thanks for the assist attempt guys! :beers:

Just wanted to provide an update that could possibly help others. Spent another couple of hours trying to work out the issue while uttering some choice words :rage: . Decided to use the long hand version of the for loop instead of using “for x in y” and the code finally worked. Also added in the obligatory null checks. Apparently, even thought the for-in is a valid JavaScript statement, the CodeCombat compiler does not like that syntax, as it would throw the not-a-function error on soldier.findNearestEnemy().


"Note: for…in should not be used to iterate over an Array where the index order is important."

Not sure if the caveat above is why the code was failing, I don’t think it was the reason, as the index order was not important, unless something is happening behind-the-scenes with the hero functions that does apply some form of index ordering.

Spoiler Alert |||||||||| Working function below!!!


// Define the function: commandSoldiers
this.commandSoldiers = function() {
    var soldiers = this.findByType("soldier");
    if (soldiers){
        for (var index = 0; index < soldiers.length; index++){
            var soldier = soldiers[index];
            var enemy = soldier.findNearestEnemy();
            if (enemy){
                this.command(soldier, 'attack', enemy);
            }
        }
    }
};

#5

In JavaScript, for soldier in soldiers will iterate over the keys of the array, so you will get 0, 1, 2, etc. instead of the first soldier, the second soldier, the third soldier, etc. That’s partially why MDN doesn’t think you should use for-in loops over arrays: you get keys, not values. That’s why the normal for loop is better for JS. In Python the for-in loop does the sane thing and iterates over the list’s values, so it’s a lot easier.


#6

Ah, I see. Appreciate the clarification. :+1:


#7

Hm - so in javascript, you wouldn’t have to re-update the enemies definition from time to time?

Separately, congrats on finding a solution!