Jump to content

help with for loop and Array's (Javascript)

Kimmaz

Hello, I need some help with my coding. I am learning javascript for fun. The for loop selects a random item from a Array (using Math.random) over and over. But I don't want it to be able to select the same item more than once. Perhaps one solution to this problem is to remove the selected item from the array, and so its not even in the "hat" next time around. But I don't know how to do/write that. Perhaps a function/code I have yet to learn can be used. Do you know how?

 

If you have any suggestions to solve this issue that would be awesome. (it should also depend on if Duplicate Civ's    and Duplicate Leaders is Enabled/Disabled)

 

You can see it in action here: https://sunomi.no/Civ6/

Here is the relevant code: (the for loop is at the very bottom).

Spoiler

// Assigns a leader to all the 20 player slots at the bottom left of the page.
function rndAssignLeaders() {
    // A list of the ID="" of the 20 output fields the data is displayed in.
    const leaderOutputID = [
        "resPlayeroutput1", "resPlayeroutput2", "resPlayeroutput3", "resPlayeroutput4", "resPlayeroutput5",
        "resPlayeroutput6", "resPlayeroutput7", "resPlayeroutput8", "resPlayeroutput9", "resPlayeroutput10",
        "resPlayeroutput11", "resPlayeroutput12", "resPlayeroutput13", "resPlayeroutput14", "resPlayeroutput15",
        "resPlayeroutput16", "resPlayeroutput17", "resPlayeroutput18", "resPlayeroutput19", "resPlayeroutput20"
    ]
    // This Array stores all the avaliable leaders that can be used/selected randomly.
    var leaderStoredText = [];
    // Adds Base Game Leaders to the Array IF they are not Banned.
    if (lbbase_input1.checked == false) leaderStoredText.push("Catherine - France");
    if (lbbase_input2.checked == false) leaderStoredText.push("Cleopatra - Egypt");
    if (lbbase_input3.checked == false) leaderStoredText.push("Frederick - Germany");
    if (lbbase_input4.checked == false) leaderStoredText.push("Gandhi - India");
    if (lbbase_input5.checked == false) leaderStoredText.push("Gilgamesh -");
    if (lbbase_input6.checked == false) leaderStoredText.push("Gorgo - Greece");
    if (lbbase_input7.checked == false) leaderStoredText.push("Harald - Norway");
    if (lbbase_input8.checked == false) leaderStoredText.push("Hojo - Japan");
    if (lbbase_input9.checked == false) leaderStoredText.push("Mvemba - Kongo");
    if (lbbase_input10.checked == false) leaderStoredText.push("Pedro - Brazil");
    if (lbbase_input11.checked == false) leaderStoredText.push("Pericles - Greeze");
    if (lbbase_input12.checked == false) leaderStoredText.push("Peter - Russia");
    if (lbbase_input13.checked == false) leaderStoredText.push("Phillip - Spain");
    if (lbbase_input14.checked == false) leaderStoredText.push("Qin - China");
    if (lbbase_input15.checked == false) leaderStoredText.push("Saladin - Arabia");
    if (lbbase_input16.checked == false) leaderStoredText.push("Teddy - America");
    if (lbbase_input17.checked == false) leaderStoredText.push("Tomyris - Scythia");
    if (lbbase_input18.checked == false) leaderStoredText.push("Trajan - Rome");
    if (lbbase_input19.checked == false) leaderStoredText.push("Victoria - England");
    // Checks if DLC1 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked1.checked == true) {
        if (lbdlc1_input1.checked == false) leaderStoredText.push("Chandragupta - India");
        if (lbdlc1_input2.checked == false) leaderStoredText.push("Genghis Khan - Mongolia");
        if (lbdlc1_input3.checked == false) leaderStoredText.push("Lautaro - Mapuche");
        if (lbdlc1_input4.checked == false) leaderStoredText.push("Poundmaker - Cree");
        if (lbdlc1_input5.checked == false) leaderStoredText.push("Robert - Scotland");
        if (lbdlc1_input6.checked == false) leaderStoredText.push("Seondeok - Korea");
        if (lbdlc1_input7.checked == false) leaderStoredText.push("Shaka - Zulu");
        if (lbdlc1_input8.checked == false) leaderStoredText.push("Tamar - Georgia");
        if (lbdlc1_input9.checked == false) leaderStoredText.push("Wilhelmina - Netherlands");
    }
    // Checks if DLC2 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked2.checked == true) {
        if (lbdlc2_input1.checked == false) leaderStoredText.push("Dido - Phoenicia");
        if (lbdlc2_input2.checked == false) leaderStoredText.push("Eleanor - France");
        if (lbdlc2_input3.checked == false) leaderStoredText.push("Kristina - Sweden");
        if (lbdlc2_input4.checked == false) leaderStoredText.push("Kupe - Maori");
        if (lbdlc2_input5.checked == false) leaderStoredText.push("Mansa Musa - Mali");
        if (lbdlc2_input6.checked == false) leaderStoredText.push("Matthias Corvinus - Hungary");
        if (lbdlc2_input7.checked == false) leaderStoredText.push("Pachacuti - Inca");
        if (lbdlc2_input8.checked == false) leaderStoredText.push("Suleiman - Ottomans");
        if (lbdlc2_input9.checked == false) leaderStoredText.push("Wilfrid Laurier - Canada");
        if (lbdlc2_input10.checked == false) leaderStoredText.push("Eleanor - England");
    }
    // Checks if DLC3 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked3.checked == true) {
        if (lbdlc3_input1.checked == false) leaderStoredText.push("John Curtin - Australia");
    }
    // Checks if DLC4 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked4.checked == true) {
        if (lbdlc4_input1.checked == false) leaderStoredText.push("Montezuma - Aztec");
    }
    // Checks if DLC5 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked5.checked == true) {
        if (lbdlc5_input1.checked == false) leaderStoredText.push("Gitarja - Indonesia");
        if (lbdlc5_input2.checked == false) leaderStoredText.push("Jayavarman - Khmer");
    }
    // Checks if DLC6 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked6.checked == true) {
        if (lbdlc6_input1.checked == false) leaderStoredText.push("Lady Six Sky - Maya");
        if (lbdlc6_input2.checked == false) leaderStoredText.push("Simon Bolivar - Gran Colombia");
    }
    // Checks if DLC7 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked7.checked == true) {
        if (lbdlc7_input1.checked == false) leaderStoredText.push("Amanitore - Nubia");
    }
    // Checks if DLC8 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked8.checked == true) {
        if (lbdlc8_input1.checked == false) leaderStoredText.push("Alexander -");
        if (lbdlc8_input2.checked == false) leaderStoredText.push("MacedonCyrus - Persia");
    }
    // Checks if DLC9 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked9.checked == true) {
        if (lbdlc9_input1.checked == false) leaderStoredText.push("Jadwiga - Poland");
    }
    for (i = 0; i < 20; i++) {
        // Selects one random Leader from the Array using Math.
        let leaderChoosen = Math.floor(Math.random() * leaderStoredText.length);
        // Sends/Writes the Leader Name to all 20 Output fields.
        document.getElementById(leaderOutputID[i]).innerHTML = leaderStoredText[leaderChoosen];
    }
}

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

@Imaginationac

Thanks for the tip. I think I got it. what do you think about this? Do you think i could have written it differently. (this is at the bottom of the code in OP)

// Checks if Duplicate leaders is allowed.
    if (duplicateLeader.textContent == "Disabled" || duplicateCiv.textContent == "Disabled") {
        console.log("Hello Enabled")
        for (i = 0; i < 20; i++) {
            // Selects one random Leader from the Array using Math.
            let leaderChoosen = Math.floor(Math.random() * leaderStoredText.length);
            // Sends/Writes the Leader Name to all 20 Output fields.
            document.getElementById(leaderOutputID[i]).innerHTML = leaderStoredText[leaderChoosen];
            leaderStoredText.splice(leaderChoosen, 1);
        }
    } else {
        for (i = 0; i < 20; i++) {
            // Selects one random Leader from the Array using Math.
            let leaderChoosen = Math.floor(Math.random() * leaderStoredText.length);
            // Sends/Writes the Leader Name to all 20 Output fields.
            document.getElementById(leaderOutputID[i]).innerHTML = leaderStoredText[leaderChoosen];
        }
    }

 

Link to comment
Share on other sites

Link to post
Share on other sites

Here's another suggestion based on the random shuffle algorithm for arrays.

 

1)  Store the length of the array in a variable (tempLen = array.length)

2)  Start the loop

3)  Select a random element based on the tempLen variable  (rndPos = randomInt()%tempLen);

4)  Do whatever you need with the value in the array

5)  Swap it with with element [tempLen-1].

6)  tempLen = tempLen-1

7)  Start the loop again

 

Since you're decrementing the tempLen variable each loop iteration, you'll always select from the elements you haven't chosen.  I think the slice answer is good, but this way will scale better if you start working with larger and larger arrays.

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

@JacobFW

Thanks for the advice. I must have misunderstood, but does not that exclude the last item in the array, since you choose from tempLen-1. example array lenght 5, random 1-5, then 1-4 then 1-3 ect. How does it move the selected array element to the "last" position of the array and thus making sure you don't pick the same value twice? is it in step 5. what code does step 5 use?

 

also, is rndPos = randomInt()%leaderStoredText.length); a shorter way to write Math.floor(Math.random() * leaderStoredText.length) ? does it give a random number just the same, perhaps I should use that instead.

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, Kimmaz said:

@JacobFW

Thanks for the advice. I must have misunderstood, but does not that exclude the last item in the array, since you choose from tempLen-1. example array lenght 5, random 1-5, then 1-4 then 1-3 ect. How does it move the selected array element to the "last" position of the array and thus making sure you don't pick the same value twice? is it in step 5. what code does step 5 use?

 

also, is rndPos = randomInt()%leaderStoredText.length); a shorter way to write Math.floor(Math.random() * leaderStoredText.length) ? does it give a random number just the same, perhaps I should use that instead.

I guess calling it "last item in the array" isn't the best terminology.  Let's use your example, where have an array of length five.

 

For the first loop iteration, we randomly select an element from all the element of the array.  We then swap that with the 5th (last) element of the array.

Next, we choose a random element from the first four elements in the array, since we know the last one has the one we've already used.  We swap the element we've chosen with the 4th element in the array.  So now elements 4 & 5 have values we've already selected.

And again, we chose a random element, but this time just from the first three elements in the array. And we swap it with the element at position 3.  So now, elements 3, 4, & 5 all have values we've selected in past loop iterations.

 

Swapping the values is pretty simple.  Normally just

// swap array[i] with array[j]
var temp = array[i];
	array[i] = array[j];
	array[j] = temp;

 

Quote

also, is rndPos = randomInt()%leaderStoredText.length); a shorter way to write Math.floor(Math.random() * leaderStoredText.length) ? does it give a random number just the same, perhaps I should use that instead.

No, that was just pseudocode on my part.  I couldn't remember how to do it in JS off the top of my head, so I just madeup the function.

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

@JacobFW

Thanks I understand now. I think I can put that together. But I have a new challenge (no pressure). I had one problem with my current version, ill use a example too.

 

Here is a Array with 5 items/elements. I use Strings, because they are shown/written to a html Element, to show on screen. (the names are made up).

var leaderPool = ["Neal - Russia", " Victoria - France", "Hanna - Belgia", "Tommy - France", "Neal - Ukraine"]

 

Lets say the function chooses randomly "Tommy - France" it should also remove "Victoria - France" from the Array, IF duplicate Nations is Disabled.

Likewise IF duplicate Leaders is Disabled. When it chooses "Neal - Ukraine", also "Neal - Russia" should be removed from the Array./

Edit: or put to the end of the array in your case. not removed. from the "hat" but hope you understood.

 

Edit If duplicate Leaders and Nations  are both Enabled, this whole thing is not a issue, and it just chooses from the array without manipulating it. Also the Array length and somewhat the order depends on what DLC is chosen. And also what leaders are banned. (check the link in OP if this makes it confusing)

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, Kimmaz said:

@JacobFW

Thanks I understand now. I think I can put that together. But I have a new challenge (no pressure). I had one problem with my current version, ill use a example too.

 

Here is a Array with 5 items/elements. I use Strings, because they are shown/written to a html Element, to show on screen. (the names are made up).

var leaderPool = ["Neal - Russia", " Victoria - France", "Hanna - Belgia", "Tommy - France", "Neal - Ukraine"]

 

Lets say the function chooses randomly "Tommy - France" it should also remove "Victoria - France" from the Array, IF duplicate Nations is Disabled.

Likewise IF duplicate Leaders is Disabled. When it chooses "Neal - Ukraine", also "Neal - Russia" should be removed from the Array./

Edit: or put to the end of the array in your case. not removed. from the "hat" but hope you understood.

 

Edit If duplicate Leaders and Nations  are both Enabled, this whole thing is not a issue, and it just chooses from the array without manipulating it. Also the Array length and somewhat the order depends on what DLC is chosen. And also what leaders are banned. (check the link in OP if this makes it confusing)

I would do duplicate removal prior to choosing a random element from the array;  doing it during the selection is possible but would be more error prone with no additional benefit.

Use the split method with the dash as a separator to get the name and country as distinct values.  Frankly though I would recommend making each element of your array an object with two variables name & country.  Then whenever you display is just combine the two values together to get the string you'll display

Link to comment
Share on other sites

Link to post
Share on other sites

I did not attempt your array movements, but You gave me a good idea, to check the duplicates before the loop. That was super. I think I managed to solve the problem I had when I started this thread.. I added one array for each of the duplicates. and then removed one at random when needed. Then I used something called concatenation. I thought that was a math term, but the .concat() does it in javascript. It seems to work, I used console.log to check the Arrays a few times.

Thank you for the help.

 

Spoiler

// Assigns a leader to all the 20 player slots at the bottom left of the page.
function rndAssignLeaders() {
    // A list of the ID="" of the 20 output fields the data is displayed in.
    const leaderOutputID = [
        "resPlayeroutput1", "resPlayeroutput2", "resPlayeroutput3", "resPlayeroutput4", "resPlayeroutput5",
        "resPlayeroutput6", "resPlayeroutput7", "resPlayeroutput8", "resPlayeroutput9", "resPlayeroutput10",
        "resPlayeroutput11", "resPlayeroutput12", "resPlayeroutput13", "resPlayeroutput14", "resPlayeroutput15",
        "resPlayeroutput16", "resPlayeroutput17", "resPlayeroutput18", "resPlayeroutput19", "resPlayeroutput20"];
    // These Array's stores all the avaliable leaders that can be used/selected randomly.
    var leaderStoredText = [];
    var leaderStoredEngland = [];
    var leaderStoredFrance = [];
    var leaderStoredIndia = [];
    var leaderStoredEleanor = [];
    // Adds Base Game Leaders to the Array IF they are not Banned.
    if (lbbase_input1.checked == false) leaderStoredFrance.push("Catherine - France");
    if (lbbase_input2.checked == false) leaderStoredText.push("Cleopatra - Egypt");
    if (lbbase_input3.checked == false) leaderStoredText.push("Frederick - Germany");
    if (lbbase_input4.checked == false) leaderStoredIndia.push("Gandhi - India");
    if (lbbase_input5.checked == false) leaderStoredText.push("Gilgamesh -Sumeria");
    if (lbbase_input6.checked == false) leaderStoredText.push("Gorgo - Greece");
    if (lbbase_input7.checked == false) leaderStoredText.push("Harald - Norway");
    if (lbbase_input8.checked == false) leaderStoredText.push("Hojo - Japan");
    if (lbbase_input9.checked == false) leaderStoredText.push("Mvemba - Kongo");
    if (lbbase_input10.checked == false) leaderStoredText.push("Pedro - Brazil");
    if (lbbase_input11.checked == false) leaderStoredText.push("Pericles - Greeze");
    if (lbbase_input12.checked == false) leaderStoredText.push("Peter - Russia");
    if (lbbase_input13.checked == false) leaderStoredText.push("Phillip - Spain");
    if (lbbase_input14.checked == false) leaderStoredText.push("Qin - China");
    if (lbbase_input15.checked == false) leaderStoredText.push("Saladin - Arabia");
    if (lbbase_input16.checked == false) leaderStoredText.push("Teddy - America");
    if (lbbase_input17.checked == false) leaderStoredText.push("Tomyris - Scythia");
    if (lbbase_input18.checked == false) leaderStoredText.push("Trajan - Rome");
    if (lbbase_input19.checked == false) leaderStoredEngland.push("Victoria - England");
    // Checks if DLC1 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked1.checked == true) {
        if (lbdlc1_input1.checked == false) leaderStoredIndia.push("Chandragupta - India");
        if (lbdlc1_input2.checked == false) leaderStoredText.push("Genghis Khan - Mongolia");
        if (lbdlc1_input3.checked == false) leaderStoredText.push("Lautaro - Mapuche");
        if (lbdlc1_input4.checked == false) leaderStoredText.push("Poundmaker - Cree");
        if (lbdlc1_input5.checked == false) leaderStoredText.push("Robert - Scotland");
        if (lbdlc1_input6.checked == false) leaderStoredText.push("Seondeok - Korea");
        if (lbdlc1_input7.checked == false) leaderStoredText.push("Shaka - Zulu");
        if (lbdlc1_input8.checked == false) leaderStoredText.push("Tamar - Georgia");
        if (lbdlc1_input9.checked == false) leaderStoredText.push("Wilhelmina - Netherlands");
    }
    // Checks if DLC2 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked2.checked == true) {
        if (lbdlc2_input1.checked == false) leaderStoredText.push("Dido - Phoenicia");
        if (lbdlc2_input2.checked == false) {
            leaderStoredEngland.push("Eleanor - England");
            leaderStoredFrance.push("Eleanor - France");
            leaderStoredEleanor.push("Eleanor - France", "Eleanor - England");
        }
        if (lbdlc2_input3.checked == false) leaderStoredText.push("Kristina - Sweden");
        if (lbdlc2_input4.checked == false) leaderStoredText.push("Kupe - Maori");
        if (lbdlc2_input5.checked == false) leaderStoredText.push("Mansa Musa - Mali");
        if (lbdlc2_input6.checked == false) leaderStoredText.push("Matthias Corvinus - Hungary");
        if (lbdlc2_input7.checked == false) leaderStoredText.push("Pachacuti - Inca");
        if (lbdlc2_input8.checked == false) leaderStoredText.push("Suleiman - Ottomans");
        if (lbdlc2_input9.checked == false) leaderStoredText.push("Wilfrid Laurier - Canada");
    }
    // Checks if DLC3 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked3.checked == true) {
        if (lbdlc3_input1.checked == false) leaderStoredText.push("John Curtin - Australia");
    }
    // Checks if DLC4 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked4.checked == true) {
        if (lbdlc4_input1.checked == false) leaderStoredText.push("Montezuma - Aztec");
    }
    // Checks if DLC5 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked5.checked == true) {
        if (lbdlc5_input1.checked == false) leaderStoredText.push("Gitarja - Indonesia");
        if (lbdlc5_input2.checked == false) leaderStoredText.push("Jayavarman - Khmer");
    }
    // Checks if DLC6 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked6.checked == true) {
        if (lbdlc6_input1.checked == false) leaderStoredText.push("Lady Six Sky - Maya");
        if (lbdlc6_input2.checked == false) leaderStoredText.push("Simon Bolivar - Gran Colombia");
    }
    // Checks if DLC7 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked7.checked == true) {
        if (lbdlc7_input1.checked == false) leaderStoredText.push("Amanitore - Nubia");
    }
    // Checks if DLC8 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked8.checked == true) {
        if (lbdlc8_input1.checked == false) leaderStoredText.push("Alexander - Macedon");
        if (lbdlc8_input2.checked == false) leaderStoredText.push("Cyrus - Persia");
    }
    // Checks if DLC9 is selected Adds its Leaders and to the Array IF they are not Banned.
    if (dlcPicked9.checked == true) {
        if (lbdlc9_input1.checked == false) leaderStoredText.push("Jadwiga - Poland");
    }
    // Checks if Duplicate leaders is allowed.
    var leaderChoosen;
    var temp;
    // If Enabled Then only 1 Eleanor is added to the Final Array.
    if (duplicateLeader.textContent == "Enabled") {
        temp = Math.floor(Math.random() * leaderStoredEleanor.length);
        leaderStoredEleanor.splice(temp, 1);
    }
    // If Enabled Then only 1 from England, France and India is added to the Final Array.
    if (duplicateCiv.textContent == "Enabled") {
        temp = Math.floor(Math.random() * leaderStoredEngland.length);
        leaderStoredEngland.splice(temp, 1);
        temp = Math.floor(Math.random() * leaderStoredFrance.length);
        leaderStoredFrance.splice(temp, 1);
        temp = Math.floor(Math.random() * leaderStoredIndia.length);
        leaderStoredIndia.splice(temp, 1);
        // When both are Enabled this gets rid of duplicates.
        if (duplicateLeader.textContent == "Enabled") {
            if (leaderStoredEleanor.includes(leaderStoredEngland[0])) leaderStoredEngland[0].pop();
            if (leaderStoredEleanor.includes(leaderStoredFrance[0])) leaderStoredFrance[0].pop();
        }
    }
    // If both are disabled, Eleanor is stored 4 times, this make er only appear twice as she should.
    if (duplicateLeader.textContent == "Disabled" && duplicateCiv.textContent == "Disabled") leaderStoredEleanor = [];
    // This creates a new Array that is a combination of the 4 at the top.
    var leaderStoredFinal = leaderStoredText.concat(leaderStoredEngland, leaderStoredFrance, leaderStoredIndia, leaderStoredEleanor);
    if (duplicateCiv.textContent == "Enabled" || duplicateLeader.textContent == "Enabled") {
        for (i = 0; i < 20; i++) {
            // Selects one random Leader from the Array using Math.
            leaderChoosen = Math.floor(Math.random() * leaderStoredFinal.length);
            // Sends/Writes the Leader Name to all 20 Output fields.
            document.getElementById(leaderOutputID[i]).innerHTML = leaderStoredFinal[leaderChoosen];
            leaderStoredFinal.splice(leaderChoosen, 1);
        }
    } else {
        for (i = 0; i < 20; i++) {
            // Selects one random Leader from the Array using Math.
            leaderChoosen = Math.floor(Math.random() * leaderStoredFinal.length);
            // Sends/Writes the Leader Name to all 20 Output fields.
            document.getElementById(leaderOutputID[i]).innerHTML = leaderStoredFinal[leaderChoosen];
        }
    }
}

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×