Pick random numbers until number is high enough [javascript] - javascript

I am building a Pathfinder Character Generator, but struggling to get the stats rolls high enough. So I'd like to tell it to reroll unless the total modifier is higher than 10.
Dice are rolled 4 times, and the three highest rolls are added to make a single stat. Six stats are served into an array to work from. The total modifier is calculated by adding all six stats together, subtract 60 and divide that number by 2. So I've got all that shown here.
I assume I'm looking for an if/else statment now where if checkModifier() < 10 then run rollStat() again else move forward. But I'm not sure what that would look like. Or would it be better to simplify the whole thing into a single function and then run it as a while statement?
EDIT: There was an issue with the code producing the same six stat numbers. I've fixed it.
function makeDie(sides) {
var die = function () {
return 1 + Math.random() * sides | 0;
};
die.times = function (count) {
var rolls = [];
for(var i = 0 ; i < count ; i++) {
rolls.push(this());
}
return rolls;
};
return die;
}
var rollStat = function () {
var dieRolls = makeDie(5).times(4)
for (a in dieRolls) {
dieRolls[a] += 1;
}
var sortedRolls = dieRolls.sort();
var singleStat = 0;
for (b = 1; b < sortedRolls.length; b++) {
singleStat += sortedRolls[b];
}
return singleStat;
}
var sixStats = function () {
var ss = [];
for (var c = 0; c < 6; c++) {
ss.push(rollStat());
}
return ss;
}
var stats = sixStats();
var stats = stats.sort(function (a, b) {
return a - b;
});
var checkModifier = function() {
var total = 0;
for (var d in stats) {
total += stats[d];
}
return (total-60)/2;
};

Here's a fiddle with the solution I'd give after seeing your edit.
var createStats = function () {
var stats = sixStats();
stats = stats.sort(function (a, b) {
return a - b;
});
var total = 0;
for (var d in stats) {
total += stats[d];
}
var totalModifier = (total-60)/2;
if (totalModifier < 10) {
return createStats();
} else {
return totalModifier; //of course, ultimately you will probably want to return stats, not the totalModifier, but this is here for debugging purposes.
}
};
You can see this fiddle as a proof of concept.
Another, perhaps neater solution:
var genStats = function () {
var stats = sixStats();
stats = stats.sort(function (a, b) {
return a - b;
});
return stats;
};
var totalMod = function (stats) {
var total = 0;
for (var d in stats) {
total += stats[d];
}
var totalModifier = (total-60)/2;
return totalModifier;
};
var createStats = function (minMod) {
var stats = genStats();
if (totalMod(stats) < minMod) {
return createStats(minMod);
} else {
return stats;
}
};

Related

Finding the prime number. how to improve efficiency of my code

So i am doing Euler problems, and i got to problem asking to find 10001st prime number. i did it like this. From what i can see it has O n^2. Codepen didnt like the time it took and thought it was an infinite loop, had to run on another compiler, my question is there anyway to improve this?
isPrime=(num)=>{
if(num<=1){
return false;
}
for(let i=2;i<num;i++){
if(num%i == 0){
return false;
}
}
return true;
}
findPrime=()=>{
let count=0;
let number = 1;
let prime=0;
while(count != 10001){
let result = isPrime(number);
if(result === true){
count++;
prime = number;
}
number++;
}
return prime;
}
Takes around 1/60 time in node.js and around 1/140 here in Chrome comparing to your original without additional optimisations on my machine, but has a bit more complex setup...
var primes = [2, 3]; // lets start with some basic
function myPrimes(no, mapSize) {
var nonPrimeMap = {};
var pos = 0;
var pos2 = 4;
while (pos < no) {
var s = primes[pos++];
for (var x = s * 2; x < mapSize; x += s) nonPrimeMap[x] = 1;
do {
if (nonPrimeMap[pos2]) pos2++;
else {
primes.push(pos2++);
break;
}
} while (true);
}
}
function runTest() {
var a = new Date();
myPrimes(9999, 110000);
var c = new Date();
console.log(primes[primes.length - 1], c - a); // My test timespans in ms
var b = findPrime();
a = new Date();
console.log(b, a - c); // Your
}
isPrime = (num) => {
if (num <= 1) {
return false;
}
for (let i = 2; i < num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
};
findPrime = () => {
let count = 0;
let number = 1;
let prime = 0;
while (count != 10001) {
const result = isPrime(number);
if (result === true) {
count++;
prime = number;
}
number++;
}
return prime;
};
runTest();

How to display output of one function after another

I have written a Javascript file of two algorithms. As shown in the code below, I am using a for loop to generate random values which are used by both algorithms as input.
At present, I am displaying output of the binarySearch and SearchSorted alternatively.
The problem I am facing is I have to pass the same array values generated by randomlyGenerateArray in the main program to both the algorithms for a meaningful comparison. But I don't know how to change the output format.
I have thought of adding them in different loops, but as I have explained above i need to use the same randomArray values for both the algorithms.
i.e., The below code produces output as shown below -
Binary Search Successful 1
Search Sorted Successful 5
Binary Search Successful 3
Search Sorted Successful 10
How do I display the output of Binary Search First and then display output of Search Sorted? it's something like this. Any help will be greatly appreciated.
Binary Search Successful 1
Binary Search Successful 3
Search Sorted Successful 5
Search Sorted Successful 10
// Binary Search Algorithm
function binarySearch(A,K)
{
var l = 0; // min
var r = A.length - 1; //max
var n = A.length;
var operations = 0;
while(l <= r)
{
var m = Math.floor((l + r)/2);
operations++;
if(K == A[m])
{
console.log('Binary Search Successful %d',operations);
return m;
}
else if(K < A[m])
{
r = m - 1;
}
else
{
l = m + 1;
}
}
operations++;
console.log('Binary Search Unsuccessful %d',operations);
return -1;
}
// Search Sorted Algorithm
function searchSorted(A, K)
{
var n = A.length;
var i = 0;
var operations = 0;
while (i < n)
{
operations++;
if (K < A[i])
{
return -1;
}
else if (K == A[i])
{
console.log('Search Sorted Successful %d', operations);
return i;
}
else
{
i = i + 1;
}
}
operations++;
console.log('Search Sorted Unsuccessful %d', operations);
return -1;
}
// Random Array generator
var randomlyGenerateArray = function(size)
{
var array = [];
for (var i = 0; i < size; i++)
{
var temp = Math.floor(Math.random() * maxArrayValue);
var final = array.splice(5, 0, 30);
array.push(final);
}
return array;
}
//Sort the Array
var sortNumber = function(a, b)
{
return a - b;
}
// Main Program
var program = function()
{
var incrementSize = largestArray / numberOfArrays;
for (var i = smallestArray; i <= largestArray; i += incrementSize)
{
var randomArray = randomlyGenerateArray(i);
var sort = randomArray.sort(sortNumber);
var randomKey = 30;
binarySearch(sort, randomKey);
searchSorted(sort, randomKey);
}
}
var smallestArray = 10;
var largestArray = 10000;
var numberOfArrays = 1000;
var minArrayValue = 1;
var maxArrayValue = 1000;
program();
You could store the sorted randomArrays in an array (which I've called sortedRandomArrays), then run a for loop for each search.
The Main Program would then look like:
// Main Program
var program = function()
{
var incrementSize = largestArray / numberOfArrays;
var sortedRandomArrays = [];
for (var i = smallestArray; i <= largestArray; i += incrementSize)
{
var randomArray = randomlyGenerateArray(i));
var sort = randomArray.sort(sortNumber);
sortedRandomArrays.push(sort);
var randomKey = 30;
}
for (var i = 0; i < sortedRandomArrays.length; i++)
{
binarySearch(sortedRandomArrays[i], randomKey);
}
for (var i = 0; i < sortedRandomArrays.length; i++)
{
searchSorted(sortedRandomArrays[i], randomKey);
}
}
Solution is simple: store the results and print with 2 separate loops (take out the printing from within the functions).
var program = function()
{
var binarySearchResults = [];
var sortedSearchResults = [];
var incrementSize = largestArray / numberOfArrays;
for (var i = smallestArray; i <= largestArray; i += incrementSize)
{
var randomArray = randomlyGenerateArray(i);
var sort = randomArray.sort(sortNumber);
var randomKey = 30;
binarySearchResults[i] = binarySearch(sort, randomKey);
sortedSearchResults[i] = searchSorted(sort, randomKey);
}
for (var i = smallestArray; i <= largestArray; i += incrementSize)
{
//print binary results
}
for (var i = smallestArray; i <= largestArray; i += incrementSize)
{
//print sorted results
}
}

Execution time for successful search Binary Search algorithm

I have implemented Binary Search Algorithm using Node.js. I am recording the time taken by the algorithm to search for a number in a random generated array. I am able to output the time taken by the algorithm for an unsuccessful search.
But I am not able to figure out how to measure the time taken by the algorithm to successfully search a number in an array.
Here is my code -
function binarySearch(A,K)
{
var l = 0; // min
var r = A.length - 1; //max
var n = A.length;
var time = process.hrtime();
while(l <= r)
{
var m = Math.floor((l + r)/2);
if(K == A[m])
{
return m;
}
else if(K < A[m])
{
r = m - 1;
}
else
{
l = m + 1;
}
}
time = process.hrtime(time);
console.log('%d',time[1]/1000000);
return -1;
}
var randomlyGenerateArray = function(size)
{
var array = [];
for (var i = 0; i < size; i++)
{
var temp = Math.floor(Math.random() * maxArrayValue);
array.push(temp);
}
return array;
}
var sortNumber = function(a, b)
{
return a - b;
}
var program = function()
{
for (var i = 0; i <= 10000; i += 10)
{
var randomArray = randomlyGenerateArray(i);
var sort = randomArray.sort(sortNumber);
var randomKey = 100;
var result = binarySearch(sort, randomKey);
if(result < 0)
{
console.log("Element not found");
}
else
{
console.log('Element found in position ',result);
}
}
}
var maxArrayValue = 1000;
program();
I am using var time = process.hrtime(); to start the timer at the beginning of the algorithm and using time = process.hrtime(time); to end the timer and output it in the console.
How can I measure the time taken by the algorithm to successfully search a number in an array.
Any help would be greatly appreciated.
Start your timer before calling the binary search function and end it after the call .. regardless of whether the search is successful or not, you will get the time ..
var time = process.hrtime();
var result = binarySearch(sort, randomKey);
time = process.hrtime(time);
......

Variable scope within methods

I was teaching myself how to make a binary genetic algorithm the other day. The goal was to make it so that it would match a randomly generated 35 length binary string. I ran into a problem where methods were editing variables that I did not think were in its scope. This caused my solution to slowly degrade in fitness instead of increase! After I found out where this was happening I fixed it by newP[0].join('').split('') so that newP[0] itself would not be edited. For convenience I've marked where the problem was happening below in comments.
While I have fixed this problem I'd like to hopefully get an understanding as to why this happens and also prevent without doing the join/split silliness.
Here is the code:
var GeneticAlgorithm = function () {};
GeneticAlgorithm.prototype.mutate = function(chromosome, p) {
for(var i = 0; i < chromosome.length; i++) {
if(Math.random() < p) {
chromosome[i] = (chromosome[i] == 0) ? 1 : 0;
}
}
return chromosome;
};
GeneticAlgorithm.prototype.crossover = function(chromosome1, chromosome2) {
var split = Math.round(Math.random() * chromosome1.length);
var c1 = chromosome1;
var c2 = chromosome2;
for(var i = 0; i < split; i++) {
c1[i] = chromosome2[i];
c2[i] = chromosome1[i];
}
return [c1, c2];
};
// fitness = function for finding fitness score of an individual/chromosome (0-1)
// length = length of string (35)
// p_c = percentage chance of crossover (0.6)
// p_m = percentage change of mutation (0.002)
GeneticAlgorithm.prototype.run = function(fitness, length, p_c, p_m, iterations) {
var iterations = 100;
var size = 100;
// p = population, f = fitnesses
var p = [];
var f = [];
for(var i = 0; i < size; i++) {
p.push(this.generate(length));
f.push(fitness(p[i].join('')));
}
while( iterations > 0 && Math.max.apply(Math, f) < 0.999 ) {
var mates = [];
var newP = [];
var newF = [];
mates = this.select(p, f);
newP.push(mates[0], mates[1]);
while(newP.length < size) {
/*-------------------> Problem! <-------------------*/
mates = [newP[0].join('').split(''), newP[1].join('').split('')];
/*
* If I passed newP[0] when mates[0] changed newP[0] would also change
*/
if(Math.random() < p_c) {
mates = this.crossover(mates[0], mates[1]);
}
mates[0] = this.mutate(mates[0], p_m);
mates[1] = this.mutate(mates[1], p_m);
newP.push(mates[0], mates[1]);
}
for(var i = 0; i < size; i++) {
newF.push(fitness(newP[i].join('')));
}
p = newP;
f = newF;
iterations--;
}
return p[f.indexOf(Math.max.apply(Math, f))].join('');
};

Generating random number in Array without repeatition - JavaScript

so I know this questing has been asked, but all the answers that were given are already known to me. I don't want to make a variable of all the posible numbers (that was always the answer). So to go to the question, I want to make a random number generator, that will generate me 7 numbers, that must not be the same. For example, I get random numbers:
"5,16,12,5,21,37,2" ... But I don't want the number 5 to be used again, so I want different numbers. I made a code for the generation, but I can not think of any good method/way to do this. I was thinking that maybe check if the number is already in array and if it is, then generate another number, but as I'm amateur in JavaScript, I don't know how to do this. So here is my JavaScript code:
// JavaScript Document
function TableOn()
{
document.write("<table border='1'>");
}
function TableOff()
{
document.write("</table>");
}
function RandNum()
{
var n = new Array();
for(var i=0;i<7;i++)
{
n[i] = Math.round((1+(Math.random()*40)));
}
TableOn();
for(var c=0;c<7;c=c+1)
{
document.write("<tr><td>"+n[c]+"</td></tr>");
}
TableOff();
}
In HTML I just have a button, that is onclick="RandNum()" ... Pardon for my English.
I would do it like this:
var nums = [], numsLen = 5, maxNum = 100, num;
while (nums.length < numsLen) {
num = Math.round(Math.random() * maxNum);
if (nums.indexOf(num) === -1) {
nums.push(num);
}
}
This generates an array with 5 random numbers in the range 0..100.
(numsLen cannot be greater than maxNum.)
These commands can be used to check if a value is/is not in your array:
if ( !!~n.indexOf(someVal) ) {
// someVal is in array "n"
}
if ( !~n.indexOf(someVal) ) {
// someVal is not in array "n"
}
I'd use a string, storing the generated random numbers with a divider. Then check if the newly generated number is in that string.
Something like this
generated = "";
for(var i=0;i<7;i++)
{
generate = Math.round((1+(Math.random()*40))); //generate = 5
while (generated.indexOf("[" + generate + "]") != -1) { //checking if the [5] is already in the generated string, and loop until it's a different number
generate = Math.round((1+(Math.random()*40))); //get a new random number
}
generated += "[" + generate + "]";
n[i] = generate;
}
or you can take another longer approach
for(var i=0;i<7;i++)
{
repeated = true;
while (repeated) {
repeated = false;
generate = Math.round((1+(Math.random()*40)));
for (var a=0; a < i, a++) {
if (generate == n[a]) { repeated = true; }
}
}
n[i] = generate;
}
Here's a function to generate an array of n unrepeated random numbers in [min, max):
function rands(n, min, max) {
var range = max - min;
if (range < n)
throw new RangeError("Specified number range smaller than count requested");
function shuffle() {
var deck = [], p, t;
for (var i = 0; i < range; ++i)
deck[i] = i + min;
for (i = range - 1; i > 0; --i) {
p = Math.floor(Math.random() * i);
t = deck[i];
deck[i] = deck[p];
deck[p] = t;
}
return deck.slice(0, n);
}
function find() {
var used = {}, rv = [], r;
while (rv.length < n) {
r = Math.floor(Math.random() * range + min);
if (!used[r]) {
used[r] = true;
rv.push(r);
}
}
return rv;
}
return range < 3 * n ? shuffle() : find();
}
This code checks the range of possible values and compares it to the number of random values requested. If the range is less than three times the number of values requested, the code uses the shuffle to avoid the terrible performance of the lookup approach. If the range is large, however, the lookup approach is used instead.
Not sure if OP's requirement of non-repeating is really needed, but here's a fiddle of something that could work if your number range isn't too big:
http://jsfiddle.net/6rEDV/1/
function range(start, end, step) {
if (typeof step === 'undefined') {
step = 1;
}
if (typeof start === 'undefined' || typeof end === 'undefined') {
throw TypeError('Must have start and end');
}
var ret = [];
for (var i = start; i <= end; i += step) {
ret.push(i);
}
return ret;
};
// source: http://stackoverflow.com/a/6274381/520857
function shuffle(o) { //v1.0
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
function getNonRepeatingRand(min, max, num) {
var arr = shuffle(range(min, max));
return arr.slice(0, num-1);
}
// Get 7 random numbers between and including 1 and 1000 that will *not* repeat
console.log(getNonRepeatingRand(1,1000,7));
A possibly slower, but less memory intensive method:
http://jsfiddle.net/Qnd8Q/
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getNonRepeatingRand(min, max, num) {
var ret = [];
for (var i = 0; i < num; i++) {
var n = rand(min, max);
if (ret.indexOf(n) == -1) {
ret.push(n);
} else {
i--;
}
}
return ret;
}
console.log(getNonRepeatingRand(1,5,5));
var n = new Array(),num;
function TableOn()
{
document.write("<table border='1'>");
}
function TableOff()
{
document.write("</table>");
}
function check_repition()
{
num=Math.round((1+(Math.random()*40)))
if(n.indexOf(num)==-1)
return true;
else
return false;
}
function RandNum()
{
for(var i=0;i<7;i++)
{
if(check_repition())
n[i] =num;
else // keep checking
{
check_repition()
n[i] =num;
}
}
TableOn();
for(var c=0;c<7;c=c+1)
{
document.write("<tr><td>"+n[c]+"</td></tr>");
}
TableOff();
}
RandNum()

Categories