Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialWaldo Alvarado
16,322 PointsJavaScript: Generating different random number pairs.
Hi, I'm trying to figure out how to write a function that produces two different random numbers (random number pairs) that have also never been "chosen" before.
For example: from 0 - 9 the Math.random() function run twice could generate the same number twice. Meaning that you could get the number 5 as the first random number and the number 5 again for the second random number. How do I ensure that the function never produces the same number twice? So that the two numbers are always different, like: 5 & 6 or 9 & 1? In other words, I want to avoid getting a result like 5&5 or 1&1, I want the two random numbers to always be different than each other.
Also, once a number pair has been generated, like 9 & 1 for example, how can I get the program to check and see if that number pair has already been selected in the past and have it keep producing new number pairs until a new, never chosen, number pair appears? In order words, if the first number pair to be generated was 9 & 1 and then the second pair of random numbers was 1 & 9 (the same number pair but in a different order) how can I have the program recognize that it's already been used before and keep it generating new random number pairs until a never chosen number pair is selected?
The end result would be a function that generated all possible different number pairs from 0-9. The series would go start like this: 0,1/0,2/0,3 all the way to 0,9 then it would continue with 1,2/1,3/1,4 up to 1/9 then 2,3/2,4/2,5 etc etc. and it would end with 7,8/7,9/8,9.
If you can help me out with this problem, you're a genius!
Thanks!
2 Answers
miikis
44,957 PointsHey Waldo,
I just spent an hour and a half of my life — should've been like 45 minutes if it wasn't for stupid JS pass-by-reference bullshit — writing this algorithm. Lol it was kinda cool though; I now have a pretty stellar understanding of Combinations and Pascal's Rule. And it works, and it came out pretty neat.
I added some console#log() statements so if you just run it, it'll explain itself, well, the results anyway. The code's also commented and pretty readable, in general. But, feel free to ask for clarification if you need it ;)
/**
* This is the combination generator
* @param {Number[]} inputSet - the set of n elements
* @param {number} k - the "at a time" part, like 3 elements 2 "at a time"
* @return {Array.<Number[]>} returns an array of arrays of numbers, like [[1, 2], [2, 3], [3, 2]]
*/
function daComboGenerator(inputSet, k) {
return (function subsetRecurser(subset, inputSetIndex, subsetIndex, result) {
// set up some defaults
inputSetIndex = inputSetIndex || 0
subsetIndex = subsetIndex || 0
subset = subset || []
result = result || []
// if true, the current is done being built, so push it into `result`
if (subsetIndex === k) {
// the .slice() here returns a clone of the subset array
// it took way too much time out of my life to catch this stupid thing
result.push(subset.slice())
return
}
// stop once we've iterated through all of the `inputSet`
if (inputSetIndex >= inputSet.length) {
return
}
// build the subset array
// notice how we're just replacing previous values whenever we rebuild
subset[subsetIndex] = inputSet[inputSetIndex]
// recurse through each subset
subsetRecurser(subset, inputSetIndex + 1, subsetIndex + 1, result)
// recurse through each member of the inputSet
subsetRecurser(subset, inputSetIndex + 1, subsetIndex, result)
// return the result
return result
})()
}
// the simplest factorial function in the world...
function factorial(num) {
if (num <= 1) {
return 1
}
return num * factorial(num - 1)
}
// something to test `daComboGenerator()` results with
// this function uses the binomial coeffecient to figure out
// how many ways n things can be taken k at a time or
// n! / (k!(n-k)!)
function daComboCounter(n, k) {
return factorial(n) / (factorial(k) * factorial(n - k))
}
// returns a random number
function randomNumberGenerator(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
// returns a range of unique numbers, each between min and max, including min and max
function uniqueRangeGenerator(min, max) {
const range = []
while (range.length < (max - min + 1)) {
var randomNumber = randomNumberGenerator(min, max)
if (range.indexOf(randomNumber) === -1) {
range.push(randomNumber)
}
}
return range
}
/**
* MOMENT OF TRUTH...
*/
const uniqueRange = uniqueRangeGenerator(0, 9)
const generatedPairs = daComboGenerator(uniqueRange, 2)
const expectedNumberOfPairs = daComboCounter(uniqueRange.length, 2)
console.log('Given a range of unique numbers like:')
console.log(uniqueRange) // returns something like [ 7, 8, 6, 0, 4, 1, 5, 2, 3, 9 ]
console.log('These are all the different possible pairs:');
console.log(generatedPairs) // returns something like:
// [ [ 7, 8 ],
// [ 7, 6 ],
// [ 7, 0 ],
// [ 7, 4 ],
// [ 7, 1 ],
// [ 7, 5 ],
// [ 7, 2 ],
// [ 7, 3 ],
// [ 7, 9 ],
// [ 8, 6 ],
// [ 8, 0 ],
// [ 8, 4 ],
// [ 8, 1 ],
// [ 8, 5 ],
// [ 8, 2 ],
// [ 8, 3 ],
// [ 8, 9 ],
// [ 6, 0 ],
// [ 6, 4 ],
// [ 6, 1 ],
// [ 6, 5 ],
// [ 6, 2 ],
// [ 6, 3 ],
// [ 6, 9 ],
// [ 0, 4 ],
// [ 0, 1 ],
// [ 0, 5 ],
// [ 0, 2 ],
// [ 0, 3 ],
// [ 0, 9 ],
// [ 4, 1 ],
// [ 4, 5 ],
// [ 4, 2 ],
// [ 4, 3 ],
// [ 4, 9 ],
// [ 1, 5 ],
// [ 1, 2 ],
// [ 1, 3 ],
// [ 1, 9 ],
// [ 5, 2 ],
// [ 5, 3 ],
// [ 5, 9 ],
// [ 2, 3 ],
// [ 2, 9 ],
// [ 3, 9 ] ]
console.log(`There should be ${generatedPairs.length} different possible pairs...`);
if (expectedNumberOfPairs === generatedPairs.length) {
console.log('... and there are!!!!');
} else {
console.log('... and there are NOT!!!!');
}
Erik Nuber
20,629 PointsYou can do this with a two dimensional array. If you haven't gotten to arrays yet, it is an array of arrays. You can store all the previous rolls into that array and check each paired roll against all the other rolls.
To accomplish two random rolls that are not the same
1) roll the first random number and store in a variable 2) roll the second random number and store in a second variable 3) you can use a do/while loop that would compare the two and keep generating a random number until the two don't match
from there...
1) store your rolls in a two dimenisional array 2) create a for loop that checks new rolls against previous rolls. 3) if that matches something you have to generate a new set of numbers 4) if it doesn't match you push the new set into the array holding previous rolls
For this second part, I would likely have a variable holding a boolean value that changes so that you can go back to the beginning of all of this if the roll has already been performed.
This would also deal with 1 & 9 vs 9 & 1 because of how the array is accessed.
if you want that array to be neat and pretty you can also use sort() to clean it up and then print it out.
Waldo Alvarado
16,322 Points@Erik Nuber, Thanks Erik I'm just learning about the while and do-while loops now, the for loops are coming up in the next lesson and the arrays after that.
I've never worked with two-dimensional arrays but it makes sense, also setting up a boolean flag to make it go back to the beginning is genius! I obviously will have to get through the arrays section of the course before attempting to code this out. Thanks for your help.
I'll post my solution to this as soon as I code it out.
Waldo Alvarado
16,322 PointsWaldo Alvarado
16,322 Points@Mikis Woodwinter, Hi Mikis,
Wow, thank you for the amazingly detailed response! I had no idea that the solution to my question was so involved. Here's what I'm trying to do by the way:
I want to create a program where people can type in a list of 10 goals, for example: Lose 20 pounds, get a hotter girlfriend (lol), increase my YouTube subscribers past 1000, move to Las Vegas, etc. Any list of ten goals.
Then, I want any two of those 10 goals to be presented to the user so that he can select which goal is more important to him. For example: which goal has a higher priority to you, losing 20 pounds or moving to Las Vegas? And then going through each possible pair of combinations in that set of goals but doing it at random without repeating any of the pairs.
Additionally, every time the user chooses one goal over another, the chosen goal gets a plus 1 added to it and the not-chosen goal gets a minus 1 point subtracted from it so that in the end, after going through all 45 possible different combinations you end up with your goals ranked in order of highest to lowest priority.
I once was actually able to make an app that did this in Android using Java but I wasn't backing up my code and eventually I ended up ruining the program to where it just crashed all the time. That's what caused my to take a brake from Android and focus on JavaScript which is sooo much easier to develop in, you don't have to deal with the virtual machine which takes forever to run your app. The code I had looked very different than what you have, my code looked amateurish compared to what you wrote above lol. I'm still a rookie in the coding game.
I'm going to keep learning JS. As soon as I develop my app, I'll post it on here or a link to it.
Thanks for the help!