Search code examples
javascriptjqueryarraysrandomextend

Built jQuery extension, but not allowing max return values


I put together a jsfiddle of the problem here: https://jsfiddle.net/sd1x3am3/5/

Basically, I built an extension called $.generateSerial which takes 3 parameters. The first parameter is a formula, the 2nd is the characters allowed, and the 3rd is the serials to not include in the return value. Basically, the extension allows you to generate a unique, random serial that is none of the serials in the 3rd parameter, and none of the serials that are returned within the output variable each time $.generateSerial gets called within the for loop.

For some reason, $.generateSerial returns "" within the loop when i = 146, but there should be more values for it to return, so it should not return "".

The formula is XXXX-XXXX-XXXX-XXXX and the chars allowed are: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789, which means any of these chars can replace any of the X chars in the formula. But there should be more than 145/146 results returned, not counting what is within the currSerials array. There should be way more serials that can be generated.

But I can't figure out why it is not generating all of the possible serials and stopping...

$.extend({
    generateSerial: function(formula, chrs, checks) {
        var formula = formula && formula != "" ? formula : 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // Default Formula to use, should change to what's most commonly used!
            chrs = chrs && chrs != "" ? chrs : "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", // Default characters to randomize, if not defined!
            len = (formula.match(/X/ig) || []).length,
            oStatic = formula.match(/[^X]+/ig) || [],
            indices = [],
            lenChecks = checks.length || 0,
            rand;

        // Let's first find out if it's possible to create another random serial from params
        // Should put the formula below through a stress test here to be sure it works!
        var possible = (len * chrs.length) - lenChecks;

        // return empty string if not possible!
        if (possible <= 0)
            return '';

        var currIndex = 0;

        // Getting all indices here of all strings that are not X or x
        for (var o = 0; o < oStatic.length; o++) {
            currIndex = formula.indexOf(oStatic[o], currIndex);
            indices.push(currIndex);
            currIndex = currIndex + oStatic[o].length; // set the position to start at for next loop! incrementing...
        }

        do {
            rand = Array(len).join().split(',').map(function() {
                return chrs.charAt(Math.floor(Math.random() * chrs.length));
            }).join('');

            // Rebuild with indices, if exists!
            if (indices && indices.length > 0) {
                for (var x = 0; x < indices.length; x++)
                    rand = rand.insert(indices[x], oStatic[x]);
            }
        } while (checks && $.inArray(rand, checks) !== -1);

        return rand;
    }
});

Can anyone help me with this please? Could something be wrong with my possible variable within the extension? Is it not correct?

Even tried it without the currSerials array, with it initially empty and only generates 576 serials before it says it can not generate anymore. You can see it here: https://jsfiddle.net/sd1x3am3/8/

var currSerials = [];
for (var i = 0; i < 2000; i++) {
    var output = $.generateSerial('XXXX-XXXX-XXXX-XXXX', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', currSerials);

    $(".serials").append($("<p />").text((i+1) + '. ' + output));
    if (output != "")
        currSerials.push(output);
    else
    {
        alert('Can not generate anymore serials, stopped at ' + i + '.');
        break;
    }
}

Solution

  • From the discussions, I find that you are not after permutations, so you should be using the following to find the total possible items,

    var possible=Math.pow(chrs.length,len) - lenChecks