简体   繁体   中英

Populate a prompt with elements of an array and number them off

(Stack Overflow doesn't have a tag for 'prompt' so I have used alert as I am guessing it is similar enough to attract the right answerers.)

Hello, I am currently making a JavaScript-based game for an assignment at university. I am usually pretty good with problem solving but have been stumped by this issue.

To explain, I have an array which names the possible armour slots the player can pick. In any order these can be picked, and each time the choice gets pushed to a second array which handles what has already been picked (and in what order) and that item gets spliced from the original array. There is a while loop which runs through until all 3 have been picked.

var armourSlotToPick = ["Head", "Chest", "Legs"],    
    armourSlotPicked = [],
    armourLoop = 1,
    indexArmour = 0;

function numInArray() {
    indexArmour++;
    return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}


function armour() {
    while (armourLoop < 4) {
        var armourPick = prompt("Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray));
        if (armourPick == 1) {
            armourSlotPicked.push(armourSlotToPick[0]);
            armourSlotToPick.splice(0,1);
        } else if (armourPick == 2) {
            armourSlotPicked.push(armourSlotToPick[1]);
            armourSlotToPick.splice(1,1);
        } else if (armourPick == 3) {
            armourSlotPicked.push(armourSlotToPick[2]);
            armourSlotToPick.splice(2,1);
        } else {
            alert("Invalid choice, you suck");
            break;
        }
        armourLoop++;
    }
}

I know it probably wouldn't be possible to do the whole return in numInArray() to the prompt, but it shows some working.

Now the problem: I got it working so that each item in the array was numbered (var armourSlotToPick = ["1. Head", "2. Chest", "3. Legs"],) but as you could see, if the player chose 2, then the next time it would show "1. Head (new line) 3. Legs" and when the player chooses 3, a problem would occur, as they were really meant to choose 2. How is it possible to number the items in the array, in a prompt?

I'm possibly over thinking this but I have suffered for a few hours now.

I thank you in advance for any insight you may have,

Daniel.


EDIT: Solved.

Below is the end result, a slight variation from the edited answer from Jonathan Brooks.

var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];
var armourLoop = 1;

function armour() {
    while (armourLoop < 4) {
        var message = "Pick an armour slot to generate an item for:\n";
        for (var i = 0; i < armourSlotToPick.length; i++) {
            if (armourSlotToPick[i] !== null) {
                message += "" + i + ". " + armourSlotToPick[i] + "\n"; 
            }            
        }
        var armourPick = prompt(message);
        if (armourPick > armourSlotToPick.length-1 || armourPick < 1) {
            alert("Invalid choice, you suck");
        } else {
            var insert = armourSlotToPick.splice(armourPick, 1);
            armourSlotPicked.push(insert);
        }
        armourLoop++;
    }
    armourSlotPicked.splice(0,1);
}

armour();
alert(armourSlotPicked.join("\n"));

I thank all that have contributed to this discussion and the end result, and I hope this is a good example for future problems people may have similar to this.

use structures / objects as content in the array, instead of just values.

the basic concept:

armourSlotPicked.push({ "key": 1, "value":armourSlotToPick[1]})
alert("value: " + armourSlotPicked[0].value)
alert("key: " + armourSlotPicked[0].key)

edit: responding to comments can take some space.

IMHO a prompt is the completely wrong tool for this, since most browsers would ask the user permission to prevent multiple popups, and since a promt can only return 1 piece of information, you can only ask for 1 thing per popup. Instead you ought to use a div element, with checkboxes for each information..

That being said it can easily be used in a promt. The prompt is just a built in function, that takes a string as an argument (which is shown as text in the popup) and returns a string with the users input.

what does the magic for you is in fact this: array.foreach() : The forEach() method executes a provided function once per array element.

in your case that means it calls a function that returns a string for each element in the array, and concatenates the strings.

in the old days you would have written this:

var messageText= "Pick an armour slot to generate an item for:\n"
for(var i = 1; i < armourSlotToPick.length; i++){
    messageText += i + ". " + armourSlotToPick[i- 1] + "\n";
}
var armourPick = prompt(messageText);

but in this modern age, you define a printing function, and use it to generate the loop:

function numInArray() {
    indexArmour++;
    return (indexArmour + ". " + armourSlotToPick[indexArmour - 1] + "\n");
}

//more code before we get to where the function is used....

indexArmour = 0;
var messageText = "Pick an armour slot to generate an item for:\n" + armourSlotToPick.forEach(numInArray);
var armourPick = prompt(messageText);

or in a single line as in your code: indexArmour = 0; //you forgot this - otherwise the list will only be complete once? var armourPick = prompt("Pick an armour slot to generate an item for:\\n" + armourSlotToPick.forEach(numInArray));

It produces the same output, because it does the same thing, its just written very differently!

If the array holds "object literals" instead of simply values, as I suggest, the old fashioned code would look something like this:

function contains(a, value) {
    try{
        for (var i = 0; i < a.length; i++) {
            if (a[i].value == value) {
                return true;
            }
        }
    }
    catch(err) {
       // do nothing 
    };
    return false;
}

and later..

for(var j = 0; j < 4; j++){
    for(var i = 0; i < Math.min(armourSlotToPick.length); i++){
        if( contains(armourSlotPicked, armourSlotToPick[i- 1]) )

continue; var messageText = "Generate an item for armour in slot: " + i + "\\n" messageText += armourSlotToPick[i- 1] + "\\n"; }

    var armourPick = prompt(messageText);
    if (armourPick > 0 && armourPick < armourSlotToPick.length) {
        armourSlotPicked.push({"key":j, "value":armourSlotToPick[armourPick]);
    }
    ...
}
//now we have an array that holds information about when what was picked..

or something along those lines.. this is bt.w completely untested, it's just for illustration

Check out my fiddle , I think I have a working solution.

What you really want to be using are Object Literals with your own indexing (starting from 1) - if it were me, I would create my own way to iterate over this custom indexing by adding a method to the Object's prototype, but I digress.

You're overcomplicating your code by using a while loop, and that large bulk of if statements is unnecessary: instead, all you need is some basic validation on the input and then you can just trust whatever input passes this validation. That is demonstrated here:

if ( armourPick > armourSlotToPick.length || armourPick < 1 ) {
    alert("Invalid choice, you suck");
}
else {
    armourSlotPicked.push( armourSlotToPick[armourPick-1] )
    alert (armourSlotPicked[armourSlotPicked.length-1].value);
}

Read my code carefully, and you should get a better understanding of how to deal with certain issues.

EDIT:

As per your request, I think I have a solution that suits your needs. Basically all you have to do to have the arrays "start" at an index of 1 is to fill the zeroth element with a null value, like so:

var armourSlotToPick = [null, "Head", "Chest", "Legs"]
var armourSlotPicked = [null];

You just have to remember to take this null object into account in your code, for example:

if (armourSlotToPick[i] !== null) {
    message += "" + i + "\n"; 
}  

The indices will update automatically. See this updated fiddle for more details.

You want to use the array index to number your items. Since your numbers are one-based and the index is zero-based, you will need to convert between the two when outputting and interpreting the response.

This approach will also allow you to eliminate all but two of the cases in your if-else statement.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM