Reputation: 11
I'm very new to coding, and working on my first Javascript project. I'm trying to create a small random character generator which randomly selects a setting, and character archetype from two arrays. My problem is that I keep getting repeats, probably due to the small size of the lists.
<html>
<head>
<script type="text/javascript">
var setting=new Array('Steampunk',
'Fuedal Japanese',
'Post Apocalyptic',
'Horror',
'Fantasy',
'Cyberpunk',
'Western',
'Pulp',
'Military',
'Space Opera',
'Medieval',
'Ancient',
'Mythological',
'Urban',
'Trans-Humanist',
'Renaissance',
'Dystopian',
'Retro Futuristic',
'Nordic',
'Colonial');
var Archetype=new Array('Ninja',
'Samurai',
'Viking',
'Cowboy',
'Rogue',
'Wizard',
'Wrestler / Luchador',
'Knight',
'Scientist',
'Gadgeteer',
'Druid',
'Performer',
'Pirate',
'Alien',
'Superhero / Villain',
'Robot',
'Soldier',
'Vampire',
'Werewolf',
'Bounty Hunter');
function resetSettingAndArchetype()
{
var whichsetting = Math.floor(Math.random()*(setting.length));
var whicharchetype = Math.floor(Math.random()*(Archetype.length));
How can I get the random operation to never return the same value twice?
Upvotes: 1
Views: 1181
Reputation: 2829
I would create an additional index of the array that I could loop over to get references. This will create a constant random order of all elements in the array, that when having traversed all elements would reset to the first one and traverse again in the same order.
This method is compatible with a shuffled copy as well, such as is described in any other answer. And you can use a better shuffling algorithm, this one is naive. Since your arrays are so small however, the performance increase will be minimal. If you want to make a shuffled copy you won't need to map the index, you only need to create the copy when creating the object.
This code is not tested. I'm not sure about the interval of Math.random
, but I'm assuming 0 < x < 1
here:
var RandomWalk = function(items) {
var self = this;
if (!items.length) {
// throw some error
}
this.index = 0;
this.index_map = (function(items) {
var map = [], i = 0;
while(map.length < items.length) {
i = Math.floor(Math.random() * items.length);
if (map.indexOf(i) === -1) {
map.push(i);
}
}
return map;
})(items); // Note that this function is evaluated, index_map is not a function
this.index_max = this.index_map.length - 1;
this.next = function() {
var r = self.index_map[self.index];
if (self.index == self.index_max) {
self.index = 0;
} else {
self.index += 1;
}
return r;
}
return this;
}
Then you'd do something like this:
// define settings and archetype
var archetype_walk = new RandomWalk(archetype);
function resetSettingAndArchetype()
{
...
var arch_index = archetype_walk.next(),
arch = archetypes[arch_index]
// arch is in ['Ninja', 'Samurai', 'Druid' ...]
By the way, 'Archetype' might be a bad variable name. It looks like a function. I use 'archetype' here.
Upvotes: 1
Reputation: 23208
You can use following method for shuffling:
function shuffle(o){ //v1.0
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
shuffle(setting);
shuffle(Archetype);
Upvotes: 1
Reputation: 179422
You can shuffle the array (e.g. using the Fisher-Yates shuffle), then just iterate one-by-one over the shuffled array. When you get to the end of one, just shuffle it again.
Upvotes: 5