0

I'm working on exercism question and am stuck on one of the jasmine-node based tests, which says that I should be able to generate 10000 random names without any clashes (e.g. 2 randomly generated names match). This is the test:

it('there can be lots of robots with different names each', function() {

    var i,
    numRobots = 10000,
    usedNames = {};

    for (i = 0; i < numRobots; i++) {
      var newRobot = new Robot();
      usedNames[newRobot.name] = true;
    }

    expect(Object.keys(usedNames).length).toEqual(numRobots);

});

What I think I need to do is:

  1. Create an array to hold all the names (robotNames),
  2. Each time a name is generated, check if it exists in the array,
  3. If it does, generate another name,
  4. If it doesn't, add it to the array.

And here is my code so far...

"use strict";

var robotNames = [];
var name;

var Robot = function() {
    this.name = this.generateName();
};

Robot.prototype.generateName = function() {

    var letters = "";
    var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    var numbers = "";
    var digits = "0123456789";

    // generate random characters for robot name...

    for( var i=0; i < 2; i++ ) {
        letters += alphabet.charAt(Math.floor(Math.random() *    alphabet.length));
    };

    for( var i=0; i < 3; i++ ) {
        numbers += digits.charAt(Math.floor(Math.random() * digits.length));
    };

    name = letters+numbers;

    // Loop through array to check for duplicates

    for(var i = 0; i < robotNames.length; i++) {
        if (name == robotNames[i]) {
            this.generateName();
            return;
        } else {
            robotNames.push(name);
        }
    }

    return name;
};

Robot.prototype.reset = function() {
     this.name = this.generateName();
};

module.exports = Robot;

The test fails with an error message: "Expected 9924 to equal 10000."

The '9924' number is slightly different each time I run the test. I'm thinking this means the generateName function is eventually generating 2 matching random names. It seems as though my loop for checking duplicates is not being run and I'm not sure why.

I have tried a couple of different versions of the loop but with no success. So my questions is a) is my approach correct and there is something wrong with the syntax of my loop? or b) have I got the wrong idea about how to check for duplicates here?

Any pointers appreciated, thanks.

4
  • 1
    Try this: return this.generateName(); instead of this.generateName(); return. I'm betting you are having empty names in usedNames. Commented Feb 3, 2016 at 22:17
  • There might be a problem with robotNames.length. Try for(var i = 0, len = robotNames.length; i < len; i++) instead of for(var i = 0; i < robotNames.length; i++). Commented Feb 3, 2016 at 22:21
  • @Kenney - Yes, I didn't understand that I had to return this.generateName() in the loop, I though just putting this.generateName() would run the function. Thanks! Commented Feb 3, 2016 at 22:29
  • 1
    It does run the function, you understood correctly - but your Robot constructor does this (as does Robot.reset): this.name = this.generateName(); and so your test would get an empty value for newRobot.name. So there were 2 problems - this one, and the one @Emile pointed out regarding the for loop. Commented Feb 3, 2016 at 22:36

2 Answers 2

1

The problem is in this bit:

for(var i = 0; i < robotNames.length; i++) {
    if (name == robotNames[i]) {
        this.generateName();
        return;
    } else {
        robotNames.push(name);
    }
}

...you probably only want to push your name if NONE of the names fail to match. Here you're adding it to the list as soon as you find ONE that doesn't match. You want something more like:

for(var i = 0; i < robotNames.length; i++) {
    if (name == robotNames[i]) {
        return this.generateName();
    }
}
robotNames.push(name);

(actually, combined with the fact that you weren't even returning the recursive call to this.generateName(), I'm not sure how your program could work...)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, your answer works perfectly. And yes, I didn't understand that I had to return this.generateName() in the loop, I though just putting this.generateName() would run the function. Cheers!
0

Find a library with an implementation for Sets. Collections.js is a good example.

One property of a set is that it doesn't have duplicates. So when you add a value to a set it will look for a duplicate and then add the value if no duplicate exists.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.