Computer Science 5, Level 30 "Reindeer Tender" will not function correctly

I have already gotten help within a previous post, which I appreciate, but the issue is that this help altered default code given to you when starting/resetting the level and still does not work properly. Instead of assigning reindeer to pens like it’s supposed to, it instead assigns all empty pens to a single reindeer (Vixen) excluding all pens already occupied, and then Vixen moves to the rightmost pen being the last pen they were commanded to move to.

// This is the array of pen positions
var penPositions = [ {x:20,y:24}, {x:28,y:24}, {x:36,y:24}, {x:44,y:24}, {x:52,y:24} ];

// Use this array to keep track of each pen's reindeer.
var penOccupants = [ null, null, null, null, null ];

// And this array contains our reindeer.
var friends = hero.findFriends();

// Figure out which reindeer are already in their pens.
var reindeer = null;
for (let deerIndex = 0; deerIndex < friends.length; deerIndex++) {
    reindeer = friends[deerIndex];
    
    // For each position check if it matches a reindeer.
    for (let penIndex = 0; penIndex < penPositions.length; penIndex++) {
        var penPos = penPositions[penIndex];
        
        if (penPos.x === reindeer.pos.x && penPos.y === reindeer.pos.y) {
            // Put the reindeer in occupants at penIndex
            penOccupants[penIndex] = reindeer;
            // Remove the reindeer from the friends array.
            friends[deerIndex] = null;
            // break out of the inner loop here:
            break;
        }
    }
}

// Assign the remaining reindeer to new positions.
for (deerIndex = 0; deerIndex < friends.length; deerIndex++) {
    // If the reindeer is null, use continue:
    if(reindeer === null){
        continue;
    }
    
    // Look for the first pen with nothing.
    for (var occIndex = 0; occIndex < penOccupants.length; occIndex++) {
        // If there is nothing, the pen is open:
        if (penOccupants[occIndex] === null) {
            // Put the reindeer in the occupants array.
            penOccupants[occIndex] = reindeer;
             // Command the reindeer to move to the pen.
            var targetPenPos = penPositions[occIndex];
            hero.command(reindeer,"move",targetPenPos);
            // break out early so we don't reassign:
            break;
        }
    }
}
hero.say(penOccupants)

This code block includes the hero.say I used for debugging when it comes to the occupants for each pen.

I am labeling this as, even with much help within a previous post, it does not work properly and the post has gone without replies for a long stretch of time, so I feel it is safe to assume it is a bug. If anyone knows any workarounds I can use or if I’m simply missing something (which could be considered a “bug” anyways because chances are it’s in the starter code which is meant to work properly, and you write maybe 5-10 lines on this level), it would be appreciated if you could put it here.

What is also frustrating is that I have attempted to write my own code to complete this level, to no avail. My custom code falls short, in a similar fashion that the code I currently have does. As far as I can tell, it is an issue with CodeCombat in some form and not me or my code, especially as I have tried multiple different approaches just for it all to end the same way. I even try just commanding them all to go to a pen that matches the reindeer’s index, and it works properly yet does not fulfil the objective anyways.

TL;DR the level won’t work properly, as the default code results in a unsatisfactory result that does not complete the level and should not occur, and similar issues occur with custom written code in multiple different approaches. Even taking a “cheaty” approach and having all the reindeer move to a pen that matches their index does not result in the level being cleared.

For situations like this where a level won’t work correctly, a “skip level” option would be nice.

Update: I have run my own independent code and have determined it is not my code causing the issues. I wrote a script that would accomplish the same objective outside of CodeCombat and wrote the same script in CodeCombat; the CodeCombat code failed.

It is good to note that my independent code did not fail. Also, I feel it important to list the details of it.

I used Python, being the language I am most confident with (I am using CodeCombat for school, learning JavaScript.), and created a script that used for loops to loop over the reindeer, in this script represented as lists which contain a name and a second list inside there containing their X and Y coordinates, with an index value as well because I found I needed an index and the variable used in python for statements contains the actual object of which is being iterated over and not it’s index.

This code ran over the pre-determined set of reindeer I created and detailed previously, and used identical X and Y values for the pen positions although this was not necessary. Two reindeer were already set in pen positions, the first and last pens, and the script correctly labeled the two in the precisely correct pens.

The problem came where I replicated this code within CodeCombat, using the same approaches but instead adapted to JavaScript. The JavaScript code, although functionally identical to my independent python code, failed to return any results into the pen occupancy list when two reindeer were inside pens and should have been added to the list.

This proves that either I failed to correctly write the JavaScript code, which I personally doubt as no errors were returned and all syntax looked perfect, or the issue stems in one of two factors: JavaScript itself or CodeCombat. This provoked me to create this topic.

The failure of the CodeCombat JavaScript code is not particularly shocking yet very frustrating. I have had experience in the past with CodeCombat not functioning as I expected, such as my first run with Web Development 2’s final level, the Quizlet project, where, even when the code was written and executed correctly, CodeCombat failed to recognize that I had completed objectives, leaving me stuck where I should not have been.

I may be incorrect, but through my trials with a separate script which worked perfectly whilst the CodeCombat script failed, I have no option in sight other than to label it as an error and put it here mainly for discussion in case of the event where the issue is not what I currently believe it to be but instead is an issue with my interpretation or execution of the code. Under my current beliefs it is a bug, yet I may be entirely incorrect.

While I do not have the original Python script, I will rewrite it here as accurately as possible and also leave the JavaScript script I wrote within CodeCombat.

Python Code

# [x,y,z] Z = the index to simplify and make my life a little easier. I recognize there are other ways to do it but this is how I chose to do it.
penPositions = [ [20,24,0], [28,24,1], [36,24,2], [44,24,3], [52,24,4] ]

penOccupants = [ None, None, None, None, None ]

#Would be hero.FindFriends, but this code isn't being written for CodeCombat since I'm writing it to discover if the problems are my code or CodeCombat/JavaScript. Reindeer not meant to be in a pen will have a, XY of 0,0.
friends = [ ["Dasher",0,0,0], ["Prancer",44,24,1], ["Dancer", 0,0,2], ["Comet",20,24,3], ["Vixen",0,0,4] ]

#Now we use for loops to iterate over all pens and all reindeer to identify which are in pens and which aren't.

for friend in friends:
	for penPos in penPositions:
		#Friend X index is 1, Y index is 2, Index index is 3
		if friend[1] == penPos[0] and friend[2] == penPos[1]:
			penOccupants[penPos[2]] = friend
			friends[friend[3]] = None
			break
print(penOccupants)

#Expected output: [['Comet', 20, 24, 3], None, None, ['Prancer', 44, 24, 1], None]] (Recieved Expected Output)

Expected code to correctly identify reindeer currently in pens and sleeping. Code managed to correctly identify reindeer in pens and place them in the correct index positions.

CodeCombat JavaScript Code

// This is the array of pen positions
var penPositions = [ {x:20,y:24}, {x:28,y:24}, {x:36,y:24}, {x:44,y:24}, {x:52,y:24} ];

// Use this array to keep track of each pen's reindeer.
var penOccupants = [ null, null, null, null, null ];

// And this array contains our reindeer.
var friends = hero.findFriends();
var reindeer = null;
for(var deerIndex = 0; deerIndex < friends.length; deerIndex++){
    var reindeer = friends[deerIndex];
    for (var penIndex = 0; penIndex < penPositions; penIndex++){
        var penPos = penPositions[penIndex]
        if(reindeer.pos.x == penPos.x && reindeer.pos.y == penPos.y){
            penOccupants[penIndex] = reindeer;
            friends[deerIndex] = null;
            break;
        }
    }
}
hero.say(penOccupants);

Expected attached JavaScript Code to identify and return reindeer currently in pens and sleeping, then using hero.say to print out the list of these reindeer in order to debug. Code failed to identify sleeping reindeer.

From these results I can in general safety state that the problem lies in either JavaScript, me, or CodeCombat, and my previous experiences and prior knowledge leads me to lean closer towards it being either JavaScript or CodeCombat and the problem being me and how I wrote my independent Python script to test my approach does not seem likely.

It is good to note the Python script I put here is not my original script when first testing for the issue. However, the only difference is the X and Y values of the reindeer are not embedded in their own list inside the list, but this difference makes no change to the performance and end result of the script.

Quick Update. I have identified the issue, where the for loops in the JavaScript/CodeCombat script are skipped over. It is specifically the second for loop, which is ignored entirely when no code is put in place to cause that. This is no doubt an issue with CodeCombat itself. This needs to be fixed.

Good to note that it is so far exclusively Reindeer Tender. Previous levels do not have this issue.

Codecombat uses an old version of javascript and the rules of the js in codecombat are a bit different because they want to limit the chance that someone finds an exploit that breaks the entire game, for example modifying Math would no doubt collapse the entire structure of the level :sweat_smile: (if they didn’t have these securities in place, of course)

This sadly introduces an unintended error that does not seem to have been taken into account when this level was originally made. There has to be a workaround which I would love, but at this point it might be worth to introduce a level skip button. To prevent users from spamming it I would introduce a gem cost per level skip, specifically so there is incentive to only use it when stuck on a level and you are unable to get past it. It’s even possible to prevent users from using level skip when on levels that teach the basics, so that they don’t skip levels with crucial information for understanding their target language over a simple syntax error that they missed.

UPDATE - I have identified the source of the issue and have moved passed the level (With some help from a fellow classmate).

This makes it less of a bug, but this does still need to be fixed.
Before

there needs to be a line that assigns reindeer to the deerIndex of friends, like so:
reindeer = friends[deerIndex];
However, the comments do not tell you to do so and it is up to the player to figure that out. In my case, I missed that.