Array removing, "undefined" and JavaScript - javascript

first sorry my english.
Im making a little program to sort football players into two teams, A and B.
6 players, 3 for A and 3 for B. With a random number generator of course.
In Java i have no problem, i made this program and runs perfect, but i dont know much about JS and array item removings seems a little diferent here.
My code:
function hola(){
var primero = document.getElementById("1").value;
var segundo = document.getElementById("2").value;
var tercero = document.getElementById("3").value;
var cuarto = document.getElementById("4").value;
var quinto = document.getElementById("5").value;
var sexto = document.getElementById("6").value;
var jugadores = [primero,segundo,tercero,cuarto,quinto,sexto];
var eq1=[];
var eq2=[];
while (jugadores.length > 0){
var largoArray = jugadores.length;
var rand = Math.round(Math.random()* largoArray);
console.log("before the if, array jugadores haves ",jugadores.toString() ," and his size is ",jugadores.length);
if (eq1.length < 3){
eq1.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
}else {
eq2.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
}
}
document.getElementById("resultado").innerHTML= eq1 + " y el equipo B: " + eq2;
console.log("equipo 1 ", eq1);
console.log("equipo 2", eq2);
}
function remove(array, element) {
const index = array.indexOf(element);
if (index !== -1) {
array.splice(index, 1);
}
}
and it return to me:
"equipo 1 (3) [undefined, "iniesta", "ronaldo"]
script2.js:35 equipo 2 (4) ["messi", "ronaldinho", "maradona", "pele"]"
also the console logs i made to depurate seems to work fine...
The array is 1 element shorter each cicle, and array.lenght match the desired sizes.
What am doing wrong?

The problem is on the line:
Math.round(Math.random() * largoArray)
Since that will sometimes return an index that is beyond the bounds of the array. When that happens, this code:
eq1.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
Won't work, since jugadores[rand] is undefined, so you end up pushing undefined into one of your arrays, without removing anything from the original jugadores array.
To fix this, use the Math.floor function instead, changing the line to:
Math.floor(Math.random() * largoArray)

Arrays (like Java) start with the index 0.
The range of random numbers you are generating varies from 0 to 6 (array has only 6 elements).
var rand = Math.round(Math.random()* largoArray);
Instead use,
var rand = Math.round((Math.random()* largoArray)-1);

Related

Can't get stable result with copying random values from array to an object

So I'm in process of creating a bot for a tournament and I got stuck on the part where I want to split players in pairs for play-off-style tournament. I just want to take 2 random players, get them from an array and write it as a value to a key as a round id for an object. Also I should not use those players again in the pair, so need to delete them or smth.
Here's the code:
var users = inc.funcs.getDatabase() //Getting a raw array of users (using my func that's basically a simplified fs.readFileSync func)
var tournamentPairs = new Object() //Object initialization
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * (users.length + 1)) //Randomizing 2 indexes
var second = Math.floor(Math.random() * (users.length + 1))
var player1 = client.users.get(users[first]) //Getting the players by id
var player2 = client.users.get(users[second])
tournamentPairs[id++] = [player1.id, player2.id] //Writing to the object
users.splice(first, 1) //Deleting user's indexes from the array to not use them anymore.
users.splice(second, 1)
}
console.log(tournamentPairs)
It works perfectly on the outside, but has a bad habit of duplicating users and I once could have a gamergod98 vs gamergod98 for example. I tried console.log this crap but it often get an error when trying to console.log player2 because it's undefined for some reason. If I try to print users[second] I get undefined though it never happened for the first player. So I tried different ways to prevent situations like this: first == second. Long story short it didn't help much.
I have 9 days 'till tournament starts, any ideas on how to improve this code?
You are getting undefined because you are going out of bounds of your users list. For a list of length the last element is list[length-1], but you are generating random numbers up to length.
To fix duplicate users, remove the first selected user from the list before selecting the second one (or for a less destructive approach, mark already selected users).
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * users.length)
var player1 = client.users.get(users[first])
users.splice(first, 1)
var second = Math.floor(Math.random() * users.length)
var player2 = client.users.get(users[second])
users.splice(second, 1)
tournamentPairs[id++] = [player1.id, player2.id]
}
Create a collection of used indexes and then if first or second are in used indexes then continue
var usedIndices = [] ;
if (usedIndices.indexOf(first) >= 0 ||
usedIndices.indexOf(second) >= 0) {
continue;
} else {
usedIndices.push(first);
usedIndices.push(second);
}
Put the usedIndices variable before for loop and the if else block inside loop after second

Compute every combination of 6 numbers

I'm more of a media developer and not the best coder, but I find myself needing to learn javascript better. I'm creating a math card game where the human player and the automated player are each dealt 6 cards. Each player must combine (concatenate) three of the cards to make a top number and the other three for the bottom number. Those two numbers are then subtracted. For the automated player, I have to go through ever possible combination of the six cards, so when the two numbers are subtracted, it gets as close as possible to a target number. I'm not very good with arrays, so I started testing every possible combination and then comparing which one was closer (See example below). This is a very inefficient way of coding this, but I'm just not sure how to do it otherwise. Any help would be greatly appreciated.
The variables have already been declared.
alienTopNum = "" + alienNum1 + alienNum2 + alienNum3;
alienBottomNum = "" + alienNum4 + alienNum5 + alienNum6;
oldDiff = targetNum - (alienTopNum - alienBottomNum);
player.SetVar("AC1R1", alienNum1);
player.SetVar("AC2R1", alienNum2);
player.SetVar("AC3R1", alienNum3);
player.SetVar("AC4R1", alienNum4);
player.SetVar("AC4R1", alienNum5);
player.SetVar("AC4R1", alienNum6);
player.SetVar("ATR1", alienTopNum - alienBottomNum);
alienTopNum = "" + alienNum1 + alienNum2 + alienNum3;
alienBottomNum = "" + alienNum4 + alienNum6 + alienNum5;
newDiff = targetNum - (alienTopNum - alienBottomNum);
if (Math.abs(newDiff) < Math.abs(oldDiff)) {
oldDiff = newDiff;
player.SetVar("AC1R1", alienNum1);
player.SetVar("AC2R1", alienNum2);
player.SetVar("AC3R1", alienNum3);
player.SetVar("AC4R1", alienNum4);
player.SetVar("AC4R1", alienNum6);
player.SetVar("AC4R1", alienNum5);
player.SetVar("ATR1", alienTopNum - alienBottomNum);
}
etc....
Store the dealt cards in an array rather than in individual variables, because that makes them a lot easier to handle when generating permutations. You don't say what values the cards can have, but as an example, given a "hand" of [1,2,3,4,5,6] if you get the permutations as an array of arrays:
[ [1,2,3,4,5,6], [1,2,3,4,6,5], [1,2,3,5,4,6], ...etc. ]
Then you can loop through that to process each permutation to take the first three "cards" and last three to get the current iteration's two numbers, subtract them, and see if the result is closer to the target than previous iterations' results.
The following does that, making use of the array permutation function that I found in this answer to another question. I'm not going to explain that algorithm because you can easily google up various permutation algorithms for yourself, but I have put comments in my bestPlay() function to explain how I process the permutations to figure out which is the best score for a hand.
I haven't tried to use your player or player.SetVar() method, but hopefully if you study this you can adapt it to use with your objects.
You didn't say what values the cards could have, so I've assumed a deck of twenty cards that repeats the numbers 0-9 twice.
function bestPlay(hand, target) {
var perms = permutator(hand); // Get all permutations for hand
var best = perms[0]; // Use the first as initial best
var bestDiff = difference(best);
for (var i = 1; i < perms.length; i++) { // Loop over the rest of the permutations
var diff = difference(perms[i]); // Get diff for current permutation
if (Math.abs(target - diff) < Math.abs(target - bestDiff)) { // Check if
best = perms[i]; // current beats previous best
bestDiff = diff; // and if so make it new best
}
}
// Output the results for this hand:
console.log(`Hand: ${hand.join(" ")}`);
console.log(`Best Numbers: ${best.slice(0,3).join("")} ${best.slice(3).join("")}`);
console.log(`Difference: ${bestDiff}`);
}
var hands = deal();
var target = 112;
console.log(`Target: ${target}`);
bestPlay(hands[1], target);
bestPlay(hands[2], target);
function difference(cards) {
return Math.abs(cards.slice(0,3).join("") - cards.slice(3).join(""));
}
function deal() {
var cards = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0];
// shuffle
cards.sort(function() { return Math.random() - 0.5; });
// first hand is first six cards, second hand is next six
return {
1: cards.slice(0,6),
2: cards.slice(6, 12)
};
}
function permutator(inputArr) {
var results = [];
function permute(arr, memo) {
var cur, memo = memo || [];
for (var i = 0; i < arr.length; i++) {
cur = arr.splice(i, 1);
if (arr.length === 0) {
results.push(memo.concat(cur));
}
permute(arr.slice(), memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return results;
}
return permute(inputArr);
}
If you click the "Run Code Snippet" button several times you'll see that sometimes a given hand has a combination of numbers that exactly matches the target, sometimes it doesn't.

Code works on codeacademy's site, but won't work on coderbyte

I'm having problems with the code below, and it's really frustrating. The problem isn't seemingly the code itself: the program works just fine to find the second greatest and lowest numbers in an array, but only does so on the labs.codeacademy.com JavaScript environment thus far.
I went to Coderbyte.org to enter the correct code to pass the challenge. First, whenever I type, "input.sort(function(a,b){return (a-b);});" into coderbyte.org's site, it indents the remainder of the block from the middle of the page for some reason. This makes me think it could be the source of my problem.
When I cut and paste my code from codeacademy to coderbyte.org's website, it pastes with fine indentation, however it only returns a blank box instead of the second highest and lowest values still. My question: why does it work on one site, but not the other? I've been going nuts on this for two days: someone please help me?
function SecondGreatestLow(arr) {
input.sort(function(a,b){return (a-b);});
var input = arr;
var hashObject = {}
for (var i = input.length - 1; i >= 0; i--) {
var currentItem = input[i]; //WE LOOP THROUGH OUR NUMBER LIST
if (hashObject[currentItem] === true) {
input.splice(i, 1); //IF CURRENTITEM IS ALREADY IN HASHOBJECT, THEN DELETE THE COPY FOUND IN ARRAY AND MOVE ON TO NEXT NUMBER
}
hashObject[currentItem] = true; //IF CURRENTITEM IS NOT IN HASHOBJECT, ADD IT! THEN MOVE ON TO NEXT NUMBER.
}
//THE ARRAY HAS NOW BEEN "DE-DUPED":
//NEXT WE OUTPUT THE MAX AND MIN VALUES ACCORDING TO ARRAY SIZE
if (input.length >= 4) { //If 4+ chars, then remove the first two values to access the second by default
input.pop();
input.shift();
var min = Math.min.apply(null,input),
max = Math.max.apply(null,input);
return (max + " " + min);
} else {
var min2 = Math.min.apply(null,input),
max2 = Math.max.apply(null,input);
return max2 + " " + min2;
}
}
//example:
console.log(SecondGreatestLow(arr));
// THE OUTPUT ON CODEACADEMY IS AS FOLLOWS:
// arr = [ 1, 5, 10, 1, 25, 1, 5, 5, 5, 40, 5, 1, 100 ]; -> 40 5
// arr = [ 4, 90 ]; -> 90 4
Two things:
You define input after you try to sort it
You have to actually call your function on an array if you want it to output something (I assume you did this, but it would surprise you how many people forget; also, some editors will show you what's returned and others will require you to output it somewhere since, essentially, you're calling a function without doing anything with it; CCLabs is nice about this in that it shows the return values for every function call)

Javascript: Math.floor(Math.random()*array.length) not producing a random number?

This on e is a doozey.
I have while loop to generate a random number that is not the same as any other random number produced before. The random number is used to select a text value from an object.
for example:
quoteArray[1] = "some text"
quoteArray[2] = "some different text"
quoteArray[3] = "text again"
quoteArray[4] = "completely different text"
quoteArray[5] = "ham sandwich"
This is part of a larger function and after that function has cycled through = quoteArray.length it resets and starts the cycle over again. The issue I am hitting is that the following code is SOMETIMES producing an infinite loop:
//Note: at this point in the function I have generated a random number once already and stored it in 'randomnumber'
//I use this while statement to evaluate 'randomnumber' until the condition of it NOT being a number that has already been used and NOT being the last number is met.
while(randomnumber === rotationArray[randomnumber] || randomnumber === lastnumber){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
}
When I console.log(randomnumber) - when I am stuck in the loop - I am just getting '0' as a result. When stuck in the loop it doesn't appear as though Math.floor(Math.random() * (quoteArray.length)) is producing a random number but rather just '0' infinitely.
can anyone tell me why I am running into this problem?
EDIT: Here is the complete pertinent code with function + variable declarations
// Function to initialize the quoteObj
function quoteObj(text,cname,ccompany,url,height) {
this.text=text;
this.cname=cname;
this.ccompany=ccompany;
this.url=url;
this.height=height;
}
// Populate my quotes Object with the quotation information from the XML sheet.
var qObj = new quoteObj('','','','');
var quoteArray = new Array();
var counter = 0;
//cycles through each XML item and loads the data into an object which is then stored in an array
$.ajax({
type: "GET",
url: "quotes.xml",
dataType: "xml",
success: function(xml) {
$(xml).find('quote').each(function(){
quoteArray[counter] = new quoteObj('','','','');
console.log(quoteArray[counter]);
quoteArray[counter].text = $(this).find('text').text();
quoteArray[counter].cname = $(this).find('customer_name').text();
quoteArray[counter].ccompany = $(this).find('customer_company').text();
quoteArray[counter].url = $(this).find('project').text();
++counter;
});
}
});
// This is the setion that is generating my infinite loop issue.
// I've included all of the other code in case people are wondering specific things about how an item was initialized, etc.
// Generate a random first quote then randomly progress through the entire set and start all over.
var randomnumber = Math.floor(Math.random() * (quoteArray.length));
var rotationArray = new Array(quoteArray.length);
var v = 0;
var lastnumber = -1;
bHeight = $('#rightbox').height() + 50;
var cHeight = 0;
var divtoanim = $('#customerquotes').parent();
//NOT RELATED//
// Give the innershadow a height so that overflow hidden works with the quotations.
$(divtoanim).css({'height' : bHeight});
// Rotate the Quotations Randomly function.
setInterval(function(){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
//checks to see if the function loop needs to start at the beginning.
if(v == (quoteArray.length)){
rotationArray.length = 0;
v = 0;
}
//determines if the random number is both different than any other random number generated before and that is is not the same as the last random number
while(randomnumber === rotationArray[randomnumber] || randomnumber === lastnumber){
randomnumber = Math.floor(Math.random() * (quoteArray.length));
}
lastnumber = randomnumber;
rotationArray[randomnumber] = randomnumber;
++v;
//NOT RELATED//
//animation sequence
$('#ctext, #cname').animate({'opacity':'0'},2000, function(){
$('#ctext').html(quoteArray[randomnumber].text);
$('#cname').html('- ' + quoteArray[randomnumber].cname);
cHeight = $('#customerquotes').height() + 50;
adjustHeight(bHeight,cHeight,divtoanim);
$('#ctext').delay(500).animate({'opacity':'1'},500);
$('#cname').delay(1500).animate({'opacity':'1'},500);
});
},15000);
This is an asynchronous problem: the array quoteArray is empty when the code runs, because it fires off the ajax request, and moves on. Anything that depends on quoteArray should be inside the success function of $.ajax.
The array has a length when you type quoteArray.length in the console, only because by that time the Ajax request has completed.
have you tried something like
Math.floor(Math.random() * (5));
To make sure the array length is being found properly?
First, since you updated your question, be sure that you are handling asynchronous data properly. Since an ajax call is asynchronous, you will need to be sure to only run the randomizer once the call is successful and data has been returned.
Second, assuming you are handling the asyc data properly, the size of your result set is likely it is too small. Thus, you are probably randomly getting the same number too often. Then, you can't use this number because you have already done so.
What you need to do is pop off the parts that are already used from the results array each time. Recalculate the array length, then pull a random from that. However, the likelihood of this feeling random is very slim.
There is probably a more efficient way to do this, but here's my go:
var results = ['some text','some text2','some text3','some text4','some text5', /* ...etc */ ],
randomable = results;
function getRandomOffset( arr )
{
var offset,
len;
if( arr.length < 1 )
return false;
else if( arr.length > 1 )
offset = Math.floor(Math.random() * arr.length );
else
offset = 0;
arr.splice( offset, 1 );
return [
offset,
arr
];
}
while( res = getRandomOffset( randomable ) )
{
// Set the randomable for next time
randomable = res[1];
// Do something with your resulting index
results[ res[0] ];
}
The arrgument sent to the function should be the array that is returned form it (except the first time). Then call that function as you need until it returns false.

how to create a loop in a function with another function?

I'm new to Java and I'm doing a uni course. I've been asked to design three functions.I have to find the difference between each adjacent numbers in an array, another to total the array and the last one to calculate the difference using the other functions then write a programme. I'm totally lost on the last function and my tutor has gone away on hols. Here is the code I have done so far. I don't want people doing the code for me but if anyone can advice me what I need to do I would appreciate your advice. I'm not sure how to loop the difference function into the array and store it into the new array I have made. If anyone could explain where I am going wrong I would love to hear from you!
var numberArray = [10,9,3,12];
// function difference will find the highest value of the two numbers,find the difference between them and return the value.
function difference(firstNumber, secondNumber)
{
if (firstNumber > secondNumber)
{
return (firstNumber - secondNumber);
}
else
{
return (secondNumber - firstNumber);
}
}
// function sum will add the total numbers in the array and return the sum of numbers.
function sum(numberArray)
{
numberTotal = 0
for (var total = 0; total < numberArray.length; total = total + 1)
{
numberTotal = numberTotal + numberArray[total]
}
{
return numberTotal
}
/*code the process that calculates a new array containing the differences between all the pairs
of adjacent numbers, using the difference() function you have already written.
This function should be named calculateDifferences() and should accept an array numberArray.
The function should first create a new empty array of the same size as numberArray
It should then calculate the differences between the pairs of adjacent numbers,
using the difference() function, and store them in the new array. Finally, the function should return the new array.
The calculation of the differences should be done in a loop, at each step finding the difference between each
array element and the next one along in the array, all except for the last difference,
which must be dealt with as a special case, because after the last element we have to wrap round to the start again.
So the final difference is between the last and first elements in the array.*/
function calculateDifferences()
var createArray = new Array (numberArray.length);
{
createArray = 0;
for (var c = 0; c < numberArray.length; c = c + 1)
{
createArray = difference(numberArray[c]);
}
{
return createArray
}
}
your implementation of function "calculateDifferences" is not correct.
this function should look like this:
function calculateDifferences()
{
var createArray = new Array (numberArray.length);
for (var c = 0; c < numberArray.length - 1 ; c = c + 1)
{
/*
because of the function "difference" has two parameters (firstNumber, secondNumber) in its declaration, we should give two arguments. (that are adjacent elements in array)
*/
createArray[c] = difference(numberArray[c],numberArray[c+1]);
}
/ *
calculating difference of first and last element of array and
assign it to returning array's last element.
*/
createArray[numberArray.length - 1] = difference(numberArray[0],numberArray[numberArray.length - 1]);
return createArray;
}
You should index createArray the same way you already do with numberArray[c].

Categories

Resources