3
var n
var players = []

var rl = readline.createInterface(process.stdin, process.stdout);

rl.question("Enter number of players ", function(answer) {
    //Use number of players to generate array of player names

for (n = 0; n < parseInt(answer); n++) {
    var playerNumber = n + 1
    rl.question("Enter name of player " + playerNumber, function(answer) {
        players.push(answer)});
// stops prompting after asking for name of player 1?
    }

});
    rl.close;
rl.on('close', function(){

console.log("The players are: " + players.toString());
});

This works until “Enter name of player 1”, which the code stores the value of. Code does not prompt the rest of the players. Why?

I also tried replacing it with the ‘for’ loop with a ‘while’ loop, but it came out even worse. It does not even begin prompting for the name of player 1. Why so? Help is appreciated :) thanks everyone

var readline = require('readline');
var n
var players = []

var rl = readline.createInterface(process.stdin, process.stdout);

rl.question("Enter number of players ", function(answer) {
    //Use number of players to generate array of player names

while (n < parseInt(answer)) {
    var playerNumber = n + 1
    rl.question("Enter name of player " + playerNumber, function(answer) {
        players.push(answer)});
    n++;
// does not even start prompting name of player 1?
    }

});
rl.close;
rl.on('close', function(){

console.log("The players are: " + players.toString());
});

Edit: Tried moving rl.close out of the loops. The issue is still the same, this is what shows up in my console:

Enter number of players

(Input) 4

Enter name of player 1

(Input) Player 1

(Console stops prompting, when I tried adding more names and ending the process, the array only stores the name of player 1.)

Jake
  • 33
  • 9

1 Answers1

1

You could solve this using recursion and callbacks:

const readline = require('readline');

var n
var players = []

var rl = readline.createInterface(process.stdin, process.stdout);

function readPlayers(playerCount, playerArr, curr = 0) {
    if (playerCount == curr) {
        rl.close();
        return;
    }

    rl.question("Enter name of player " + (curr + 1) + ": ", function (playerName) {
        playerArr.push(playerName)
        readPlayers(playerCount, playerArr, curr + 1);
    });
}

rl.question("Enter number of players: ", function (answer) {
    //Use number of players to generate array of player names

    readPlayers(parseInt(answer), players);
});

rl.on('close', function () {
    console.log("The players are: " + players.toString());
});

Here rl.close is called only once when the readPlayers end recursion condition is met.

Martín Zaragoza
  • 1,717
  • 8
  • 19
  • The issue is still the same, this is what shows up in my console: Enter number of players (Input) 4 Enter name of player 1 (Input) Player 1 (Console stops prompting, when I tried adding more names and ending the process, the array only stores the name of player 1.) (The brackets aren't part of what shows up in the console.) – Jake Aug 07 '18 at 18:39
  • This worked! Thanks, but I have some more questions.. Why didn't my code work? And why did you write return after rl.close? Does return tell the function to end and prevent it from proceeding? You were very helpful today kind sir. I googled recursion and callbacks and understood them :) Is there any way I can contact you in the future if I need more help? I have upvoted your answer, but I have less than 15 reputation and it doesn't show up :( – Jake Aug 07 '18 at 19:20
  • 2
    @Jake while loops usually block the whole main thread until they are done (synchronous), Martin pretty much created a recursive function that does what you want without blocking the whole main thread. – Kitanga Nday Aug 07 '18 at 19:31
  • 2
    @Jake , i'm calling return after rl.close in order to end the recursive function call (to prevent running the `rl.question("Enter name of player "...` block). – Martín Zaragoza Aug 07 '18 at 19:33
  • @KitangaNday For what I want my code to do, does it matter if my code is synchronous or not? Because the system has to wait for the player input anyway before asking for the next name? Also, I cannot seem to understand how Martin's code is asynchronous. Thanks for your help as well :) – Jake Aug 07 '18 at 19:37
  • @MartínZaragoza I see. Am I able to use break instead? – Jake Aug 07 '18 at 19:39
  • 1
    No. break is used within loops. If you want to "break" a function you must call "return" – Martín Zaragoza Aug 07 '18 at 19:41
  • 1
    @Jake no it doesn't. Actually you would want this to be synchronous (not blocking the thread though). I am quite curious as to what was causing your issue though, did some test and all was good. i can see that your code (Jake) isn't calling `rl.close()`. you forgot the "()". Anywho, have a good day. – Kitanga Nday Aug 07 '18 at 19:44
  • 1
    Oh, and I made a mistake it isn't async, but I assume that that was it. Based on the fact that while loops block the main thread, but as mentioned, I did some tests and found that all was well. – Kitanga Nday Aug 07 '18 at 19:47
  • @MartínZaragoza Understood. I also noticed that you used the var players in players.push(playerName) within the function instead of using the playerArr argument. It should be changed right? var n also seems to be unnecessary. Just putting it out there in case newbies like me come looking at your code – Jake Aug 07 '18 at 19:48
  • 1
    @Jake i've edited the answer. I've also changed the curr argument on the readPlayers function so that it has a 0 default value (when only two arguments are passed) – Martín Zaragoza Aug 07 '18 at 19:52
  • @KitangaNday I copy pasted my initial code in the question. added () to rl.close() and required readline. It does not work for me. Are you sure you didn't change anything else for it to work? – Jake Aug 07 '18 at 19:53
  • 1
    Your code doesn't work, I just run my own interpretation of it using prompt, but then again prompt also blocks the main thread, so should have used something like a function that shows a modal, but then again the question has already been answered. Unless, of course, you still interesting in finding the root of the issue, I'm here to help – Kitanga Nday Aug 07 '18 at 19:59
  • Yes! I still would like to know why my code doesn't work and to avoid the same mistakes in future. I'm assuming modals are used for html and not consoles? Also, my for and while loops seem identical in function, but they produce different results. Why so? – Jake Aug 07 '18 at 20:05
  • 1
    @Jake for loops don't wait for the processes they call to finish running. That plus a whole [bunch of other nonsense](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops.3A_A_common_mistake) that will mess up your code output. – Kitanga Nday Aug 07 '18 at 20:25
  • 1
    btw, I have narrowed down the issue to the fact that we are messing with the DOM. Made a simple test which tried to update the dom with a div I created, nothing popped up. This means that since a while loop blocks the thread, and everything is dependent on that thread (DOM events and manipulation included), then we can safely assume that the DOM is being blocked by our while loop thence your code doesn't work. Now trying to find proof – Kitanga Nday Aug 07 '18 at 20:30
  • 1
    OK, so found something. This [question](https://stackoverflow.com/questions/10809868/js-hangs-on-a-do-while-loop) and this [answer](https://stackoverflow.com/a/10809891/4831083) in said question pretty much says what I said. Nothing will update so long as the loop is running. The for loop on the other hand will run without waiting for any response from user. So it will fire your modal multiple times and only at the end will it actually listen, if it has posted a modal on the screen that it. – Kitanga Nday Aug 07 '18 at 20:39