Randomly storing elements from an array into a table - javascript

I'm trying to create a simple memory matching game and I'm having trouble assigning one number to each table cell from my cardValues array. My giveCellValue function is supposed to generate a random number then pick that number from the array and give it to one of the table cells but I'm a little over my head on this one and having trouble accomplishing this task.
var countCells;
var cardValues = [];
var checker = true;
var createTable = function (col, row) {
$('table').empty();
for (i = 1; i <= col; i++) {
$('table').append($('<tr>'));
}
for (j = 1; j <= row; j++) {
$('tr').append($('<td>'));
}
countCells = row * col;
};
createTable(3, 6);
for (i = 1; i <= countCells / 2; i++) {
cardValues.push(i);
if (i === countCells / 2 && checker) {
checker = false;
i = 0;
}
}
var giveCellValue = function () {
var random = Math.ceil(Math.random() * cardValues.length) - 1;
for (i = 0; i <= cardValues.length; i++) {
$('td').append(cardValues[random]);
cardValues.splice(random, 1);
}
};
giveCellValue();
console.log(cardValues);

Use
var countCells;
var cardValues = [];
var checker = true;
var createTable = function (col, row) {
$('table').empty();
for (var i = 0; i < col; i++) {
$('table').append($('<tr>'));
}
for (var j = 0; j < row; j++) {
$('tr').append($('<td>'));
}
countCells = row * col;
};
createTable(3, 6);
for (i = 0; i < countCells; i++) {
cardValues.push(i % 9 + 1);
}
var giveCellValue = function () {
var len = cardValues.length, tds = $('td');
for (var i = 0; i < len; i++) {
var random = Math.floor(Math.random() * cardValues.length);
tds.eq(i).append(cardValues.splice(random, 1));
}
};
giveCellValue();
console.log(cardValues);
Demo: Fiddle

Leaving aside the problems that have already been mentioned in the comments above...
If I understand it right, you want to assign each of the numbers in cardValues to a random table cell?
Seems like the problem is with this line:
var random = Math.ceil(Math.random() * cardValues.length) - 1;
What this does is generates a random number once. If you access the variable random at a later time, you're not calling the full line of code again, you're just getting the same value that was calculated the first time. E.g. if the above code runs, spits out '7' as its random number and stores that in random, then every time you go through the for loop, the value of random will always be '7' rather than being re-generated every time - make sense?
Try putting the randomiser inside the for loop - that way it will be run multiple times, generating a new random number every time:
var giveCellValue = function () {
var random;
for (i = 0; i <= cardValues.length; i++) {
random = Math.ceil(Math.random() * cardValues.length) - 1;
$('td').append(cardValues[random]);
cardValues.splice(random, 1);
}
};
Actually, I'd change line 4 above to random = Math.floor(Math.random() * cardValues.length); too which should have the same effect.

Related

How to step through google script

I am trying to write a Google Sheets script macro. How do I step through it to understand why the time is being exceeded?
My problem is the loop, when I set the iteration max(scenarios) to 46, the code seems to run fine, taking about 1-2 seconds. When the max is set to 47, it dies with max execution time exceeded (4-5 minutes). Whats going on?
function testing() {
var aa = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Run
Program");
var scenarios = aa.getRange("H19").getValue();
for (i = 1; i <= scenarios; i++){
var ss =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet6");
var range = ss.getRange("b6:u6");
var min = 1 ;
var max = 20 ;
var numbers = []
for (var i = min; i <= max; i++) {
numbers.push(i);
}
shuffleArray(numbers)
var counter = 0;
for (var x = 1; x <= range.getWidth(); x++) {
for (var y = 1; y <= range.getHeight(); y++) {
range.getCell(y, x).setValue(numbers[counter]);
counter++;
}
}
var range = ss.getRange("v6:ao6");
var min = 21 ;
var max = 40 ;
var numbers = []
for (var i = min; i <= max; i++) {
numbers.push(i);
}
shuffleArray(numbers)
var counter = 0;
for (var x = 1; x <= range.getWidth(); x++) {
for (var y = 1; y <= range.getHeight(); y++) {
range.getCell(y, x).setValue(numbers[counter]);
counter++;
}
}
var range = ss.getRange("ap6:at6");
var min = 41 ;
var max = 45 ;
var numbers = []
for (var i = min; i <= max; i++) {
numbers.push(i);
}
shuffleArray(numbers)
var counter = 0;
for (var x = 1; x <= range.getWidth(); x++) {
for (var y = 1; y <= range.getHeight(); y++) {
range.getCell(y, x).setValue(numbers[counter]);
counter++;
}
}
}
// function Chart4() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A1').activate();
spreadsheet.getSheetByName('Chart4').showSheet()
.activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Chart4'),
true);
};
Your code needs a lot of help. Here's a tip to get you started.
As others have mentioned, you should call .getValues() on the whole range, which gives you a 2 dimensional array of cell values [[A1value,B1value,...],[A2val,B2val...],...]. You should grab the width and length first and assign to a variable. Reference that variable instead of calling the API in the loop conditions. In fact, since you know the ranges ahead of time, you should define all the ranges you'll be needing outside of the main for loop, as well as the spreadsheet (ss):
var aa = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Run Program");
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet6");
var range1 = ss.getRange("b6:u6");
var range2 = ss.getRange("v6:ao6");
for (i = 1; i <= scenarios; i++) { ...
Scripts start taking a long time if you make repeated calls to the API.
Not sure exactly what your macro is trying to do, but here is a template for running this kind of loop and how you should think about it.
var range = ss.getRange(A1-style-address);
var values = range1.getValues();
var width = range1[0].length;
var height = range1.length;
var new_values = new Array();
for (var i = 0; i < height; i++) {
for (var j = 0; j < width; j++) {
//do something with values[i][j], like push to new_values
}
}
//something like:
//var new_range = ss.getRange(different A1-style address)
//new_range.setValues(new_array)
You'll have to make sure that the new array contains values in a 2 dimensional array that has the same dimensions as the range you're putting them into or it will throw an error.
I'll leave it to you to figure out how to modify the new_values array inside the loop to make sure it is the right size.
Here's a link to an overview of arrays in javascript if this is new for you, and here's some array documentation.
Range.getCell() call can be expensive sometimes and should be avoided. Use Range.getValues() and iterate over the two dimensional array. Also, instead of using active spreadsheet open spreadsheet by Id for unit testing. This way you will be able to debug/run from GAS editor directly. GAS editor usually catches such performance issues in the code and displays warnings pointing to the line number in the code.

Counting duplicate random numbers from a for loop

I am trying to create a score predictor based on a teams goal difference (football). I am new to JavaScript, and I have managed to get this far.
I want it to be like spinning a ten-sided dice 20 times + the team's goal difference. I have got this bit sorted I think. With my code now I have a list of random numbers logged in the console which is what I wanted. Now I would like to choose a number (e.g., 2) and see how many times this occurs in the list. I'd like to save this in a new variable called homeFinalScore (So if '2' occurs three times in the list of random numbers, the homeFinalScore variable should be 3). I've tried several things but have been unable to sort it yet!
Any help would be extremely helpful. Thank you in advance!
var homeFinalScore = 0;
function calculateScore(){
var homeTeam = document.getElementById("HomeTeam").value;
var awayTeam = document.getElementById("AwayTeam").value;
var homeGd = parseInt(document.getElementById("HomeGD").value);
var awayGd = parseInt(document.getElementById("AwayGD").value);
var homeGd = 20 + homeGd;
var awayGd = 15 + awayGd;
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
console.log(randNum);
}
}
You can create an array, use Array.prototype.push() to push randNum to the array, then use Array.prototype.filter(), .length to determine how many occurrences of a value are present within array.
var homeGd = 20 + 2;
var awayGd = 15 + 2;
var arr = [];
function countOccurrences(n, arr) {
return arr.filter(function(value) {
return value === n
}).length;
}
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
arr.push(randNum);
}
console.log(arr);
console.log(countOccurrences(2, arr));
Alternatively, you can increment a variable when randNum is equal to a value.
var homeGd = 20 + 2;
var awayGd = 15 + 2;
var n = 0;
var num = 2;
for (i = 0; i < homeGd; i++) {
var randNum = Math.floor(Math.random() * 11);
console.log(randNum);
if (randNum === num) {
++n
}
}
console.log("occurrences of 2:", n);
const homeGd = 10;
const randomNumbers = []; // array of random numbers
for (i = 0; i < homeGd; i++) {
randomNumbers.push(Math.floor(Math.random() * 11));
}
const countBy = randomNumbers.reduce((acc, current) => {
acc[current] = (acc[current] || 0) + 1;
return acc;
}, {});
console.log(countBy);

How to create 100 random numbers between 1 and 9999 with 4 digits, and place numbers in 10 rows of 10 numbers?

Having an issue figuring out how to get this solved, and I've searched and looked for answers, but they don't resemble what I'm looking for.
This is beginner stuff, I realize but any help would be highly appreciated.
The code below was given by my teacher and it works for creating one random number. For the life of me I can't figure out how to make this create 100 random numbers and make a 10 x 10 square of them.
eg. 5468 2367 1587 2587 2310 9802 0154 8753 4965 2571
3249 3248 2158 4659 1321 1278 9871 0123 4654 4587
etc. for 10 rows.
<div id="answer"></div>
<script type="text/javascript">
function giveValues() {
var length, zeroes;
var number = Math.round((Math.random() * 9999));
// toString()-method and lenght to set amount of digts
zeroes = 4 - number.toString().length;
for (var j = 1; j <= zeroes; j++) {
number = "0" + number;
}
return number;
}
document.getElementById("answer").innerHTML = giveValues();
I also know that there is if (j % nameofvar == 0) { for making a new line, but am unable to make that work.
Considering that you haven't learned arrays yet, try the following as I think it's best inline with what you're looking for. Here is a Plunker as well http://plnkr.co/edit/LltYPtSfR9Ndo46kYmVN?p=preview.
<div id="answer"></div>
<script>
function giveValues() {
var length, zeroes;
var number = Math.round((Math.random() * 9999));
// toString()-method and lenght to set amount of digts
zeroes = 4 - number.toString().length;
for (var j = 1; j <= zeroes; j++) {
number = "0" + number;
}
return number;
}
var columns = 10;
var total = 100;
var bigString = "";
for (var i=0; i<total; i++) {
if (i != 0 && i % columns == 0) {
bigString += "<br/>";
}
bigString += giveValues(i).toString() + " ";
}
var answer = document.getElementById("answer");
answer.innerHTML = bigString;
</script>
Most basic way:
function lpad(number) {
while (number.toString().length < 4) {
number = "0"+number;
}
return number;
}
var max = 9999;
var matrix = [];
var size = 10;
for (var i = 0; i < size * size; i++) {
if (i % size === 0) {
matrix.push([]);
}
var number = lpad(Math.ceil(Math.random() * max));
matrix[matrix.length - 1].push(number);
}
document.getElementById("answer").innerHTML = matrix.join("<br />");
<div id = "answer"></div>
Using arrays is more effective, but you can also simply concatenate too.
You could just generate a large random number, and then limit it to 4 digits.
Try this:
function giveValues() {
var number = Math.round((Math.random() * 999999999));
return number.toString().substr(0, 4);
}
var arr = [];
for(var i = 0; i < 10; i++){
arr.push([giveValues(), giveValues(), giveValues(), giveValues(), giveValues(), giveValues(), giveValues(), giveValues(), giveValues(), giveValues()]);
}
document.getElementById("answer").innerHTML = arr.join(' <br/>').replace(/,/g,' ');
https://jsfiddle.net/moshekarmel1/34spm4hh/

Strange performance quirk in javascript

I experience a strange differences in performance of simple task depending of array I am working with. The task is to calculate sum of those elements in array which are greater than 5. Task is performed on arrays with equal lenghts.
I try the very same approach on three different array objects:
1) var hugeArray1 - array with all elemenets randomly picked from 0:10 range
2) var hugeArray2 - copy of hugeArray1 sorted with Array.prototype.sort()
3) var hugeArray3 - handcrafted but sorted array with values from 0:10 range, spread to equaly cover this interval.
I try to calculate sum of elements greater than 5 many times for each Array and then average them. What is strange, time needed varies a lot for those three arrays.
1) hugeArray1: 5.805ms
2) hugeArray2: 15.738ms
3) hugeArray3: 3.753ms
Result for array sorted with sort() is extreamly poor. Why is that? it looks like sort() returns some kind of wraper/proxy instead of 'native' Array, which affects performance. I tried it on 2 computers. Also i tried to change order of testing.
I include code below, please tell me what is happening here.
// random array with elements 0-10 of size n
function randomArray(n) {
var arr = [];
for (var i = 0; i < n; ++i) {
arr.push(Math.random() * 10);
}
return arr;
};
// measures time of execution
function measureTime(f) {
var start = new Date().getTime();
f();
var stop = new Date().getTime();
return stop - start;
};
// enumerate ofer array and calculate sum of elementsgreater than 5
function sumGreaterThan5(arr) {
var sum = 0;
for (var i = 0; i < arr.length; ++i) {
if (arr[i] > 5.0)
sum += arr[i];
}
return sum;
}
// generate array os size 'size' with elements with constant step to fill interval 0:10
function generateSortedArr(size) {
var arr = [];
for (var i = 0; i < size; ++i) {
arr.push(i * 10 / size);
}
return arr;
}
var huge = 1000000;
var hugeArray1 = randomArray(huge);
var hugeArray2 = hugeArray1.slice(0).sort();
var hugeArray3 = generateSortedArr(huge);
var hugeArrays = [hugeArray1, hugeArray2, hugeArray3];
hugeArrays.forEach(x=> {
var res = [];
for (var i = 0; i < 1000; ++i) {
res.push(measureTime(function () {
sumGreaterThan5(x);
}));
}
console.log(res.reduce((prev, curr)=> prev + curr) / res.length);
});
// random array with elements 0-10 of size n
function randomArray(n) {
var arr = [];
for (var i = 0; i < n; ++i) {
arr.push(Math.random() * 10);
}
return arr;
};
// measures time of execution
function measureTime(f) {
var start = new Date().getTime();
f();
var stop = new Date().getTime();
return stop - start;
};
// enumerate ofer array and calculate sum of elementsgreater than 5
function sumGreaterThan5(arr) {
var sum = 0;
for (var i = 0; i < arr.length; ++i) {
if (arr[i] > 5.0)
sum += arr[i];
}
return sum;
}
// generate array os size 'size' with elements with constant step to fill interval 0:10
function generateSortedArr(size) {
var arr = [];
for (var i = 0; i < size; ++i) {
arr.push(i * 10 / size);
}
return arr;
}
var huge = 1000000;
var hugeArray1 = randomArray(huge);
var hugeArray2 = hugeArray1.slice(0).sort();
var hugeArray3 = generateSortedArr(huge);
var hugeArrays = [hugeArray1, hugeArray2, hugeArray3];
hugeArrays.forEach(function(x){
var res = [];
for (var i = 0; i < 1000; ++i) {
res.push(measureTime(function () {
sumGreaterThan5(x);
}));
}
console.log(res.reduce(function(prev, curr){return prev + curr},0) / res.length);
});

Speeding up simple math operations on numeric 2D array (matrix) in JavaScript

I have a numeric 2D array (an array of arrays, or a matrix) and I need to do simple matrix operations like adding a value to each row, or multiplying every value by a single number. I have little experience with math operations in JavaScript, so this may be a bone-headed code snippet. It is also very slow, and I need to use it when the number of columns is 10,000 - 30,000. By very slow I mean roughly 500 ms to process a row of 2,000 values. Bummer.
var ran2Darray = function(row, col){
var res = [];
for (var i = 0 ; i < row; i++) {
res[i] = [];
for (var j = 0; j < col; j++) {
res[i][j] = Math.random();
}
}
return res;
}
var myArray = ran2Darray(5, 100);
var offset = 2;
for (i = 0; i < myArray.length; i++) {
aRow = myArray[i];
st = Date.now();
aRow.map(function addNumber(offset) {myArray[i] + offset*i; })
end = Date.now();
document.write(end - st);
document.write("</br>");
myArray[i] = aRow;
}
I want to avoid any added libraries or frameworks, unless of course, that is my only option. Can this code be made faster, or is there another direction I can go, like passing the calculation to another language? I'm just not familiar with how people deal with this sort of problem. forEach performs roughly the same, by the way.
You don't have to rewrite array items several times. .map() returns a new array, so just assign it to the current index:
var myArray = ran2Darray(5, 100000);
var offset = 2;
var performOperation = function(value, idx) {
return value += offset * idx;
}
for (i = 0; i < myArray.length; i++) {
console.time(i);
myArray[i] = myArray[i].map(performOperation)
console.timeEnd(i);
}
It takes like ~20ms to process.
Fiddle demo (open console)
Ok, Just a little modification and a bug fix in what you have presented here.
function addNumber(offset) {myArray[i] + offset*i; }) is not good.
myArray[i] is the first dimention of a 2D array why to add something to it?
function ran2Darray (row, col) {
var res = [];
for (var i = 0 ; i < row; i++) {
res[i] = [];
for (var j = 0; j < col; j++) {
res[i][j] = Math.random();
}
}
return res;
}
var oneMillion = 1000000;
var myArray = ran2Darray(10, oneMillion);
var offset = 2;
var startTime, endTime;
for (i = 0; i < myArray.length; i++) {
startTime = Date.now();
myArray[i] = myArray[i].map(function (offset) {
return (offset + i) * offset;
});
endTime = Date.now();
document.write(endTime - startTime);
document.write("</br>");
}
try it. It's really fast
https://jsfiddle.net/itaymer/8ttvzyx7/

Categories