Animation in JavaScript with Modulo - javascript

Is it possible, to store the logged numbers from this loop in an array? I have to solve something like this: Some people turn up in rows of two. When they line up, one is remaining. Same as the show up in rows of three, four, five and six people. But as people turn up in rows of seven, no one is left (the result is 301).
I have to animate this "people", which show up, for every row separately, until 301. It should be a little game with user input (or just buttons). I tried with something like below, but I don't even know, if I'm completely wrong.
I thought, that it would work, if I try to store the output in an array and making a for...in-loop, to display the "people-animation" for each number in the array. I would be so happy, if would get some help or just a little hint, thank you so much! I'm completely new to this and I'm desperate.
I already have a working animation-script (for one "people").
var seven = 7;
var six;
var five;
var four;
var three;
var two;
while (six != 1 || five != 1|| four != 1|| three != 1|| two != 1)
{six = seven % 6;
five = seven % 5;
four = seven % 4;
three = seven % 3;
two = seven % 2;
console.log(seven);
seven += 7;}

This is a simple way to divide the number sequence in rows.
var seven = [[]];
var six = [[]];
var five = [[]];
var four = [[]];
var three = [[]];
var two = [[]];
cnt = 1;
while (cnt <= 301) {
seven[seven.length - 1].push(cnt);
six[six.length - 1].push(cnt);
five[five.length - 1].push(cnt);
four[four.length - 1].push(cnt);
three[three.length - 1].push(cnt);
two[two.length - 1].push(cnt);
if (!(cnt % 7) && (cnt < 301)) seven.push([]);
if (!(cnt % 6) && (cnt < 301)) six.push([]);
if (!(cnt % 5) && (cnt < 301)) five.push([]);
if (!(cnt % 4) && (cnt < 301)) four.push([]);
if (!(cnt % 3) && (cnt < 301)) three.push([]);
if (!(cnt % 2) && (cnt < 301)) two.push([]);
cnt++;
}
console.log(seven);
console.log(six);
console.log(five);
console.log(four);
console.log(three);
console.log(two);
Here's an improved version:
var rows = {}; // object to keep the rows
var list = [...Array(8).keys()].slice(2); //creates a 2 to 7 range in an array
list.map(e=>rows[e] = [[]]); // initializes the rows object with empty array to store sequences
cnt = 1; //counter
while (cnt <= 301) {
//for each row type (2 to 7)
list.forEach(row=> {
// get last row list and put current number
rows[row][rows[row].length -1].push(cnt);
// if there are already enough elements in that row type
// add another row in this row type
if (!(cnt % row) && (cnt < 301)) rows[row].push([]);
});
cnt++;
}
console.log(rows);
Hope it helps you.

I hope that I understand your question correctly and that my effort is of any use to you. If I think I know what you mean is that you want to add rows divided into columns. For example 7 people divided over 3 columns equals:
...
...
.
or in an array with numbers:
[
3,
3,
1
]
And that the length of each column can be dynamically set, by either you or the user, but adding 7 people (in your case) with each set of rows.
I've build a class with which you can create an object which stores all of your values and can do the calculations needed when adding a row. You would be able to use this in your game and let you are the user decide in how many columns people should be added.
Try it out and let me know if I understood your question correctly as mine and #NelsonTeixeira's answer differ so vastly.
class Crowd {
/**
* Store maxColumnLength and setup the default peopleLimit.
*/
constructor(maxColumnLength, peopleLimit = 301) {
this.maxColumnLength = maxColumnLength;
this.peopleLimit = peopleLimit;
this.totalPeople = 0;
this.rows = [];
}
/**
* Adds a new set of rows to the main rows collection
*
* #param {number} columnLength
* #return {this}
*/
addPeopleInColumnsOf(columnLength) {
if (columnLength <= this.maxColumnLength && this.totalPeople + this.maxColumnLength <= this.peopleLimit) {
// Create rows and calculate columns.
let row = [];
const amountOfFullRows = Math.floor(this.maxColumnLength / columnLength);
const peopleInLastRow = this.maxColumnLength % columnLength;
// Add all the full rows to the array.
for (let i = 0; i < amountOfFullRows; i++) {
row.push(columnLength);
}
// Add the last row to the array.
if (peopleInLastRow !== 0) {
row.push(peopleInLastRow);
}
// Push new rows to main row collection.
// And add the total.
this.rows.push(row);
this.totalPeople += this.maxColumnLength;
}
return this;
}
/**
* Outputs each row in the console.
*/
showRows() {
this.rows.forEach(row => {
console.log(row);
});
}
}
/**
* Create an instance with a maximum column
* length of 7 and start adding people in columns of...
*/
const crowd = new Crowd(7)
.addPeopleInColumnsOf(4)
.addPeopleInColumnsOf(5)
.addPeopleInColumnsOf(6)
.addPeopleInColumnsOf(2)
.addPeopleInColumnsOf(3)
.addPeopleInColumnsOf(4)
.addPeopleInColumnsOf(8) // This one will silently fail.
.addPeopleInColumnsOf(1)
.addPeopleInColumnsOf(6);
// Show the results
crowd.showRows();
console.log(crowd.totalPeople);

Related

I want to implement a loop script in JS

I want to implement a script to create an array consisting of integers from 1 to 20. Chose those elements that can be divided by 3 and multiply by 3rd power. then chose minimal value from three of its maximum elements.
Here is my code..
var total = 0;
var arrVal = [];
for (var counter = 0; counter <= 20; counter++) {
var i = 3;
var a = 0;
if (counter%i===0 && i!==counter) {
arrVal.push(counter * i);
}
}
console.log(arrVal)
for(var i = arrVal.length; i > 0; i--) {
if(i >= 3){
max = arrVal[i];
total = max;
}
}
console.log(total);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I would like to know if it is ok or not?
Thanks in advance..
You could do it in an easier manner if I understand what you want to do:
Array(21).fill(0).map((v, i) => i).filter(v => v !== 3 && v % 3 === 0).map(v => v * 3).slice(-3)[0]
I'll explain each step:
First you create an array of size 20+1
Then you fill it with zeros (because you can iterate over an array of undefined values)
Fill it with the index number of each element (0,1,2,3...,20).
Filter the array to get the elements that can be divided by 3 but aren't 3 (0,6,9,...) and you multiply them by 3 (0,18,27,...)
Slice the three last elements (36, 45, 54)
Take the first element which is the lowest of the three highest elements.

Printing 2d array in javascript

Like the picture above, how would it be possible to create four separate lines of text, given the word defendtheeastwallofthecastle while using Javascript?
Math solution
Take a closer look at your output:
a.....g.....m.....s.
.b...f.h...l.n...r.t
..c.e...i.k...o.q...
...d.....j.....p....
Note that it can be splitted into similiar repeating blocks:
a..... g..... m..... s.
.b...f .h...l .n...r .t
..c.e. ..i.k. ..o.q. ..
...d.. ...j.. ...p.. ..
The length of this blocks is calculable: every row, except for the first one and the last one, has 2 letters. The total length will be: rows * 2 - 2. Let's call it blockLength. By the way, x * 2 - 2 is always even - it is important.
Now, you can see that in every block the letters are "sinking" in the left half, and arising in the second one. So, if you make some observations and analysis, you will understand that for blockLength == 6 you need to output letters at i:
row | i % blockLength
----------------------------
0 | 0
1 | 1, blockLength - 1
2 | 2, blockLength - 2
3 | 3
After i exceeds blockLength, it will repeat again and again, until the end of the string. This regularity can be easily converted to a JavaScript loop, if you know its basics.
Lazy solution
Within a loop set values in zig-zag order:
var str = 'abcdefghijklmopqrst';
var rows = 4, letterRows = [], currentRow = 0, direction = 1;
for (var i = 0; i < str.length; i++)
{
letterRows.push(currentRow);
currentRow += direction;
if ((direction === 1 && currentRow == rows - 1) // bottom limit
|| (direction === -1 && currentRow == 0)) // top limit
{
direction = direction * -1; // invert direction
}
}
Then, within nested loops simply output your letters according to letterRows:
for (var row = 0; row < rows; row++)
{
for (var i = 0; i < str.length; i++)
{
output(letterRows[i] == row ? str[i] : '.'); // output is any possible output in your case
}
output('\n');
}

In javascript, how do I add a random amount to a user's balance while controlling how much gets given total?

I'm trying to make it to where when a user does a certain thing, they get between 2 and 100 units. But for every 1,000 requests I want it to add up to 3,500 units given collectively.
Here's the code I have for adding different amounts randomly to a user:
if (Math.floor(Math.random() * 1000) + 1 === 900) {
//db call adding 100
}
else if (Math.floor(Math.random() * 100) + 1 === 90) {
//db call adding 40
}
else if (Math.floor(Math.random() * 30) + 1 === 20) {
//db call adding 10
}
else if (Math.floor(Math.random() * 5) + 1 === 4) {
//db call adding 5
}
else {
//db call adding 2
}
If my math is correct, this should average around 4,332 units per 1,000 calls. But obviously it would vary and I don't want that. I'd also like it to add random amounts instead, as the units added in my example are arbitrary.
EDIT: Guys, Gildor is right that I simply want to have 3,500 units, and give them away within 1,000 requests. It isn't even entirely necessary that it always reaches that maximum of 3,500 either (I could have specified that). The important thing is that I'm not giving users too much, while creating a chance for them to win a bigger amount.
Here's what I have set up now, and it's working well, and will work even better with some tweaking:
Outside of call:
var remaining = 150;
var count = 0;
Inside of call:
count += 1;
if (count === 100) {
remaining = 150;
count = 0;
}
if (Math.floor(Math.random() * 30) + 1 === 20) {
var addAmount = Math.floor(Math.random() * 85) + 15;
if (addAmount <= remaining) {
remaining -= addAmount;
//db call adding addAmount + 2
}
else {
//db call adding 2
}
}
else if (Math.floor(Math.random() * 5) + 1 === 4) {
var addAmount1 = Math.floor(Math.random() * 10) + 1;
if (addAmount1 <= remaining) {
remaining -= addAmount1;
//db call adding addAmount1 + 2
}
else {
//db call adding 2
}
}
else {
//db call adding 2
}
I guess I should have clarified, I want a "random" number with a high likelihood of being small. That's kind of part of the gimmick, where you have low probability of getting a larger amount.
As I've commented, 1,000 random numbers between 2 and 100 that add up to 3,500 is an average number of 3.5 which is not consistent with random choices between 2 and 100. You'd have to have nearly all 2 and 3 values in order to achieve that and, in fact couldn't have more than a couple large numbers. Nothing even close to random. So, for this to even be remotely random and feasible, you'd have to pick a total much large than 3,500. A random total of 1,000 numbers between 2 and 100 would be more like 51,000.
Furthermore, you can't dynamically generate each number in a truly random fashion and guarantee a particular total. The main way to guarantee that outcome is to pre-allocate random numbers that add up to the total that are known to achieve that and then random select each number from the pre-allocated scheme, then remove that from the choice for future selections.
You could also try to keep a running total and bias your randomness if you get skewed away form your total, but doing it that way, the last set of numbers may have to be not even close to random in order to hit your total consistently.
A scheme that could work if you reset the total to support what it should be for actual randomness (e.g. to 51,000) would be to preallocated an array of 500 random numbers between 2 and 100 and then add another 500 numbers that are the complements of those. This guarantees the 51 avg number. You can then select each number randomly from the pre-allocated array and then remove it form the array so it won't be selected again. I can add code to do this in a second.
function RandResults(low, high, qty) {
var results = new Array(qty);
var limit = qty/2;
var avg = (low + high) / 2;
for (var i = 0; i < limit; i++) {
results[i] = Math.floor((Math.random() * (high - low)) + low);
//
results[qty - i - 1] = (2 * avg) - results[i];
}
this.results = results;
}
RandResults.prototype.getRand = function() {
if (!this.results.length) {
throw new Error("getRand() called, but results are empty");
}
var randIndex = Math.floor(Math.random() * this.results.length);
var value = this.results[randIndex];
this.results.splice(randIndex, 1);
return value;
}
RandResults.prototype.getRemaining = function() {
return this.results.length;
}
var randObj = new RandResults(2, 100, 1000);
// get next single random value
if (randObj.getRemaining()) {
var randomValue = randObj.getRand();
}
Working demo for a truly random selection of numbers that add up to 51,000 (which is what 1,000 random values between 2 and 100 should add up to): http://jsfiddle.net/jfriend00/wga26n7p/
If what you want is the following: 1,000 numbers that add up to 3,500 and are selected from between the range 2 to 100 (inclusive) where most numbers will be 2 or 3, but occasionally something could be up to 100, then that's a different problem. I wouldn't really use the word random to describe it because it's a highly biased selection.
Here's a way to do that. It generates 1,000 random numbers between 2 and 100, keeping track of the total. Then, afterwards it corrects the random numbers to hit the right total by randomly selected values and decrementing them until the total is down to 3,500. You can see it work here: http://jsfiddle.net/jfriend00/m4ouonj4/
The main part of the code is this:
function RandResults(low, high, qty, total) {
var results = new Array(qty);
var runningTotal = 0, correction, index, trial;
for (var i = 0; i < qty; i++) {
runningTotal += results[i] = Math.floor((Math.random() * (high - low)) + low);
}
// now, correct to hit the total
if (runningTotal > total) {
correction = -1;
} else if (runningTotal < total) {
correction = 1;
}
// loop until we've hit the total
// randomly select a value to apply the correction to
while (runningTotal !== total) {
index = Math.floor(Math.random() * qty);
trial = results[index] + correction;
if (trial >= low && trial <= high) {
results[index] = trial;
runningTotal += correction;
}
}
this.results = results;
}
This meets an objective of a biased total of 3,500 and all numbers between 2 and 100, though the probability of a 2 in this scheme is very high and the probably of a 100 in this scheme is almost non-existent.
And, here's a weighted random generator that adds up to a precise total. This uses a cubic weighting scheme to favor the lower numbers (the probably of a number goes down with the cube of the number) and then after the random numbers are generated, a correction algorithm applies random corrections to the numbers to make the total come out exactly as specified. The code for a working demo is here: http://jsfiddle.net/jfriend00/g6mds8rr/
function RandResults(low, high, numPicks, total) {
var avg = total / numPicks;
var i, j;
// calculate probabilities for each value
// by trial and error, we found that a cubic weighting
// gives an approximately correct sub-total that can then
// be corrected to the exact total
var numBuckets = high - low + 1;
var item;
var probabilities = [];
for (i = 0; i < numBuckets; i++) {
item = low + i;
probabilities[i] = avg / (item * item * item);
}
// now using those probabilities, create a steps array
var sum = 0;
var steps = probabilities.map(function(item) {
sum += item;
return sum;
});
// now generate a random number and find what
// index it belongs to in the steps array
// and use that as our pick
var runningTotal = 0, rand;
var picks = [], pick, stepsLen = steps.length;
for (i = 0; i < numPicks; i++) {
rand = Math.random() * sum;
for (j = 0; j < stepsLen; j++) {
if (steps[j] >= rand) {
pick = j + low;
picks.push(pick);
runningTotal += pick;
break;
}
}
}
var correction;
// now run our correction algorithm to hit the total exactly
if (runningTotal > total) {
correction = -1;
} else if (runningTotal < total) {
correction = 1;
}
// loop until we've hit the total
// randomly select a value to apply the correction to
while (runningTotal !== total) {
index = Math.floor(Math.random() * numPicks);
trial = picks[index] + correction;
if (trial >= low && trial <= high) {
picks[index] = trial;
runningTotal += correction;
}
}
this.results = picks;
}
RandResults.prototype.getRand = function() {
if (!this.results.length) {
throw new Error("getRand() called, but results are empty");
}
return this.results.pop();
}
RandResults.prototype.getAllRand = function() {
if (!this.results.length) {
throw new Error("getAllRand() called, but results are empty");
}
var r = this.results;
this.results = [];
return r;
}
RandResults.prototype.getRemaining = function() {
return this.results.length;
}
As some comments pointed out... the numbers in the question does not quite make sense, but conceptually there are two approaches: calculate dynamically just in time or ahead of time.
To calculate just in time:
You can maintain a remaining variable which tracks how many of 3500 left. Each time when you randomly give some units, subtract the number from remaining until it goes to 0.
In addition, to make sure each time at least 2 units are given, you can start with remaining = 1500 and give random + 2 units each time.
To prevent cases that after 1000 gives there are still balances left, you may need to add some logic to give units more aggressively towards the last few times. However it will result in not-so-random results.
To calculate ahead of time:
Generate a random list with 1000 values in [2, 100] and sums up to 3500. Then shuffle the list. Each time you want to give some units, pick the next item in the array. After 1000 gives, generate another list in the same way. This way you get much better randomized results.
Be aware that both approaches requires some kind of shared state that needs to be handled carefully in a multi-threaded environment.
Hope the ideas help.

Javascript challenge - which basket contains the last apple?

I'm presented with the following challenge question:
There are a circle of 100 baskets in a room; the baskets are numbered
in sequence from 1 to 100 and each basket contains one apple.
Eventually, the apple in basket 1 will be removed but the apple in
basket 2 will be skipped. Then the apple in basket 3 will be removed.
This will continue (moving around the circle, removing an apple from a
basket, skipping the next) until only one apple in a basket remains.
Write some code to determine in which basket the remaining apple is
in.
I concluded that basket 100 will contain the last apple and here's my code:
var allApples = [];
var apples = [];
var j = 0;
var max = 100;
var o ='';
while (j < max) {
o += ++j;
allApples.push(j);
}
var apples = allApples.filter(function(val) {
return 0 == val % 2;
});
while (apples.length > 1) {
for (i = 0; i < apples.length; i += 2) {
apples.splice(i, 1);
}
}
console.log(apples);
My question is: did I do this correctly? What concerns me is the description of "a circle" of baskets. I'm not sure this is relevant at all to how I code my solution. And would the basket in which the remaining apple reside be one that would otherwise be skipped?
I hope someone can let me know if I answered this correctly, answered it partially correct or my answer is entirely wrong. Thanks for the help.
So, ... I got WAY too into this question :)
I broke out the input/output of my last answer and that revealed a pretty simple pattern.
Basically, if the total number of items is a power of 2, then it will be the last item. An additional item after that will make the second item the last item. Each additional item after that will increase the last item by 2, until you reach another item count that is again divisible by a power of 2. Rinse and repeat.
Still not a one-liner, but will be much faster than my previous answer. This will not work for 1 item.
var items = 100;
function greatestPowDivisor(n, p) {
var i = 1;
while(n - Math.pow(p, i) > 0) {
i++;
}
return Math.pow(p, (i - 1));
}
var d = greatestPowDivisor(items, 2)
var last_item = (items - d) * 2;
I believe Colin DeClue is right that there is a single statement that will solve this pattern. I would be really interested to know that answer.
Here is my brute force solution. Instead of moving items ("apples") from their original container ("basket") into a discard pile, I am simply changing the container values from true or false to indicate that an item is no longer present.
var items = 100;
var containers = [];
// Just building the array of containers
for(i=0; i<items; i++) {
containers.push(true);
}
// count all containers with value of true
function countItemsLeft(containers) {
total = 0;
for(i=0; i<containers.length; i++) {
if(containers[i]) {
total++;
}
}
return total;
}
// what is the index of the first container
// with a value of true - hopefully there's only one
function getLastItem(containers) {
for(i=0; i<containers.length; i++) {
if(containers[i]) {
return(i);
}
}
// shouldn't get here if the while loop did it's job
return false;
}
var skip = false;
// loop through the items,
// setting every other to false,
// until there is only 1 left
while(countItemsLeft(containers) > 1) {
for(i=0; i<containers.length; i++) {
if(containers[i]) {
if(skip) {
skip = false;
} else {
containers[i] = false;
skip = true;
}
}
}
}
// what's the last item? add one to account for 0 index
// to get a human readable answer
var last_item = getLastItem(containers) + 1;
Needs error checking, etc... but it should get the job done assuming items is an integer.

javascript - generate a new random number

I have a variable that has a number between 1-3.
I need to randomly generate a new number between 1-3 but it must not be the same as the last one.
It happens in a loop hundreds of times.
What is the most efficient way of doing this?
May the powers of modular arithmetic help you!!
This function does what you want using the modulo operator:
/**
* generate(1) will produce 2 or 3 with probablity .5
* generate(2) will produce 1 or 3 with probablity .5
* ... you get the idea.
*/
function generate(nb) {
rnd = Math.round(Math.random())
return 1 + (nb + rnd) % 3
}
if you want to avoid a function call, you can inline the code.
Here is a jsFiddle that solves your problem : http://jsfiddle.net/AsMWG/
I've created an array containing 1,2,3 and first I select any number and swap it with the last element. Then I only pick elements from position 0 and 1, and swap them with last element.
var x = 1; // or 2 or 3
// this generates a new x out of [1,2,3] which is != x
x = (Math.floor(2*Math.random())+x) % 3 + 1;
You can randomly generate numbers with the random number generator built in to javascript. You need to use Math.random().
If you're push()-ing into an array, you can always check if the previously inserted one is the same number, thus you regenerate the number. Here is an example:
var randomArr = [];
var count = 100;
var max = 3;
var min = 1;
while (randomArr.length < count) {
var r = Math.floor(Math.random() * (max - min) + min);
if (randomArr.length == 0) {
// start condition
randomArr.push(r);
} else if (randomArr[randomArr.length-1] !== r) {
// if the previous value is not the same
// then push that value into the array
randomArr.push(r);
}
}
As Widor commented generating such a number is equivalent to generating a number with probability 0.5. So you can try something like this (not tested):
var x; /* your starting number: 1,2 or 3 */
var y = Math.round(Math.random()); /* generates 0 or 1 */
var i = 0;
var res = i+1;
while (i < y) {
res = i+1;
i++;
if (i+1 == x) i++;
}
The code is tested and it does for what you are after.
var RandomNumber = {
lastSelected: 0,
generate: function() {
var random = Math.floor(Math.random()*3)+1;
if(random == this.lastSelected) {
generateNumber();
}
else {
this.lastSelected = random;
return random;
}
}
}
RandomNumber.generate();

Categories

Resources