Dungeons and Dragons - Ability scores generation - javascript

I'm trying to create an array variable containing 6 numbers from 3 to 18, generated the way we generate the ability scores for D&D 5th edition.
For those who are not familiar with the game, the concept is to roll 6 die, and add up the 3 highest results, in order to get an ability score between 3 and 18.
My problem is that even tho it is supposed to have a range between 3-18, it sometimes generates a score of 0, and never really seems to go higher than 14...
Also, if I try to do a do/while loop until the result is higher than 17, just to check out if it is possible, I get some scores of 24 and even 34... So actually, what am I doing wrong? I tried a lot of things, and still it doesn't work... if anyone could help me out, I'd be so grateful!
Here is my code for the moment:
function generation() {
var abilities = [0,0,0,0,0,0];
var i, k, c, n, p;
//for each ability (there is 6)
for (c = 0; c <= 5; c++){
var scores = [0,0,0,0,0,0]
var nb = [-1,-2,-3]
var diffMax = 0;
var iDiff = 0;
var diff = 0;
//roll 6 die
for (i = 0; i <= 5; i++){
scores[i] = Math.ceil(Math.random() * 6);
}
//for each die rolled
for (k = 0; k <= 5; k++){
//compare to each score slot (there is 3)
for (n = 0; n <= 2; n++){
//determine difference
diff = scores[k] - nb[n];
//if the difference is higher than the previously determined difference
if (diff >= diffMax){
//note the difference and the position
iDiff = n;
diffMax = diff;
}
}
//replace the lowest score slot by the result if this result is higher than the score slot
if (diffMax >= 0){
nb[iDiff] = scores[k];
}
}
//add up each score slot
for (p = 0; p <= 2; p++){
abilities[c] = abilities[c] + nb[p];
}
}
return abilities;
}

From prior comments:
let rolls = [];
let min = 1;
let max = 6;
let numrolls = 6;
for ( let i = 0; i < numrolls; i++ ) {
// Probably put this in a util function
rolls.push ( Math.floor ( Math.random () * ( max - min + 1 ) ) + min );
}
rolls = rolls.sort ( ( a, b ) => { return a < b; } );
let result = rolls
.splice ( 0, 3 )
.reduce ( ( a, b ) => { return a + b; } );
console.log ( result );

You can accomplish what you're after like this:
function sumOfThreeDice() {
rolls = [0, 0, 0, 0, 0, 0].map((x) => Math.ceil(Math.random() * 6));
rolls.sort();
sum = rolls[5] + rolls[4] + rolls[3];
return sum;
}
console.log(sumOfThreeDice());
We roll 6 dice, then add up the largest 3 by sorting the array. If you want to do this multiple times to fill up an array, you could do:
[0, 0, 0, 0, 0, 0].map(sumOfThreeDice); // generates 6 D&D ability scores

Related

there are 'X' participants. The participants are to be divided into groups. Each group can have a minimum of 6 and a maximum of 10 participants

there are 'X' participants. The participants are to be divided into groups. Each group can have a minimum of 6 and a maximum of 10 participants. How would you approach this problem, and can you write code for this problem? Optimize for a minimum number of groups. Example: If there are 81 participants, then your program should split them into 9 groups, with each group having 9 participants.
If you have an array with 90 participants and want to create new arrays with a max you could do something like this:
let participants = []
for (let i = 0; i < 90; i++) {
participants.push("Participant" + i)
}
function splitArray(array, newArrayMaxLength) {
var chunks = [], i = 0, n = array.length;
while (i < n) {
chunks.push(array.slice(i, i += newArrayMaxLength));
}
return chunks;
}
console.log(splitArray(participants, 9));
When you call this function, you pass with it an argument stating the max length of the new arrays. If the numbers does not add up, there will only be a difference with one, so ideally you would not have to do anything else, if you span is between 6-10.
Please in the future include your code if you have done any :-)
This is a variation of the classical coin change problem with result as sequence instead of minimum coins required. The base solution is recursive and given below.
function minGroup(groupSize, totalParticipants) {
// Base case
if (totalParticipants == 0) return [];
// Initialize result
let groupArray = -1;
// Try every group that is smaller
// than totalParticipants
for (let i = 0; i < groupSize.length; i++) {
if (groupSize[i] <= totalParticipants) {
let sub_arr = minGroup(groupSize, totalParticipants - groupSize[i]);
// enters if new minGroup less than current or no current solution
if (sub_arr !== -1 && (sub_arr.length + 1 < groupArray.length || groupArray === -1)) {
groupArray = sub_arr.concat([groupSize[i]])
}
}
}
return groupArray
}
The solution can be improved on by Dynamic Programming with tabulation.
function minGroupDp(groupSize, totalParticipants) {
let dpTable = new Array(totalParticipants + 1);
// base case
dpTable[0] = [];
// Initialize all dpTable values as -1
for (let i = 1; i <= totalParticipants; i++) {
dpTable[i] = -1;
}
// Compute minimum groupSize required for all
// totalParticipantss from 1 to V
for (let i = 1; i <= totalParticipants; i++) {
// Go through all groupSize smaller than current total participants
for (let j = 0; j < groupSize.length; j++)
if (groupSize[j] <= i) {
let sub_arr = dpTable[i - groupSize[j]];
// enters if new minGroup less than current or no current solution
if (
sub_arr !== -1 &&
(sub_arr.length + 1 < dpTable[i].length || dpTable[i] === -1)
)
dpTable[i] = sub_arr.concat([groupSize[j]]);
}
}
return dpTable[totalParticipants];
}

Fill an array with distanced random integers

I need an array to be filled with random integers
Those integers should be very distinct from each other i.e. must at least be 20 units of separation between each items
This is what i have tried so far :
var all = [];
var i = 0;
randomDiff();
function randomDiff() {
var num1 = randomNumber(10, 290); //chose a first random num in the range...
all[0] = num1; //...put it in first index of array
do // until you have 12 items...
{
var temp = randomNumber(10, 290); //...you pick a temporary num
var j;
for (j = 0; j < all.length; j++) // for each item already in the array
{
if ((temp < all[i] - 10) || (temp > all[i] + 10)) // if the temporary num is different enough from others members...
{
all.push(temp); //then you can store it
i++; //increment until....
console.log(all[i]);
}
}
}
while (i < 11) // ...it is filled with 12 items in array
}
////////////Radom in int range function///////////////////////////////////////
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
but always unsuccessful, including infinite loops...
Have a look on something like this:
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
const LIST_SIZE = 20;
const DISTANCE = 10;
const STOP_AFTER_ATTEMPT = 2000;
const randomList = [];
let attempt = 0;
while(randomList.length < LIST_SIZE && attempt < STOP_AFTER_ATTEMPT) {
const num = randomNumber(10, 290);
const numberExistsWithSmallerDistance = randomList.some(r => Math.abs(r - num) < DISTANCE)
if (!numberExistsWithSmallerDistance) {
randomList.push(num);
}
attempt++;
}
if (randomList.length === LIST_SIZE) {
console.log(randomList);
} else {
console.log("Failed to create array with distnct values after ", attempt, " tries");
}
Here's a solution that will always work, as long as you allow enough room in the range/separation/count you choose. And it's way more efficient than a while loop. It doesn't just keep trying until it gets it right, it actually does the math to make sure it's right the first time.
This comes at the cost of tending to lean towards certain numbers more than others (like from + (i * separation)), so take note of that.
function getSeparatedRadomInts(from, through, separation, count) {
if(through < from) return getSeparatedRadomInts(through, from, separation, count);
if(count == 0) return [];
if(separation == 0) return !!console.log("Please allow enough room in the range/separation/count you choose.");
//pick values from pool of numbers evenly stepped apart by units of separation... adding 1 to from and through if from is 0 so we can divide properly
var smallFrom = Math.ceil((from || 1) / separation);
var smallThrough = Math.floor((through + (from == 0)) / separation);
var picks = randoSequence(smallFrom, smallThrough).slice(-count).sort((a, b) => a - b);
if(picks.length < count) return !!console.log("Please allow enough room in the range/separation/count you choose.");
for (var i = 0; i < picks.length; i++) picks[i] *= separation;
//go through each pick and randomize with any wiggle room between the numbers above/below it... adding 1 to from and through if from is 0
for (var i = 0; i < picks.length; i++) {
var lowerBound = picks[i - 1] + separation || from || 1;
var upperBound = picks[i + 1] - separation || (through + (from == 0));
picks[i] = rando(lowerBound, upperBound);
}
//subtract 1 from all picks in cases where from is 0 to compensate for adding 1 earlier
for (var i = 0; i < picks.length; i++) if(from == 0) picks[i] = picks[i] - 1;
return picks;
}
console.log(getSeparatedRadomInts(10, 290, 20, 12));
<script src="https://randojs.com/1.0.0.js"></script>
To be clear, from is the minimum range value, through is the maximum range value, separation is the minimum each number must be apart from each other (a separation of 20 could result in [10, 30, 50, 70], for example), and count is how many values you want to pick.
I used randojs in this code to simplify the randomness and make it easier to read, so if you want to use this code, just remember to paste this in the head of your HTML document:
<script src="https://randojs.com/1.0.0.js"></script>

How to stop a For Loop in a middle and continue from there down back in JavaScript

I have a JavaScript code like so:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == myArray.length - 1) { di = -1; }
document.writeln(myArray[i]);
}
I need it to stop right in the middle like 10 and from 10 starts counting down to 0 back.
So far, I've managed to make it work from 0 to 20 and from 20 - 0.
How can I stop it in a middle and start it from there back?
Please help anyone!
Here is an example using a function which accepts the array and the number of items you want to display forwards and backwards:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
if(myArray.length === 1){
ShowXElementsForwardsAndBackwards(myArray, 1);
}
else if(myArray.length === 0) {
//Do nothing as there are no elements in array and dividing 0 by 2 would be undefined
}
else {
ShowXElementsForwardsAndBackwards(myArray, (myArray.length / 2));
}
function ShowXElementsForwardsAndBackwards(mYarray, numberOfItems){
if (numberOfItems >= mYarray.length) {
throw "More Numbers requested than length of array!";
}
for(let x = 0; x < numberOfItems; x++){
document.writeln(mYarray[x]);
}
for(let y = numberOfItems - 1; y >= 0; y--){
document.writeln(mYarray[y]);
}
}
Just divide your array length by 2
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == ((myArray.length / 2) -1 )) { di = -1; }
document.writeln(myArray[i]);
}
Could Array.reverse() help you in this matter?
const array = [0,1,3,4,5,6,7,8,9,10,11,12,13,14,15]
const getArrayOfAmount = (array, amount) => array.filter((item, index) => index < amount)
let arraySection = getArrayOfAmount(array, 10)
let reversed = [...arraySection].reverse()
console.log(arraySection)
console.log(reversed)
And then you can "do stuff" with each array with watever array manipulation you desire.
Couldn’t you just check if you’ve made it halfway and then subtract your current spot from the length?
for(i = 0; i <= myArray.length; i++){
if( Math.round(i/myArray.length) == 1 ){
document.writeln( myArray[ myArray.length - i] );
} else {
document.writeln( myArray[i] );
}
}
Unless I’m missing something?
You could move the checking into the condition block of the for loop.
var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
for (
var i = 0, l = (myArray.length >> 1) - 1, di = 1;
i === l && (di = -1), i >= 0;
i += di
) {
document.writeln(myArray[i]);
}
If you capture the midpoint ( half the length of the array ), just start working your step in the opposite direction.
const N = 20;
let myArray = [...Array(N).keys()];
let midpoint = Math.round(myArray.length/2)
for ( let i=1, step=1; i; i+=step) {
if (i === midpoint)
step *= -1
document.writeln(myArray[i])
}
To make things clearer, I've:
Started the loop iterator variable (i) at 1; this also meant the array has an unused 0 value at 0 index; in other words, myArray[0]==0 that's never shown
Set the the loop terminating condition to i, which means when i==0 the loop will stop because it is falsy
Renamed the di to step, which is more consistent with other terminology
The midpoint uses a Math.round() to ensure it's the highest integer (midpoint) (e.g., 15/2 == 7.5 but you want it to be 8 )
The midpoint is a variable for performance reasons; calculating the midpoint in the loop body is redundant and less efficient since it only needs to be calculated once
For practical purpose, made sizing the array dynamic using N
Updated to ES6/ES7 -- this is now non-Internet Explorer-friendly [it won't work in IE ;)] primarily due to the use of the spread operator (...) ... but that's easily avoidable

Shuffle array and prevent more than 2 in a row

I have an array being built like this:
var entries = ['L','L','L','L','L','L','L','L','L','L','R','R','R','R','R','R','R','R','R','R','M','M','M','M','M']
This means the array is always filled with 10 times L, 10 times R and 5 times M
The output I want to achieve is a randomly generated array, so I came up with the simple solution to just shuffle it with
function shuffle(o){
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;
}
The problem I have now is that there is a rule for the outcome, never have one of these letters more than 2 times in a row. So I thought I just use a do/while loop to shuffle until that criteria is met. But in my test runs this totally fails with long loops.
So my question is - what is the best way to build this array without depending on luck. My full program that fails is something like this
function shuffle(o){
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 createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
//Build array with L/R/M
for( d=0; d < 10; d++ ){
program.push('L');
program.push('R');
if(d < 5){
program.push('M');
}
}
// This will run way too long and is not reliable
//do{
// program = shuffle(program);
//}while(!checkProgram(program))
if(!checkProgram(program)){
console.log('invalid program at ' + s);
}
programs[s] = program;
}
return programs;
}
function checkProgram(program){
var len = program.length;
var last = null;
var dups = 0;
for(var i=0; i<len; len++){
if(program[i] == last){
dups++;
}else{
dups = 0;
}
if(dups == 2){
return false;
}
last = program[i];
}
return true;
}
createProgram(5);
Instead of just shuffle arrays and hope for one without duplicates, you can create them by picking characters by random and specifically avoid to pick the character that was picked previously.
If you keep track of how many there are left to pick of each character, you can control the odds for the character to pick so that the distribution is correct. If for example the first two characters are L, then there are 10 R and 5 M left to pick from (and 8 L, but they are excluded for the next pick), so there should be a 2 in 3 chance to pick an R and a 1 in 3 chance to pick and M.
This approach can run into a dead end, where the array can't be completed, so it has to start over. Running it a few hundred times I have seen something like a 10% overhead, so if you create five arrays you should by average see a retry every other time.
function createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
var chars = [ 'L', 'R', 'M' ];
var program;
do {
program = [];
var cnt = [ 10, 10, 5, 0 ]; // picks left
var prev = 3; // previous pick
var tot = 25; // total picks left
while (program.length < 25) {
// check for duplicates
var x = program.length >= 2 && program[program.length - 2] == program[program.length - 1] ? prev : 3;
// check if more picks are possible
if (tot - cnt[x] <= 0) {
console.log('invalid program ' + program);
break;
}
// pick from the possible
var r = Math.floor(Math.random() * (tot - cnt[x]));
// determine what character was picked
var c = 0;
while (c == x || r >= cnt[c]) {
if (c != x) r -= cnt[c];
c++;
}
program.push(chars[c]);
cnt[c]--;
tot--;
prev = c;
}
} while (program.length < 25);
programs[s] = program;
}
return programs;
}
console.log(createProgram(1).toString());
So this is the final solution I came up with, as commented Guffas solution also works nice and smooth. But after doing some tests mine is about 30% faster and more readable, but way longer so I'll accept Guffas - thanks to everybody for their input!
function createProgram(numShooters){
var programs = [];
for(var s = 0; s < numShooters; s++){
var program = buildProgram();
programs[s] = program;
}
return programs;
}
function buildProgram(){
var program = [];
var ls = fillArray('L',10);
var rs = fillArray('R',10);
var ms = fillArray('M',5);
//Use either L or R to mix into M - adds variation
var side = Math.random() > 0.5 ? ls : rs;
var otherSide = side == ls ? rs : ls;
var initProg = side.concat(ms);
initProg = shuffle(initProg);
var program = [];
//Correcting invalid positions as suggested
for(var p1 = 0; p1 < initProg.length; p1++){
if(p1 > 1 && initProg[p1-1] == initProg[p1-2] && initProg[p1-1] == initProg[p1]){
if(otherSide.length > 0){
program.push(otherSide.pop());
}else{
return buildProgram(); //impossible state, redo...
}
}
program.push(initProg[p1]);
}
//Fill into remaining other pos
for(var p2 = 0; p2 < otherSide.length; p2++){
program = addAtRandomPos(program,otherSide[p2]);
}
return program;
}
function addAtRandomPos(arr,chr){
var pos = getRandomInt( 0, arr.length - 1 );
var charCur = arr[pos];
var pprev = pos > 1 ? arr[pos-2] : null;
var prev = pos > 0 ? arr[pos-1] : null;
var next = pos < arr.length - 1 ? arr[pos] : null;
var nnext = pos < arr.length - 2 ? arr[pos+1] : null;
var str = pprev + prev + chr + next + nnext;
if(str.indexOf('MMM') !== -1 || str.indexOf('RRR') !== -1 || str.indexOf('LLL') !== -1){
return addAtRandomPos(arr,chr);
}else{
arr.splice(pos,0,chr);
}
return arr;
}
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function fillArray(chr,num){
var arr = [];
for(i = 0; i < num; i++){
arr.push(chr);
}
return arr;
}

How to find prime numbers between 0 - 100?

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
In Javascript how would i find prime numbers between 0 - 100? i have thought about it, and i am not sure how to find them. i thought about doing x % x but i found the obvious problem with that.
this is what i have so far:
but unfortunately it is the worst code ever.
var prime = function (){
var num;
for (num = 0; num < 101; num++){
if (num % 2 === 0){
break;
}
else if (num % 3 === 0){
break;
}
else if (num % 4=== 0){
break;
}
else if (num % 5 === 0){
break;
}
else if (num % 6 === 0){
break;
}
else if (num % 7 === 0){
break;
}
else if (num % 8 === 0){
break;
}
else if (num % 9 === 0){
break;
}
else if (num % 10 === 0){
break;
}
else if (num % 11 === 0){
break;
}
else if (num % 12 === 0){
break;
}
else {
return num;
}
}
};
console.log(prime());
Here's an example of a sieve implementation in JavaScript:
function getPrimes(max) {
var sieve = [], i, j, primes = [];
for (i = 2; i <= max; ++i) {
if (!sieve[i]) {
// i has not been marked -- it is prime
primes.push(i);
for (j = i << 1; j <= max; j += i) {
sieve[j] = true;
}
}
}
return primes;
}
Then getPrimes(100) will return an array of all primes between 2 and 100 (inclusive). Of course, due to memory constraints, you can't use this with large arguments.
A Java implementation would look very similar.
Here's how I solved it. Rewrote it from Java to JavaScript, so excuse me if there's a syntax error.
function isPrime (n)
{
if (n < 2) return false;
/**
* An integer is prime if it is not divisible by any prime less than or equal to its square root
**/
var q = Math.floor(Math.sqrt(n));
for (var i = 2; i <= q; i++)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
A number, n, is a prime if it isn't divisible by any other number other than by 1 and itself. Also, it's sufficient to check the numbers [2, sqrt(n)].
Here is the live demo of this script: http://jsfiddle.net/K2QJp/
First, make a function that will test if a single number is prime or not. If you want to extend the Number object you may, but I decided to just keep the code as simple as possible.
function isPrime(num) {
if(num < 2) return false;
for (var i = 2; i < num; i++) {
if(num%i==0)
return false;
}
return true;
}
This script goes through every number between 2 and 1 less than the number and tests if there is any number in which there is no remainder if you divide the number by the increment. If there is any without a remainder, it is not prime. If the number is less than 2, it is not prime. Otherwise, it is prime.
Then make a for loop to loop through the numbers 0 to 100 and test each number with that function. If it is prime, output the number to the log.
for(var i = 0; i < 100; i++){
if(isPrime(i)) console.log(i);
}
Whatever the language, one of the best and most accessible ways of finding primes within a range is using a sieve.
Not going to give you code, but this is a good starting point.
For a small range, such as yours, the most efficient would be pre-computing the numbers.
I have slightly modified the Sieve of Sundaram algorithm to cut the unnecessary iterations and it seems to be very fast.
This algorithm is actually two times faster than the most accepted #Ted Hopp's solution under this topic. Solving the 78498 primes between 0 - 1M takes like 20~25 msec in Chrome 55 and < 90 msec in FF 50.1. Also #vitaly-t's get next prime algorithm looks interesting but also results much slower.
This is the core algorithm. One could apply segmentation and threading to get superb results.
"use strict";
function primeSieve(n){
var a = Array(n = n/2),
t = (Math.sqrt(4+8*n)-2)/4,
u = 0,
r = [];
for(var i = 1; i <= t; i++){
u = (n-i)/(1+2*i);
for(var j = i; j <= u; j++) a[i + j + 2*i*j] = true;
}
for(var i = 0; i<= n; i++) !a[i] && r.push(i*2+1);
return r;
}
var primes = [];
console.time("primes");
primes = primeSieve(1000000);
console.timeEnd("primes");
console.log(primes.length);
The loop limits explained:
Just like the Sieve of Erasthotenes, the Sieve of Sundaram algorithm also crosses out some selected integers from the list. To select which integers to cross out the rule is i + j + 2ij ≤ n where i and j are two indices and n is the number of the total elements. Once we cross out every i + j + 2ij, the remaining numbers are doubled and oddified (2n+1) to reveal a list of prime numbers. The final stage is in fact the auto discounting of the even numbers. It's proof is beautifully explained here.
Sieve of Sundaram is only fast if the loop indices start and end limits are correctly selected such that there shall be no (or minimal) redundant (multiple) elimination of the non-primes. As we need i and j values to calculate the numbers to cross out, i + j + 2ij up to n let's see how we can approach.
i) So we have to find the the max value i and j can take when they are equal. Which is 2i + 2i^2 = n. We can easily solve the positive value for i by using the quadratic formula and that is the line with t = (Math.sqrt(4+8*n)-2)/4,
j) The inner loop index j should start from i and run up to the point it can go with the current i value. No more than that. Since we know that i + j + 2ij = n, this can easily be calculated as u = (n-i)/(1+2*i);
While this will not completely remove the redundant crossings it will "greatly" eliminate the redundancy. For instance for n = 50 (to check for primes up to 100) instead of doing 50 x 50 = 2500, we will do only 30 iterations in total. So clearly, this algorithm shouldn't be considered as an O(n^2) time complexity one.
i j v
1 1 4
1 2 7
1 3 10
1 4 13
1 5 16
1 6 19
1 7 22 <<
1 8 25
1 9 28
1 10 31 <<
1 11 34
1 12 37 <<
1 13 40 <<
1 14 43
1 15 46
1 16 49 <<
2 2 12
2 3 17
2 4 22 << dupe #1
2 5 27
2 6 32
2 7 37 << dupe #2
2 8 42
2 9 47
3 3 24
3 4 31 << dupe #3
3 5 38
3 6 45
4 4 40 << dupe #4
4 5 49 << dupe #5
among which there are only 5 duplicates. 22, 31, 37, 40, 49. The redundancy is around 20% for n = 100 however it increases to ~300% for n = 10M. Which means a further optimization of SoS bears the potentital to obtain the results even faster as n grows. So one idea might be segmentation and to keep n small all the time.
So OK.. I have decided to take this quest a little further.
After some careful examination of the repeated crossings I have come to the awareness of the fact that, by the exception of i === 1 case, if either one or both of the i or j index value is among 4,7,10,13,16,19... series, a duplicate crossing is generated. Then allowing the inner loop to turn only when i%3-1 !== 0, a further cut down like 35-40% from the total number of the loops is achieved. So for instance for 1M integers the nested loop's total turn count dropped to like 1M from 1.4M. Wow..! We are talking almost O(n) here.
I have just made a test. In JS, just an empty loop counting up to 1B takes like 4000ms. In the below modified algorithm, finding the primes up to 100M takes the same amount of time.
I have also implemented the segmentation part of this algorithm to push to the workers. So that we will be able to use multiple threads too. But that code will follow a little later.
So let me introduce you the modified Sieve of Sundaram probably at it's best when not segmented. It shall compute the primes between 0-1M in about 15-20ms with Chrome V8 and Edge ChakraCore.
"use strict";
function primeSieve(n){
var a = Array(n = n/2),
t = (Math.sqrt(4+8*n)-2)/4,
u = 0,
r = [];
for(var i = 1; i < (n-1)/3; i++) a[1+3*i] = true;
for(var i = 2; i <= t; i++){
u = (n-i)/(1+2*i);
if (i%3-1) for(var j = i; j < u; j++) a[i + j + 2*i*j] = true;
}
for(var i = 0; i< n; i++) !a[i] && r.push(i*2+1);
return r;
}
var primes = [];
console.time("primes");
primes = primeSieve(1000000);
console.timeEnd("primes");
console.log(primes.length);
Well... finally I guess i have implemented a sieve (which is originated from the ingenious Sieve of Sundaram) such that it's the fastest JavaScript sieve that i could have found over the internet, including the "Odds only Sieve of Eratosthenes" or the "Sieve of Atkins". Also this is ready for the web workers, multi-threading.
Think it this way. In this humble AMD PC for a single thread, it takes 3,300 ms for JS just to count up to 10^9 and the following optimized segmented SoS will get me the 50847534 primes up to 10^9 only in 14,000 ms. Which means 4.25 times the operation of just counting. I think it's impressive.
You can test it for yourself;
console.time("tare");
for (var i = 0; i < 1000000000; i++);
console.timeEnd("tare");
And here I introduce you to the segmented Seieve of Sundaram at it's best.
"use strict";
function findPrimes(n){
function primeSieve(g,o,r){
var t = (Math.sqrt(4+8*(g+o))-2)/4,
e = 0,
s = 0;
ar.fill(true);
if (o) {
for(var i = Math.ceil((o-1)/3); i < (g+o-1)/3; i++) ar[1+3*i-o] = false;
for(var i = 2; i < t; i++){
s = Math.ceil((o-i)/(1+2*i));
e = (g+o-i)/(1+2*i);
if (i%3-1) for(var j = s; j < e; j++) ar[i + j + 2*i*j-o] = false;
}
} else {
for(var i = 1; i < (g-1)/3; i++) ar[1+3*i] = false;
for(var i = 2; i < t; i++){
e = (g-i)/(1+2*i);
if (i%3-1) for(var j = i; j < e; j++) ar[i + j + 2*i*j] = false;
}
}
for(var i = 0; i < g; i++) ar[i] && r.push((i+o)*2+1);
return r;
}
var cs = n <= 1e6 ? 7500
: n <= 1e7 ? 60000
: 100000, // chunk size
cc = ~~(n/cs), // chunk count
xs = n % cs, // excess after last chunk
ar = Array(cs/2), // array used as map
result = [];
for(var i = 0; i < cc; i++) result = primeSieve(cs/2,i*cs/2,result);
result = xs ? primeSieve(xs/2,cc*cs/2,result) : result;
result[0] *=2;
return result;
}
var primes = [];
console.time("primes");
primes = findPrimes(1000000000);
console.timeEnd("primes");
console.log(primes.length);
Here I present a multithreaded and slightly improved version of the above algorithm. It utilizes all available threads on your device and resolves all 50,847,534 primes up to 1e9 (1 Billion) in the ballpark of 1.3 seconds on my trash AMD FX-8370 8 core desktop.
While there exists some very sophisticated sublinear sieves, I believe the modified Segmented Sieve of Sundaram could only be stretced this far to being linear in time complexity. Which is not bad.
class Threadable extends Function {
constructor(f){
super("...as",`return ${f.toString()}.apply(this,as)`);
}
spawn(...as){
var code = `self.onmessage = m => self.postMessage(${this.toString()}.apply(null,m.data));`,
blob = new Blob([code], {type: "text/javascript"}),
wrkr = new Worker(window.URL.createObjectURL(blob));
return new Promise((v,x) => ( wrkr.onmessage = m => (v(m.data), wrkr.terminate())
, wrkr.onerror = e => (x(e.message), wrkr.terminate())
, wrkr.postMessage(as)
));
}
}
function pi(n){
function scan(start,end,tid){
function sieve(g,o){
var t = (Math.sqrt(4+8*(g+o))-2)/4,
e = 0,
s = 0,
a = new Uint8Array(g),
c = 0,
l = o ? (g+o-1)/3
: (g-1)/3;
if (o) {
for(var i = Math.ceil((o-1)/3); i < l; i++) a[1+3*i-o] = 0x01;
for(var i = 2; i < t; i++){
if (i%3-1) {
s = Math.ceil((o-i)/(1+2*i));
e = (g+o-i)/(1+2*i);
for(var j = s; j < e; j++) a[i + j + 2*i*j-o] = 0x01;
}
}
} else {
for(var i = 1; i < l; i++) a[1+3*i] = 0x01;
for(var i = 2; i < t; i++){
if (i%3-1){
e = (g-i)/(1+2*i);
for(var j = i; j < e; j++) a[i + j + 2*i*j] = 0x01;
}
}
}
for (var i = 0; i < g; i++) !a[i] && c++;
return c;
}
end % 2 && end--;
start % 2 && start--;
var n = end - start,
cs = n < 2e6 ? 1e4 :
n < 2e7 ? 2e5 :
4.5e5 , // Math.floor(3*n/1e3), // chunk size
cc = Math.floor(n/cs), // chunk count
xs = n % cs, // excess after last chunk
pc = 0;
for(var i = 0; i < cc; i++) pc += sieve(cs/2,(start+i*cs)/2);
xs && (pc += sieve(xs/2,(start+cc*cs)/2));
return pc;
}
var tc = navigator.hardwareConcurrency,
xs = n % tc,
cs = (n-xs) / tc,
st = new Threadable(scan),
ps = Array.from( {length:tc}
, (_,i) => i ? st.spawn(i*cs+xs,(i+1)*cs+xs,i)
: st.spawn(0,cs+xs,i)
);
return Promise.all(ps);
}
var n = 1e9,
count;
console.time("primes");
pi(n).then(cs => ( count = cs.reduce((p,c) => p+c)
, console.timeEnd("primes")
, console.log(count)
)
)
.catch(e => console.log(`Error: ${e}`));
So this is as far as I could take the Sieve of Sundaram.
A number is a prime if it is not divisible by other primes lower than the number in question.
So this builds up a primes array. Tests each new odd candidate n for division against existing found primes lower than n. As an optimization it does not consider even numbers and prepends 2 as a final step.
var primes = [];
for(var n=3;n<=100;n+=2) {
if(primes.every(function(prime){return n%prime!=0})) {
primes.push(n);
}
}
primes.unshift(2);
To find prime numbers between 0 to n. You just have to check if a number x is getting divisible by any number between 0 - (square root of x). If we pass n and to find all prime numbers between 0 and n, logic can be implemented as -
function findPrimeNums(n)
{
var x= 3,j,i=2,
primeArr=[2],isPrime;
for (;x<=n;x+=2){
j = (int) Math.sqrt (x);
isPrime = true;
for (i = 2; i <= j; i++)
{
if (x % i == 0){
isPrime = false;
break;
}
}
if(isPrime){
primeArr.push(x);
}
}
return primeArr;
}
var n=100;
var counter = 0;
var primeNumbers = "Prime Numbers: ";
for(var i=2; i<=n; ++i)
{
counter=0;
for(var j=2; j<=n; ++j)
{
if(i>=j && i%j == 0)
{
++counter;
}
}
if(counter == 1)
{
primeNumbers = primeNumbers + i + " ";
}
}
console.log(primeNumbers);
Luchian's answer gives you a link to the standard technique for finding primes.
A less efficient, but simpler approach is to turn your existing code into a nested loop. Observe that you are dividing by 2,3,4,5,6 and so on ... and turn that into a loop.
Given that this is homework, and given that the aim of the homework is to help you learn basic programming, a solution that is simple, correct but somewhat inefficient should be fine.
Using recursion combined with the square root rule from here, checks whether a number is prime or not:
function isPrime(num){
// An integer is prime if it is not divisible by any prime less than or equal to its square root
var squareRoot = parseInt(Math.sqrt(num));
var primeCountUp = function(divisor){
if(divisor > squareRoot) {
// got to a point where the divisor is greater than
// the square root, therefore it is prime
return true;
}
else if(num % divisor === 0) {
// found a result that divides evenly, NOT prime
return false;
}
else {
// keep counting
return primeCountUp(++divisor);
}
};
// start # 2 because everything is divisible by 1
return primeCountUp(2);
}
You can try this method also, this one is basic but easy to understand:
var tw = 2, th = 3, fv = 5, se = 7;
document.write(tw + "," + th + ","+ fv + "," + se + ",");
for(var n = 0; n <= 100; n++)
{
if((n % tw !== 0) && (n % th !==0) && (n % fv !==0 ) && (n % se !==0))
{
if (n == 1)
{
continue;
}
document.write(n +",");
}
}
I recently came up with a one-line solution that accomplishes exactly this for a JS challenge on Scrimba (below).
ES6+
const getPrimes=num=>Array(num-1).fill().map((e,i)=>2+i).filter((e,i,a)=>a.slice(0,i).every(x=>e%x!==0));
< ES6
function getPrimes(num){return ",".repeat(num).slice(0,-1).split(',').map(function(e,i){return i+1}).filter(function(e){return e>1}).filter(function(x){return ",".repeat(x).slice(0,-1).split(',').map(function(f,j){return j}).filter(function(e){return e>1}).every(function(e){return x%e!==0})})};
This is the logic explained:
First, the function builds an array of all numbers leading up to the desired number (in this case, 100) via the .repeat() function using the desired number (100) as the repeater argument and then mapping the array to the indexes+1 to get the range of numbers from 0 to that number (0-100). A bit of string splitting and joining magic going on here. I'm happy to explain this step further if you like.
We exclude 0 and 1 from the array as they should not be tested for prime, lest they give a false positive. Neither are prime. We do this using .filter() for only numbers > 1 (≥ 2).
Now, we filter our new array of all integers between 2 and the desired number (100) for only prime numbers. To filter for prime numbers only, we use some of the same magic from our first step. We use .filter() and .repeat() once again to create a new array from 2 to each value from our new array of numbers. For each value's new array, we check to see if any of the numbers ≥ 2 and < that number are factors of the number. We can do this using the .every() method paired with the modulo operator % to check if that number has any remainders when divided by any of those values between 2 and itself. If each value has remainders (x%e!==0), the condition is met for all values from 2 to that number (but not including that number, i.e.: [2,99]) and we can say that number is prime. The filter functions returns all prime numbers to the uppermost return, thereby returning the list of prime values between 2 and the passed value.
As an example, using one of these functions I've added above, returns the following:
getPrimes(100);
// => [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
Here's a fast way to calculate primes in JavaScript, based on the previous prime value.
function nextPrime(value) {
if (value > 2) {
var i, q;
do {
i = 3;
value += 2;
q = Math.floor(Math.sqrt(value));
while (i <= q && value % i) {
i += 2;
}
} while (i <= q);
return value;
}
return value === 2 ? 3 : 2;
}
Test
var value = 0, result = [];
for (var i = 0; i < 10; i++) {
value = nextPrime(value);
result.push(value);
}
console.log("Primes:", result);
Output
Primes: [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ]
It is faster than other alternatives published here, because:
It aligns the loop limit to an integer, which works way faster;
It uses a shorter iteration loop, skipping even numbers.
It can give you the first 100,000 primes in about 130ms, or the first 1m primes in about 4 seconds.
function nextPrime(value) {
if (value > 2) {
var i, q;
do {
i = 3;
value += 2;
q = Math.floor(Math.sqrt(value));
while (i <= q && value % i) {
i += 2;
}
} while (i <= q);
return value;
}
return value === 2 ? 3 : 2;
}
var value, result = [];
for (var i = 0; i < 10; i++) {
value = nextPrime(value);
result.push(value);
}
display("Primes: " + result.join(', '));
function display(msg) {
document.body.insertAdjacentHTML(
"beforeend",
"<p>" + msg + "</p>"
);
}
UPDATE
A modern, efficient way of doing it, using prime-lib:
import {generatePrimes, stopWhen} from 'prime-lib';
const p = generatePrimes(); //=> infinite prime generator
const i = stopWhen(p, a => a > 100); //=> Iterable<number>
console.log(...i); //=> 2 3 5 7 11 ... 89 97
<code>
<script language="javascript">
var n=prompt("Enter User Value")
var x=1;
if(n==0 || n==1) x=0;
for(i=2;i<n;i++)
{
if(n%i==0)
{
x=0;
break;
}
}
if(x==1)
{
alert(n +" "+" is prime");
}
else
{
alert(n +" "+" is not prime");
}
</script>
Sieve of Eratosthenes. its bit look but its simple and it works!
function count_prime(arg) {
arg = typeof arg !== 'undefined' ? arg : 20; //default value
var list = [2]
var list2 = [0,1]
var real_prime = []
counter = 2
while (counter < arg ) {
if (counter % 2 !== 0) {
list.push(counter)
}
counter++
}
for (i = 0; i < list.length - 1; i++) {
var a = list[i]
for (j = 0; j < list.length - 1; j++) {
if (list[j] % a === 0 && list[j] !== a) {
list[j] = false; // assign false to non-prime numbers
}
}
if (list[i] !== false) {
real_prime.push(list[i]); // save all prime numbers in new array
}
}
}
window.onload=count_prime(100);
And this famous code from a famous JS Ninja
var isPrime = n => Array(Math.ceil(Math.sqrt(n)+1)).fill().map((e,i)=>i).slice(2).every(m => n%m);
console.log(Array(100).fill().map((e,i)=>i+1).slice(1).filter(isPrime));
A list built using the new features of ES6, especially with generator.
Go to https://codepen.io/arius/pen/wqmzGp made in Catalan language for classes with my students. I hope you find it useful.
function* Primer(max) {
const infinite = !max && max !== 0;
const re = /^.?$|^(..+?)\1+$/;
let current = 1;
while (infinite || max-- ) {
if(!re.test('1'.repeat(current)) == true) yield current;
current++
};
};
let [...list] = Primer(100);
console.log(list);
Here's the very simple way to calculate primes between a given range(1 to limit).
Simple Solution:
public static void getAllPrimeNumbers(int limit) {
System.out.println("Printing prime number from 1 to " + limit);
for(int number=2; number<=limit; number++){
//***print all prime numbers upto limit***
if(isPrime(number)){
System.out.println(number);
}
}
}
public static boolean isPrime(int num) {
if (num == 0 || num == 1) {
return false;
}
if (num == 2) {
return true;
}
for (int i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
A version without any loop. Use this against any array you have. ie.,
[1,2,3...100].filter(x=>isPrime(x));
const isPrime = n => {
if(n===1){
return false;
}
if([2,3,5,7].includes(n)){
return true;
}
return n%2!=0 && n%3!=0 && n%5!=0 && n%7!=0;
}
Here's my stab at it.
Change the initial i=0 from 0 to whatever you want, and the the second i<100 from 100 to whatever to get primes in a different range.
for(var i=0; i<100000; i++){
var devisableCount = 2;
for(var x=0; x<=i/2; x++){
if (devisableCount > 3) {
break;
}
if(i !== 1 && i !== 0 && i !== x){
if(i%x === 0){
devisableCount++;
}
}
}
if(devisableCount === 3){
console.log(i);
}
}
I tried it with 10000000 - it takes some time but appears to be accurate.
Here are the Brute-force iterative method and Sieve of Eratosthenes method to find prime numbers upto n. The performance of the second method is better than first in terms of time complexity
Brute-force iterative
function findPrime(n) {
var res = [2],
isNotPrime;
for (var i = 3; i < n; i++) {
isNotPrime = res.some(checkDivisorExist);
if ( !isNotPrime ) {
res.push(i);
}
}
function checkDivisorExist (j) {
return i % j === 0;
}
return res;
}
Sieve of Eratosthenes method
function seiveOfErasthones (n) {
var listOfNum =range(n),
i = 2;
// CHeck only until the square of the prime is less than number
while (i*i < n && i < n) {
listOfNum = filterMultiples(listOfNum, i);
i++;
}
return listOfNum;
function range (num) {
var res = [];
for (var i = 2; i <= num; i++) {
res.push(i);
}
return res;
}
function filterMultiples (list, x) {
return list.filter(function (item) {
// Include numbers smaller than x as they are already prime
return (item <= x) || (item > x && item % x !== 0);
});
}
}
You can use this for any size of array of prime numbers. Hope this helps
function prime() {
var num = 2;
var body = document.getElementById("solution");
var len = arguments.length;
var flag = true;
for (j = 0; j < len; j++) {
for (i = num; i < arguments[j]; i++) {
if (arguments[j] % i == 0) {
body.innerHTML += arguments[j] + " False <br />";
flag = false;
break;
} else {
flag = true;
}
}
if (flag) {
body.innerHTML += arguments[j] + " True <br />";
}
}
}
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
prime.apply(null, data);
<div id="solution">
</div>
public static void main(String[] args) {
int m = 100;
int a[] =new int[m];
for (int i=2; i<m; i++)
for (int j=0; j<m; j+=i)
a[j]++;
for (int i=0; i<m; i++)
if (a[i]==1) System.out.println(i);
}
Using Sieve of Eratosthenes, source on Rosettacode
fastest solution: https://repl.it/#caub/getPrimes-bench
function getPrimes(limit) {
if (limit < 2) return [];
var sqrtlmt = limit**.5 - 2;
var nums = Array.from({length: limit-1}, (_,i)=>i+2);
for (var i = 0; i <= sqrtlmt; i++) {
var p = nums[i]
if (p) {
for (var j = p * p - 2; j < nums.length; j += p)
nums[j] = 0;
}
}
return nums.filter(x => x); // return non 0 values
}
document.body.innerHTML = `<pre style="white-space:pre-wrap">${getPrimes(100).join(', ')}</pre>`;
// for fun, this fantasist regexp way (very inefficient):
// Array.from({length:101}, (_,i)=>i).filter(n => n>1&&!/^(oo+)\1+$/.test('o'.repeat(n))
Why try deleting by 4 (and 6,8,10,12) if we've already tried deleting by 2 ?
Why try deleting by 9 if we've already tried deleting by 3 ?
Why try deleting by 11 if 11 * 11 = 121 which is greater than 100 ?
Why try deleting any odd number by 2 at all?
Why try deleting any even number above 2 by anything at all?
Eliminate the dead tests and you'll get yourself a good code, testing for primes below 100.
And your code is very far from being the worst code ever. Many many others would try dividing 100 by 99. But the absolute champion would generate all products of 2..96 with 2..96 to test whether 97 is among them. That one really is astonishingly inefficient.
Sieve of Eratosthenes of course is much better, and you can have one -- under 100 -- with no arrays of booleans (and no divisions too!):
console.log(2)
var m3 = 9, m5 = 25, m7 = 49, i = 3
for( ; i < 100; i += 2 )
{
if( i != m3 && i != m5 && i != m7) console.log(i)
else
{
if( i == m3 ) m3 += 6
if( i == m5 ) m5 += 10
if( i == m7 ) m7 += 14
}
} "DONE"
This is the sieve of Eratosthenes, were we skip over the composites - and that's what this code is doing. The timing of generation of composites and of skipping over them (by checking for equality) is mixed into one timeline. The usual sieve first generates composites and marks them in an array, then sweeps the array. Here the two stages are mashed into one, to avoid having to use any array at all (this only works because we know the top limit's square root - 10 - in advance and use only primes below it, viz. 3,5,7 - with 2's multiples, i.e. evens, implicitly skipped over in advance).
In other words this is an incremental sieve of Eratosthenes and m3, m5, m7 form an implicit priority queue of the multiples of primes 3, 5, and 7.
I was searching how to find out prime number and went through above code which are too long. I found out a new easy solution for prime number and add them using filter. Kindly suggest me if there is any mistake in my code as I am a beginner.
function sumPrimes(num) {
let newNum = [];
for(let i = 2; i <= num; i++) {
newNum.push(i)
}
for(let i in newNum) {
newNum = newNum.filter(item => item == newNum[i] || item % newNum[i] !== 0)
}
return newNum.reduce((a,b) => a+b)
}
sumPrimes(10);
Here is an efficient, short solution using JS generators. JSfiddle
// Consecutive integers
let nats = function* (n) {
while (true) yield n++
}
// Wrapper generator
let primes = function* () {
yield* sieve(primes(), nats(2))
}
// The sieve itself; only tests primes up to sqrt(n)
let sieve = function* (pg, ng) {
yield ng.next().value;
let n, p = pg.next().value;
while ((n = ng.next().value) < p * p) yield n;
yield* sieve(pg, (function* () {
while (n = ng.next().value) if (n % p) yield n
})())
}
// Longest prefix of stream where some predicate holds
let take = function* (vs, fn) {
let nx;
while (!(nx = vs.next()).done && fn(nx.value)) yield nx.value
}
document.querySelectorAll('dd')[0].textContent =
// Primes smaller than 100
[...take(primes(), x => x < 100)].join(', ')
<dl>
<dt>Primes under 100</dt>
<dd></dd>
</dl>
First, change your inner code for another loop (for and while) so you can repeat the same code for different values.
More specific for your problem, if you want to know if a given n is prime, you need to divide it for all values between 2 and sqrt(n). If any of the modules is 0, it is not prime.
If you want to find all primes, you can speed it and check n only by dividing by the previously found primes. Another way of speeding the process is the fact that, apart from 2 and 3, all the primes are 6*k plus or less 1.
It would behoove you, if you're going to use any of the gazillion algorithms that you're going to be presented with in this thread, to learn to memoize some of them.
See Interview question : What is the fastest way to generate prime number recursively?
Use following function to find out prime numbers :
function primeNumbers() {
var p
var n = document.primeForm.primeText.value
var d
var x
var prime
var displayAll = 2 + " "
for (p = 3; p <= n; p = p + 2) {
x = Math.sqrt(p)
prime = 1
for (d = 3; prime && (d <= x); d = d + 2)
if ((p % d) == 0) prime = 0
else prime = 1
if (prime == 1) {
displayAll = displayAll + p + " "
}
}
document.primeForm.primeArea.value = displayAll
}

Categories

Resources