Array functions 'push' and 'splice' Javascript - javascript

1 of spades,1 of diamonds,1 of clubs,1 of hearts,2 of spades,2 of diamonds,2 of clubs,2 of hearts,3 of spades,3 of diamonds,3 of clubs,3 of hearts,4 of spades,4 of diamonds,4 of clubs,4 of hearts,5 of spades,5 of diamonds,5 of clubs,5 of hearts,6 of spades,6 of diamonds,6 of clubs,6 of hearts,7 of spades,7 of diamonds,7 of clubs,7 of hearts,8 of spades,8 of diamonds,8 of clubs,8 of hearts,9 of spades,9 of diamonds,9 of clubs,9 of hearts,10 of spades,10 of diamonds,10 of clubs,10 of hearts
,,,
[This is what the program returns]
I'm trying to make a program in JavaScript that allows someone to play poker. I am using the ProcessingJS terminal in Khan Academy. Below is my full program so far. What it's supposed to do is make an array called deck which includes the names of all the cards (not including the face cards) in a deck of cards. That part of the program works. The next part attempts to make a new array called current that is an exact copy of deck. It then tries to print out current, and it does so successfully.
The last for loop is what is causing the problem. It tries to take a random card from current and copy it to another array called player which is supposed to be the player's hand. It then tries to remove that card from the array current.
However, when it tries to print out the array player, all it prints is three commas. I have no idea what the issue is and I have looked at many websites that talk about push and splice. I really have no idea what is wrong.
Again, I want the program to display the player's hand. Thank you for your help.
var deck = [];
var current = [];
var enemy = [];
var player = [];
var suits = ['spades', 'diamonds', 'clubs', 'hearts'];
for (var i = 1; i < 11; i++) {
for (var x = 0; x < 4; x++) {
if (i <= 10) {
deck.push(i + ' of ' + suits[x]);
}
}
}
for (var c = 0; c < 40; c++) {
current[c] = deck[c];
}
println(current);
var y;
for (var a = 0; a < 4; a++) {
y = random(0, (current.length - 1));
player.push(current[y]);
current.splice(y);
}
println(player);

Why not just simplify this without using splice?
From what I understand, you're drawing the card using random. So, just push that card to the players hand with player.push(current[y]).
Also, when you call current.splice(y), I don't think you're deleting just the card that was drawn. That deletes every card in the deck after the index y. Change this to current.splice(y, 1).

Related

PIXI Logic is Skewed from the Actual Visuals

I am pretty new to JavaScript and PIXI. I am making a little game that requires the player to navigate and grab a key (move onto the same space as the key). This takes them to the next level. My problem is that whenever a new level is generated, it somehow uses the x and y coordinates for the key of the previous level to skew the logic. Because of this, the first level works fine, but every level afterwards is messed up.
The levels get skewed up and to the left by the respective values of the previous key. I have a 2d array in the background which holds values of where and where not the player can (holds values for things like walls, turrets, and the key). I randomly generate the key coordinates and for example set grid[9][12] = 3; for the key space. The next level visually looks perfect, with the walls and key generating, and the player being in the top left. However because of the skew, the top left of the visuals is really at [max_X - 9][max_Y - 12] and the player can go off screen to invisibly access the rest of the maze. So I can then phase through walls because the logic has the walls in a different place than the visuals, and the actual key space usually ends up off screen.
Here is my code that generates a new goal (key) object
function createGoal(scene) {
while (true) {
let x = getRandomInt(APP_WIDTH);
let y = getRandomInt(APP_HEIGHT);
//if space is not already occupied, populate
if (grid[x][y] == 0) {
console.log(x);
console.log(y);
goal = null;
goal = new Goal(TILE_WIDTH, x, y);
scene.addChild(goal);
grid[x][y] = 3;
break;
}
}
}
And here is the grid initialization:
const grid = new Array(APP_WIDTH);
for (let i = 0; i < APP_WIDTH; i++) {
grid[i] = new Array(APP_HEIGHT);
for (let j = 0; j < APP_HEIGHT; j++) {
grid[i][j] = 0;
}
}
Any help would be greatly appreciated.

Why do both of these variables change when only one is supposed to?

The following is a subroutine that I excised from my main program. It executes as a stand-alone script, but does not behave in the intended manner any better than it did in the main program:
//Generate permanent array of all possible directional marker pairs,
//excluding 0,0. Also generate array length the "hard" way
var potential_direction_pairs = [];
var length_of_potential_direction_pairs_array = 0;
for (var x_count = -1; x_count < 2; x_count++) {
for (var y_count= -1; y_count < 2; y_count++) {
if (x_count == 0 && y_count == 0) {}
else {
potential_direction_pairs.splice(0, 0, [x_count, y_count]);
length_of_potential_direction_pairs_array += 1
}
}
}
//Create temporary and mutable copy of permanent directional marker array.
var direction_pairs_being_tried = potential_direction_pairs;
//Iterate over all elements in temporary marker array. Use permanent array
//length, as temporary array length will change with each loop.
for (var count = 0, current_direction_pair_being_tried; count < length_of_potential_direction_pairs_array; count++) {
//Count out current length of (shrinking) temporary array.
for (var pair_index = 0; direction_pairs_being_tried[pair_index] != undefined; pair_index++) {}
//Choose a random marker pair from temporary array...
var random_index = Math.floor(Math.random() * pair_index);
//...and store it temporarily in a single-pair array.
current_direction_pair_being_tried = direction_pairs_being_tried[random_index];
//Remove the randomly chosen marker pair from larger temporary array.
direction_pairs_being_tried.splice(random_index, 1);
//Insert temporary "tracer" to display current state of intended
//"permanent" array.
console.log("Potential direction pairs: " + potential_direction_pairs);
//Insert another "tracer" to display current state of intended
//temporary array.
console.log("Direction pairs being tried: " + direction_pairs_being_tried);
//"Tracer" showing current state of temporary single-pair array.
console.log("Current direction pair being tried: " + current_direction_pair_being_tried);
}
Only one of the two "2D" arrays is meant to change, but as you can see from the following screenshot of terminal window output, both do: output of simple subroutine. My knowledge of scope/closure/etc is still pretty shaky, but my suspicions lie that direction. Any help would be appreciated (including a brief explanation), but I'm especially keen on the simplest possible correction to make this work.
Thanks in advance,
Rob
var direction_pairs_being_tried = potential_direction_pairs; is not a copy of an array, it's pointing to the same array. You can copy an array with
var direction_pairs_being_tried = potential_direction_pairs.slice()

Google apps script - Broken for loop

I'm working in Google apps script and seem to have screwed up one of my for loops. I'm sure that I am missing something trivial here, but I can't seem to spot it.
Code Snippet:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var lastRow = sheets[3].getLastRow();
var zw = sheets[3].getRange(2, 1, lastRow - 1, 26).getValues();
for (var j = 0; j < zw.length; ++j) {
if (zw[j][9] === 'Yes') {
var masterEmail = [];
var firstLetterLastName = [];
var first2Letter = [];
var masterEmail.push(zw[j][22]);
var firstLetterLastName.push(zw[j][1].charAt(0).toLowerCase());
var first2Letter.push(zw[j][1].charAt(0).toLowerCase() + zw[j][1].charAt(1).toLowerCase());
//The rest of the function follows...
}
}
What's Not Working:
The for loop doesn't increment. When running the code in a debugger, var j stays at a value of 0.0, and the rest of the function only runs based of off the values in the 0 position of zw.
What I need it to do (AKA - How I thought I had written it:)
The ZW variable is holding a 2 dimensional array of cell values from a Google sheet. I'm looping through that, checking the 9th value of each array entry for a string of "Yes" and then running the rest of the function (for each column with a "Yes") if the condition is true.
I thought I had this working before, but recently had to restructure and optimize some things. Now I'm starting to think I may need to rethink things and use a different loop method. Can anyone educate me?
Edit: Here's a bit more context as requested:
function menuItem1() {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Are you sure you want to send emails?', ui.ButtonSet.YES_NO);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var lastRow = sheets[3].getLastRow();
var zw = sheets[3].getRange(2, 1, lastRow - 1, 26).getValues();
if (response === ui.Button.YES) {
for (var j = 0; j < zw.length; j++) {
if (zw[j][9] === 'Yes') {
var firstLetterLastName = [];
firstLetterLastName.push(zw[j][1].charAt(0).toLowerCase());
//Other Stuff....
}
}
}
}
I have a menu item attached to a simple onOpen, that calls menuItem1(). Calling the function prompts the user with a warning that they are about to send emails, then goes about getting data to assign email addresses based on the contents of the sheets. firstLetterLastName is an example.
I'm still not getting the loop to function, is it because I have it between two if statements? (Here is a link to the sheet)
Indeed it is quite trivial. You have mixed up your increment. You wrote
for (var j = 0; j < zw.length; ++j)
which means that you do 1 + i (and we know that at the start i = 0 which means your value will always be 1) instead of using the usual
for (var j = 0; j < zw.length; j++)
which would mean that you do i + 1 and update i, so you will get the expected 0 + 1 1 + 1 etc
EDIT:
First, I recommend instead of something like
if (responseMir === ui.Button.YES) {
// Your For loop
doing
if (responseMir !== ui.Button.YES) {
return
}
and in a similar fashion in the for loop
if (zw[j][9] !== 'Yes') {
break
}
It mostly helps increase readability by not including large blocks of code under a single if, when all you want to do is to stop execution.
Your for loop gets broken because of the mistake here:
teacherEmailMir.push(selValsMir[j][7]);
So your loop will go over once. However on the next itteration, you try to push selValsMir[1][7] which does not exist. Note that each itteration you have var selValsMir = []; inside the loop, which means that for every j selValsMir will always be an empty array. So with the following line
selValsMir.push([zw[j][0], zw[j][1], zw[j][2], zw[j][3], zw[j][4], zw[j][5], zw[j][7], zw[j][22], zw[j][23], zw[j][24]]);
your array will always have selValsMir.lenght = 1 and selValsMir[0].length = 10. So obviously trying to access anything from selValsMir[1] will throw you an error and stop the script right there.
I also recommend looking over the if statements that look at the first and first 2 letters of the name as I believe you can accomplish the same with less code. Always try to streamline. Consider using switch() where you end up using a lot of else if

Loop reload same trial instead of next one Qualtrics

I have a problem with Qualtrics Loop and Merge + Javascript. Basically, Qualtrics reload the previous trial of my loop instead of a new one.
First, here is what I try to do: I have two sets of pictures, at each loop, one picture of each set is randomly picked and displayed (randomly to the left or right side). At the end of the loop, each pictures of the set will be displayed (33 in each set, so 33 trials of the loop), without picking twice the same picture. At each trial, I also display randomly the name of the condition "in relationship" or "friends"
The problem in details:
I have coded something that seems to work quite well, except at some point: It happens that when loading the next trial of the loop, it doesn't display new pictures but instead the one that were presented in the previous trial (and also the same name of condition). This can go for a while presenting me always the same pictures, or this can just be one time.
In any case, this trial which is represented count as a trial, as my loop always ends after 33 trials, whatever if some of these are actually not new pictures presented.
This problem doesn't appear always at the same trial, and can appear several times in a loop.
It also happened that only one picture displayed is new, and the other is the one presented in the previous trial. (I really don't get how this can happen).
I coded the randomisation of picture in an empty question, just before the question where it displays the pictures. This empty question is supposed to not require to press the "next" button. When the trial are correct, this is working well, but when the next trial is going to be one "reloaded" trial, it requires to press the "next" button.
I tried the survey with Firefox and Edge, and the problem is the same.
My javascript code:
In the first question of the survey:
Qualtrics.SurveyEngine.addOnload(function () {
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;
};
var FacesM_list = "IM_7U04c3TQlA7dT3D,IM_eE5iBcKfoOblbJH,IM_a3mklzA9E1OuRWl,IM_bQnoSJOGwa0vn9P,IM_5inNCVgPdHHTVSR,IM_bHlurQJWSXDRDFj,IM_3rCr2DIzW2cvqLP,IM_509x1wz7pM6PP0N,IM_3UGdsp02IcCqaSV,IM_eLrY7bwDPiT7apn,IM_3LdlHnBb6tnkBEh,IM_3pY6z6JDgaDvwq1,IM_9HtZxBS79DiOfR3,IM_03c9pDSpcwcqIyF,IM_6WGKJOzUWK4TJat,IM_2rxQPEGO7SEvsY5,IM_9YN3UCUtWEWTfGR,IM_8jZTSUAGJfuVECV,IM_9nQkFhRY2cLIVgN,IM_2abcJA7B79jt30h,IM_cD31N8XPTGliUN7,IM_0eL8iQd4PVdyuQl,IM_cuOoV9gSAe6CWd7,IM_9Nv3X7lWYEsTzsF,IM_5ccXAuuomEEyamp,IM_9mnvThFiNA5U84t,IM_e3UGNNuMdrKH8cl,IM_3aggsd5P9MMlUDr,IM_4ORY6GEMW8CmNPT,IM_50WOBkz8ADTFGHH,IM_3rqtlVBfijYCccZ,IM_3CzDsr0tYv7PH5H,IM_4SmeprjDgOeCl5b"
var FacesF_list = "IM_6fkHDs5f6ItAuk5,IM_0ri9MLjDhHxyonP,IM_bKlHtoAaxnBFlnT,IM_1WUqtBPpdhERpjf,IM_ac0yWos8tAqSMNT,IM_3xCePACn1Lq97tH,IM_6o1ZPLGUM682Au1,IM_babATdN3VtBLIsl,IM_8HSUICLvFvDXaN7,IM_0ebTztq3ML5Zh0V,IM_3lB8j5dhMs8i8ip,IM_0iC0pwDlpOkcTGt,IM_cIRojwU6sx3W7Od,IM_9ZHNbignrAfcThX,IM_8iFXvVcCqk5hemN,IM_6rrwImdl4Nss0u1,IM_6mPEaoIdazwqAWp,IM_b8lrxhsPGcc1HaR,IM_23uYWeF2gYVMsap,IM_6ycfrm5xOlewjFb,IM_7UKValFGc9Kmpp3,IM_8Bbkzsmc7CyMvqt,IM_d5S95FnSgo8j06F,IM_brXT4VUU8QJiRwN,IM_9MEkpgEmOwXhril,IM_6KG9qokOlD16GDH,IM_ellgVnYbtb8ZSbb,IM_eg6qSYMQ56z5JpX,IM_5vfbDNPdZeP1XCZ,IM_cDbOprwCUUSnUZT,IM_cumIGHXOFByV4Pz,IM_0jh2Va4JTfGsQDz,IM_0CGlFRy4dW8lDcF"
var FacesM_order = [];
for (var i = 1; i <= 33; i++) {
FacesM_order.push(i);
}
FacesM_order = shuffle(FacesM_order);
var FacesF_order = [];
for (var i = 1; i <= 33; i++) {
FacesF_order.push(i);
}
FacesF_order = shuffle(FacesF_order);
var nTrial = 0;
Qualtrics.SurveyEngine.setEmbeddedData("FacesM_order", FacesM_order.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesF_order", FacesF_order.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesF_list", FacesF_list.toString());
Qualtrics.SurveyEngine.setEmbeddedData("FacesM_list", FacesM_list.toString());
Qualtrics.SurveyEngine.setEmbeddedData("nTrial", nTrial.toString());
});
And in the first question of the Block with Loop and Merge:
Qualtrics.SurveyEngine.addOnload(function () {
var nTrial = Number("${e://Field/nTrial}") + 1;
var FacesF_list = "${e://Field/FacesF_list}".split(',');
var FacesM_list = "${e://Field/FacesM_list}".split(',');
var FacesF_order = "${e://Field/FacesF_order}".split(',');
var FacesM_order = "${e://Field/FacesM_order}".split(',');
var FacesF = FacesF_list[FacesF_order[nTrial]];
var FacesM = FacesM_list[FacesM_order[nTrial]];
var rand = Math.random()
if (rand < 0.5) {
var left = FacesF
var right = FacesM
} else {
var left = FacesM
var right = FacesF
}
Qualtrics.SurveyEngine.setEmbeddedData("nTrial", nTrial.toString());
Qualtrics.SurveyEngine.setEmbeddedData("left", left.toString());
Qualtrics.SurveyEngine.setEmbeddedData("right", right.toString());
this.clickNextButton.delay(.00000000000001);
});
Thanks a lot for your help!

Generating random unique data takes too long and eats 100% CPU

WARNING: CPU Usage goes to 100%, be careful.
Link to the jsFiddle
This script has been written to design a dynamic snake and ladder board. Everytime the page is refreshed a new board is created. Most of the time all of the background images do not appear, and the CPU usage goes up to 100%. But on occasion all of them appear and the CPU usage is normal.
Opera shows some of the background images, Firefox lags and asks me if I wish to stop the script.
I believe that the problem is with these lines of code:
for(var key in origin) // Need to implement check to ensure that two keys do not have the same VALUES!
{
if(origin[key] == random_1 || origin[key] == random_2 || key == random_2) // End points cannot be the same AND starting and end points cannot be the same.
{
valFlag = 1;
}
console.log(key);
}
Your algorithm is very ineffective. When array is almost filled up, you literally do millions of useless iterations until you're in luck and RNG accidentally picks missing number. Rewrite it to:
Generate an array of all possible numbers - from 1 to 99.
When you need a random numbers, generate a random index in current bounds of this array, splice element and this random position, removing it from array and use its value as your desired random number.
If generated numbers don't fit some of your conditions (minDiff?) return them back to array. Do note, that you can still stall in loop forever if everything that is left in array is unable to fit your conditions.
Every value you pull from array in this way is guaranteed to be unique, since you originally filled it with unique numbers and remove them on use.
I've stripped drawing and placed generated numbers into array that you can check in console. Put your drawing back and it should work - numbers are generated instantly now:
var snakes = ['./Images/Snakes/snake1.png','./Images/Snakes/snake2.jpg','./Images/Snakes/snake3.gif','./Images/Snakes/snake4.gif','./Images/Snakes/snake5.gif','./Images/Snakes/snake6.jpg'];
var ladders = ['./Images/Ladders/ladder1.jpg','./Images/Ladders/ladder2.jpg','./Images/Ladders/ladder3.png','./Images/Ladders/ladder4.jpg','./Images/Ladders/ladder5.png'];
function drawTable()
{
// Now generating snakes.
generateRand(snakes,0);
generateRand(ladders,1);
}
var uniqNumbers = []
for(var idx = 1; idx < 100; idx++){ uniqNumbers.push(idx) }
var results = []
function generateRand(arr,flag)
{
var valFlag = 0;
var minDiff = 8; // Minimum difference between start of snake/ladder to its end.
var temp;
for(var i = 0; i< arr.length; ++i) {
var valid = false
// This is the single place it still can hang, through with current size of arrays it is highly unlikely
do {
var random_1 = uniqNumbers.splice(Math.random() * uniqNumbers.length, 1)[0]
var random_2 = uniqNumbers.splice(Math.random() * uniqNumbers.length, 1)[0]
if (Math.abs(random_1 - random_2) < minDiff) {
// return numbers
uniqNumbers.push(random_1)
uniqNumbers.push(random_2)
} else {
valid = true
}
} while (!valid);
if(flag == 0) // Snake
{
if(random_1 < random_2) // Swapping them if the first number is smaller than the second number.
{
var temp = random_1; random_1 = random_2; random_2 = temp
}
}
else // Ladders
{
if(random_1>random_2) // Swapping them if the first number is greater than the second number.
{
var temp = random_1; random_1 = random_2; random_2 = temp
}
}
// Just for debug - look results up on console
results.push([random_1, random_2])
}
}
drawTable()
I had a problem like this using "HighCharts", in a for loop - "browsers" have an in-built functionality to detect dead scripts or infinite loops. So the browsers halts or pop-ups up a message saying not responding. Not sure if you have that symptom!
This was resulted from a "loop" with a large pool of data. I wrote a tutorial on it on CodeProject, you might try it, and it might be your answer.
http://www.codeproject.com/Tips/406739/Preventing-Stop-running-this-script-in-Browsers

Categories