How can I convert a periodic range into one range - javascript

I'm searching for a function to convert sound frequency into a light frequency, or in other words a sound into a color.
For the moment I can achieve this by a simple formula that transposes the sound frequency to the light frequency range:
const lightFreq = frequency * Math.pow( 2, 40 );
Now if I want to have the wave length in nanometers I only need to do
const waveLength = 1 / lightFreq / 10000000;
One common analogy between sound and color would be to replicate this corresponding wavelength to each octaves. This would imply that if 440Hz is equal to a wavelength of approximately 640nm then the octave which is 880Hz would also be 640nm.
Using the function could look like:
soundFreqToLightWaveLength( 440 ) //approx.640
soundFreqToLightWaveLength( 880 ) //approx.640
soundFreqToLightWaveLength( 1760 ) //approx.640
waveLength range [380,780]

In order to divide a frequency range into 9 divisions you will have to find the 9th root of the factor from lower to higher frequency:
let a=20,b=20000,n=9;
const fact=Math.pow(b/a,1/n);
console.log(a);
for (i=0; i<n; i++) console.log(a*=fact)
Update, referring to the updated question:
The following snippet translates sound frequencies to light frequencies with an equivalence of 440HZ = 640nm. Within one octave: the higher the sound pitch, the shorter the wave length will be:
sound frequency / Hz
wave length / nm
440
640
660
426.6666666666667
879.9999
320.0000363636406
880
640
1320
426.6666666666667
1760
640
let a=20,b=20000,n=12;
const A=440, lnA=Math.log2(A)%1;
const L=640; // base wave length
if(1)for (let n=35,f=20,f1=20000,fact=Math.pow(f1/f,1/n);n-->-1; f*=fact) {
let l=(lnA-Math.log2(f))%1;
let wl=Math.pow(2,l)*L // light wave length in nm
console.log(f,wl)
}
The snippet goes throught the frequency range 20 ... 20000Hz in 35 steps (this can be changed to any value). The light wave lengths are mapped only for the fractional part (l=(lnA-Math.log2(f))%1) of the frequencies as the will repeat in each octave.
Clarification/question
Looking at OP's latest comment I now assume that the wave-length calculations should be done according to the following diagram:
In the above example we can see that the whole frequency range (from lower value f0 to higher value f1) has been divided into 6 divisions (instead of octaves!), within each of which the sound frequencies will be mapped to the wave length in the range defined by wl0 (longest wave length) and wl1 (shortest wave length).
OP, is that what you had in mind?
If so, then the following would work for you:
function calcWaveLength([f0,f1],[wl0,wl1],n){
const lf0=Math.log(f0), lfstep=Math.log(f1/f0)/n,
lwl0=Math.log(wl0), llrange=Math.log(wl1/wl0);
return function(freq){ // return the actual calc-function here
lf=Math.log(freq)
return Math.exp( lwl0 + (lf-lf0)/lfstep % 1 * llrange )
}
}
// set up the calc function (once) for each frequency range:
const calc=calcWaveLength([20,20000],[640,460],3);
console.log("frequency, wavelength");
// test for the following frequencies:
[20,35.56558820077846,63.245553203367585,112.46826503806982,199.999,
200,355.65588200778456,632.4555320336758,1124.682650380698,1999.99,
2000,3556.558820077845,6324.555320336758,11246.82650380698,19999.9,
20000].forEach(f=>
console.log(f.toFixed(3),calc(f).toFixed(3))
)
The snippet calculates what the diagram demands, but the result is something like a sawtooth wave function, having sharp inclines at the end of each division:

// outputs a number between 0 and 1, depending on whether the pitch
// is at the lower or upper end of an octave
// each semitone will be 1/12th of the way between 0 and 1
// the octave starts with an A note. Change the number 440
// to the frequency of another note if you want the octave
// to start at a different note
function freqToOctavePosition(freq) {
return ((Math.log(freq/440)/Math.log(2) % 1) + 1) % 1
}
// linearly converts the position within the octave to a position within a range
function freqToRange(freq, rangeStart, rangeEnd) {
return (freqToOctavePosition(freq) * (rangeEnd-rangeStart)) + rangeStart
}
console.log(freqToRange(262, 400, 700))

Related

Generate big numbers with Math random in Javascript

I need to generate 26 digit numbers with Math.random, but when I use this:
Math.floor(Math.random() * 100000000000000000000000000) + 900000000000000000000000000
I gets 9.544695043285823e+26
Modern browsers support BigInt and bigint primitive type and we can combine it with a random generated array containing 8 bytes (the sizeof bigint is 8 bytes (64 bits)).
1. Generating Random BigInt Performance Wise
We can generate a random hex string of 16 characters length and apply it directly to BigInt:
const hexString = Array(16)
.fill()
.map(() => Math.round(Math.random() * 0xF).toString(16))
.join('');
const randomBigInt = BigInt(`0x${hexString}`);
// randomBigInt will contain a random Bigint
document.querySelector('#generate').addEventListener('click', () => {
const output = [];
let lines = 10;
do {
const hexString = Array(16)
.fill()
.map(() => Math.round(Math.random() * 0xF).toString(16))
.join('');
const number = BigInt(`0x${hexString}`);
output.push(`${
number.toString().padStart(24)
} : 0x${
hexString.padStart(16, '0')
}`);
} while (--lines > 0);
document.querySelector('#numbers').textContent = output.join('\n');
});
<button id="generate">Generate</button>
<pre id="numbers"><pre>
2. Generating Random BigInt from random bytes array
If we want to use Uint8Array or if we want more control over the bits manipulation, we can combine Array.prototype.fill with Array.prototype.map to generate an array containing 8 random byte number values (beware this is around 50% slower than the above method):
const randomBytes = Array(8)
.fill()
.map(() => Math.round(Math.random() * 0xFF));
// randomBytes will contain something similar to this:
// [129, 59, 98, 222, 20, 7, 196, 244]
Then we use Array.prototype.reduce to initialize a BigInt of zero value and left shift each randum byte value its position X 8 bits and applying bitwise or to the current value of each reduce iteration:
const randomBigInt = randomBytes
.reduce((n, c, i) => n | BigInt(c) << BigInt(i) * 8n, 0n);
// randomBigInt will contain a random Bigint
Working example generating 10 random BigInt values
document.querySelector('#generate').addEventListener('click', () => {
const output = [];
let lines = 10;
do {
const number = Array(8)
.fill()
.map(() => Math.round(Math.random() * 0xFF))
.reduce((n, c, i) => n | BigInt(c) << BigInt(i) * 8n, 0n);
output.push(`${
number.toString().padStart(24)
} : 0x${
number.toString(16).padStart(16, '0')
}`);
} while (--lines > 0);
document.querySelector('#numbers').textContent = output.join('\n');
});
<button id="generate">Generate</button>
<pre id="numbers"><pre>
Floating point numbers in JavaScript (and a lot of other languages) can contain only about 15.955 digits without losing precision. For bigger numbers you can look into JS libraries, or concatenate few numbers as strings. For example:
console.log( Math.random().toString().slice(2, 15) + Math.random().toString().slice(2, 15) )
Your question seems to be an XY problem where what you really want to do is generate a sequence of 26 random digits. You don't necessarily have to use Math.random. Whenever one mentions randomness it's important to specify how that randomness is distributed, otherwise you could end up with a paradox.
I'll assume you want each of the 26 digits to be independently randomly chosen uniformly from each of the 10 digits from 0 to 9, but I can also see a common interpretation being that the first digit must not be 0, and so that digit would be chosen uniformly from numbers 1 to 9.
Other answers may tempt you to choose a random bigint value using what amounts to random bits, but their digits will not be randomly distributed in the same way, since their maximum value is not a power of 10. For a simple example consider that a random 4 bit binary value in decimal will range from 00 to 15, and so the second digit will have a 12/16(=75%) chance of being 0 to 5, though it should be 60%.
As for an implementation, there's many ways to go about it. The simplest way would be to append to a string 26 times, but there are more potentially efficient ways that you could investigate for yourself if you find the performance isn't adequate. Math.random has a roughly uniform distribution from 0 to 1, but by being double precision it only has 15 or so significant decimal digits to offer us, so for each call to Math.random we should be able to retrieve up to 15 out of 26 decimal digits. Using this fact, I would suggest the following compromise on ease of readability and efficiency:
function generate26Digits() {
const first13 = Math.floor(Math.random() * Math.pow(10, 13)).toFixed(0).padStart(13, "0");
const next13 = Math.floor(Math.random() * Math.pow(10, 13)).toFixed(0).padStart(13, "0");
return first13 + next13;
}
console.log(generate26Digits())
This solution is not cryptographically secure however, and so I will direct readers to use Crypto.getRandomValues if you need more security for this for some reason.
If you then want to do math on this number as well without losing precision, you will have to use bigint types as others have suggested.
If I use a 6 decillion LG about 72.9 million out of 300 but when I switch to 10 centillion it comes like this 10 ^ 999 - 99999 + 26 just like how 9 - 9 - 9 - 9 - googolplex is equal to 0 googolplex

Javascript number interval search optimization

As topic says i ran into optimization problem when it comes to a large amount of intervals
Variables: FirstPrice, LastPrice, Increment and the number that user writes
Task: Need to round number to one side or another in specific interval.
Example:
FirstPrice = 0.99, LastPrice = 9.99, Increment = 1 User number = 5.35
Workflow:
I need to find interval in which one number exists, and what i could think of is to push numbers into array. So for this example array would be:
["0.99","1.99","2.99","3.99","4.99","5.99","6.99","7.99","8.99","9.99"].
Then i use for loop to find in which interval (in this case number = 5.35) number exists. In this case interval would be from 4.99 to 5.99. And then user number is updating to 4.99 or 5.99.
Problem:
It works fine doing that with low amount of numbers. But it comes really hard to execute high ranges. E.g. if FirstPrice = 1 LastPrice = 1000000 and Increment = 1. Then my array gets thousands of values and it takes way too long to push every value into array and find the number. Array gets ~999999 values and then loop goes through all of them to find specific interval.
So i think my problem is clear. The optimization. I need a better way of doing this. I tried cutting price range to half and a half but then intervals are wrong. Tried working with the inserted number but the same problem occurred.
Correct me if I'm wrong, but isn't this simply:
lower = floor((q - s) / i) * i + s
upper = lower + i
where:
q = User number
s = FirstPrice
i = Increment
function foo(q, s, i) {
const lower = Math.floor((q - s) / i) * i + s;
const upper = lower + i;
return [lower, upper];
}
console.log(
foo(5.35, 0.99, 1),
foo(5.35, 0.99, 2),
foo(5.35, 0.99, 3)
);

Where is my logic going wrong in trying to calculate the presidential outcome?

Let me explain what I'm trying to do. I have data like
const dataByState = {
'Washington' : { ElectoralVotes : 12, RChance: 54, DChance: 46 },
'Oregon': { ElectoralVotes: 7, RChance: 51, DChance: 49 },
.
.
.
'Hawaii' : { ElectoralVotes: 4, RChance : 40, DChance: 60 }
};
where one of the above key-value pairs like
'Hawaii' : { ElectoralVotes: 4, RChance : 40, DChance: 60 }
means "In the state Hawaii, which has 4 electoral votes, there is a 40% chance of the Republican Candidate winning and a 60% chance of the Democrat candidate winning". What I'm ultimately trying to do is calculate the chance of each candidate winning the election. How this would be done in a perfect world is
Iterate through all 2^51 combinations of states
For each combination c, its combined electoral votes are greater than or equal to 270, add it to a collection C of collecions of states
For the Republican candidate, sum up the probabilities of winning each combination of states in C; call that value r. That's his/her chance of winning. The Democrat's chance is 1 - r.
But since I can't go through all 2^51, what I'm doing is choosing some N smaller than 51 and doing
Find a random 2^N combinations of states whose combined electoral votes sum to greater than or equal to 270; call this combination C.
For the Republican candidate, sum up the probabilities of winning each combination of states in C; call that value r. Multiply r by 2^(51-N). That's approximately his/her chance of winning. The Democrat's chance is 1 - r.
Anyhow, this doesn't seem to be working and I'm wondering whether my logic is wrong (I haven't taken statistics since college 3 years ago) or if I'm running into rounding errors. I'm getting a near 100% of the Republican winning (i.e. America being made great again) when I make the chance even in every state, which is wrong because it should calculate to about 50/50.
Code dump: https://jsfiddle.net/pqhnwek9/
The probability of a republican victory is
probRepVict = 0
for(combination in combinations) {
if(combination is republican victory) {
probRepVict += proability of combination
}
}
As you observe it is not feasible to calculate the entire sum. Hence, you choose some subset C to try to estimate this probability.
N = number of combination // 2^51
n = size of C
probRepVictEstimate = 0
for(combination in C) {
if(combination is republican victory) {
probRepVictEstimate += proability of combination
}
}
probRepVictEstimate *= N/n
In the last statement we assume that the probability of a victory scales linearly with the size of the subset.
I believe the logic goes wrong at several places in the script:
(1) When generating the random number you might not get a sufficiently many bits of randomness. For instance if there were 54 states you would be outside of the safe integer range. Some implementations might give you even less fewer bits of randomness (it did break for me in Node, which only give 32 bits). Thus I suggest adding a function
function getRandom() {
// Generate 32 random bits
var s = Math.floor(Math.random()*Math.pow(2, 32)).toString(2)
return new Array(32 - s.length + 1).join("0") + s
}
Replacing
const rand = Math.floor(Math.random() * Math.pow(2,states.length));
with const rand = getRandom() + getRandom();, and replace getCombo with
const getCombo = (i) => {
let combo = [];
for(var j = 0; j < states.length; ++j)
if(i[j] == "0")
combo.push(states[j]);
return combo;
}
(2) You need to count both wins and losses for the republican party to be able to estimate the probability. Thus you cannot add the complement of a combo (by the way, ~ is a bitwise operations, hence convert the operand to a 32-bit integer, so your code does not work as intended). Hence your code should be simplified to:
...
if(!winningCombos.hasOwnProperty(rand)) {
const stateCombo = getCombo(rand);
if(hasSufficientVotes(stateCombo))
{
winningCombos[rand] = stateCombo;
++wins;
}
++count;
}
...
(3) You should scale repubChanceSum by N/n, where N = Math.pow(2, 51) and n = limit. Note that limit should be considerably greater than winningCombos.length.
With these modifications the code correctly predicts a ~50% probability. See this modified fiddle.
Let's hope we get a more optimistic outlook for the future with more realistic probabilities.

HTML Canvas game: 2D collision detection

I need to program a very simple 2D HTML canvas game with a character and a few walls. The map (top view) is a multidimensional array (1=walls)
map = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0],
[1,0,0,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,0,0,0,0,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1],
[1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1],
[1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1],
[1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1],
[0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1],
[1,1,1,0,1,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,0,1,1],
[1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
The character shouldn't be able to walk over the walls... so he should only walk on the "0"s. I already got the map rendering and the walking part of the character working just fine, but I can't quite figure out how to check for collisions yet.
A very simple version can be found on JSBin. You can either use the arrow keys or WASD to move around (black square).
I already tried to do a very simple collision detection by using something like this:
function checkCollision( x, y ) {
if ( map[ Math.round( x ) ][ Math.round( y ) ] !== 0 ) {
return true; // Collision
}
return false;
}
But this doesn't quite work (see JSBin). With Math.round the character and wall overlap... if I use Math.ceil or Math.floor it's even worse.
Is there any way that I can improve this "collision detection", so that the character can't walk over the red walls?
There are a few problems:
First you should avoid using 0.1 as coordinate step because it's a "bad number" in floating point (it's periodic when expressed in binary). Much better is 0.125 (1/8). Adding/substracting 1/8 will guarantee your numbers will always remain exact multiples of 1/8, not accumulating any error.
You should define an "ok(x, y)" function checking if the (possibly fractional) point (x, y) is valid or inside a wall... a simple implementation could be:
return map[y|0][x|0] == 0; // <expr>|0 is used to convert to integer
Finally you should compute new_charX and new_charY and only accept moving from charX, charY to the new position if all four points:
(new_charX+s, new_charY+s)
(new_charX+1-s, new_charY+s)
(new_charX+s, new_charY+1-s)
(new_charX+1-s, new_charY+1-s)
are valid with s = 1/16 (i.e. half of the moving step).
Example: http://jsbin.com/wipimidije/edit?js,output
Your player can potentially be overlapping four squares in the map at any time. So you need to check for collision in all four squares (corresponding to the top-left, top-right, bottom-left, bottom-right corners of the character). To allow it to 'squeeze' through corridors (given that the character is the same size as a tile) you may also need to adjust this by one or two pixels (hence the 1 / config.tileSize in the following).
function checkCollision( x, y ) {
var x1 = Math.floor(x + 1 / config.tileSize),
y1 = Math.floor(y + 1 / config.tileSize),
x2 = Math.floor(x + 1 - 1 / config.tileSize),
y2 = Math.floor(y + 1 - 1 / config.tileSize);
if (map[y1][x1] !== 0 || map[y2][x1] !== 0 || map[y1][x2] !== 0 ||
map[y2][x2] !== 0) {
return true; // Collision
}
return false;
}
See this version of the JSBin
My answer is a little different. Instead of having a 2D array I'd use a simple array and calculate the rows (if you even need them). Now you only have to check the map array at the one index that is the position of the actor:
var map = [0,0,0,1,1,0,0,1,1,0,0,...];
//heres how to calculate the x/y if you need it for something else
var pos_x = position % NUM_OF_ROWS;
var pos_y = Math.floor(position / NUM_OF_ROWS);
//for collisions now you just check the value of the array at that index
leftKey.addEventListener('keypress', function() {
test(position - 1);
});
rightKey.addEventListener('keypress', function() {
test(position + 1);
});
upKey.addEventListener('keypress', function() {
test(position + NUM_OF_ROWS);
});
downKey.addEventListener('keypress', function() {
test(position - NUM_OF_ROWS);
});
function test(n) {
if (map[n] === 0) {
//if there's no collision, update the position.
position = n;
} else {
console.log('Collided!');
}
}
You need to consider two aspects: the first is collision detection, the second is response. Let's start with the detection. You are checking a single point, but in reality you have a tile size, so there is thickness which you must consider. The coordinate of the character, and the coordinate of your tiles is the top-left corner. It is not sufficient to compare the top-left corners, you must also check the other corners. The right-hand side of the player's square for example is at charX + config.tileSize.
The second aspect is the collision response. The simplest mechanism you can use here is to check the next position of the character for collisions, and only move the character if there are none. You should preferably check the two axes separately to allow the character to "slide" along walls (otherwise it till get stuck in walls in moving diagonally into the wall).
First of all I would change the tiles "value" if you change the character to walk in 1's but in 0's you can check if a tile is walkable by typing
If(tile[x][y])...
Then, I would, first calculate the next position and then make the move if the player is able to...
Var nextpos = new position;
If(KEYLEFT){
Nextpos.x = currpos - 1;
}
If(nextpos > 0 && nextpos < mapsize && tile[nextpos.x][nextpos.y])
Player.pos = nextpos;

Create unique colors using javascript

What is the best way to pick random colors for a bar chart / histogram such that each color is different from the other.. and possibly in contrast
The most talked about way is
'#'+(Math.random()*0xFFFFFF<<0).toString(16);
but this can generate similar colors.. and sometimes distinguishing them might be a problem..
Example
I would generate colors using HSV (hue, saturation, value) instead of RGB. In HSV, the color is defined by the hue, ranging from 0-360. Thus, if you want e.g. 6 different colors, you can simply divide 360 by 5 (because we want to include 0) and get 72, so each color should increment with 72. Use a function like this one to convert the generated HSV color to RGB.
The following function returns an array of total different colors in RGB format. Note that the colors won't be "random" in this example, as they will always range from red to pink.
function randomColors(total)
{
var i = 360 / (total - 1); // distribute the colors evenly on the hue range
var r = []; // hold the generated colors
for (var x=0; x<total; x++)
{
r.push(hsvToRgb(i * x, 100, 100)); // you can also alternate the saturation and value for even more contrast between the colors
}
return r;
}
The best way is to convert from HSV values. You can divide the maximum value of "Hue" by the amount of colors you need and then increment by this result.
For improved contrast, you can also alternate between high and low values of lightness.
The existing answers which mention the Hue, Saturation, Value representation of colors are very elegant, are closer to how humans perceive color, and it is probably best to follow their advice. Also creating a long precalculated list of colors and choosing subsets of them as needed is fast and reliable.
However, here is some code that answers your question directly: it will generate random colors in RGB that are sufficiently different. There are two drawbacks to this technique that I can see. First, these colors are really random and could look kind of gross together, and second it might take a while for the code to stumble on colors that work, depending on how "far apart" you require the colors to be.
function hex2rgb(h) {
return [(h & (255 << 16)) >> 16, (h & (255 << 8)) >> 8, h & 255];
}
function distance(a, b) {
var d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
return Math.sqrt((d[0]*d[0]) + (d[1]*d[1]) + (d[2]*d[2]));
}
function freshColor(sofar, d) {
var n, ok;
while(true) {
ok = true;
n = Math.random()*0xFFFFFF<<0;
for(var c in sofar) {
if(distance(hex2rgb(sofar[c]), hex2rgb(n)) < d) {
ok = false;
break;
}
}
if(ok) { return n; }
}
}
function getColors(n, d) {
var a = [];
for(; n > 0; n--) {
a.push(freshColor(a, d));
}
return a;
}
The distance between colors is the Euclidean distance measured by the R, G, and B components. Thus the furthest that two colors (black and white) can be is about 441.67.
To use this code, call getColors where the first parameter is the number of colors, and the second is the minimum distance between any two of them. It will return an array of numerical RGB values.
I like using hsl values for specifying colour this way.
So
"color: hsl(" + getRandomArbitary(0, 360) + ", 50%, 50%)";
would give you random results, but that won't give you your distinct separations. So I'd base it on the i value of a loop. Something like,
for (var i = 0; i < whateverYourValue; i += 1) {
color = "color: hsl(" + i * 10 + ", 50%, 50%)";
// set your colour on whatever
}
obviously the above is indicative, and not valid code on it's own.
Want to know more on hsl? Check http://mothereffinghsl.com/ 'cause, you know, it's fun.
'#'+(Math.random()*0xFFFFFF<<0).toString(16);
Isn't the best method to use because it can generate values like #4567 which is missing two digits instead of generating #004567
It's better to pick each character individually like:
'#'+Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16);
But that can easily be reduced to picking three numbers since hex colours can be shortened. IE. #457 == #445577
Then if you want to decrease the number of posibilities and widen the gap between them you can use:
'#'+(5*Math.floor(Math.random()*4)).toString(16)+
(5*Math.floor(Math.random()*4)).toString(16)+
(5*Math.floor(Math.random()*4)).toString(16);
Which divides the number of choices for each color by 5, and then evens out the distribution equally.
I second what kbok and Harpyon say about working in HSV colorspace, and this little library makes it super easy to switch between RGB and HSV - and others.

Categories

Resources