NodeJS Tic Tac Toe STDIN冲突

我试图做一个游戏循环运行this.turn()不断获得用户input。 但是当我运行代码时,turn()函数全部运行并且在STDIN中彼此冲突。

在进行下一次迭代和函数调用之前,程序不会停止并等待input。

如何才能在停止并等待input之前进行下一次迭代?

const readline = require('readline'); function TicTacToe () { this.board = []; this.playerTurn = ''; this.state = true; this.intitializeBoard = () => { for ( let i = 0; i < 9; i++ ) { this.board.push(i); } } this.printBoard = () => { for (let i = 0; i < 7; i += 3 ) { console.log(this.board.slice(i, i + 3)); } } this.determineFirstTurn = () => { let result = Math.floor(Math.random() * 2); if ( result == 0 ) { this.playerTurn = 'X'; } else { this.playerTurn = 'O'; } } this.prompt = () => { var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('Enter the number of the square you wish to occupy\n', (input) => { if ( this.board[input] && this.board[input] !== 'X' && this.board[input] !== 'O' ) { this.board[input] = this.playerTurn; rl.close(); } else { console.log("Incorrect input. Try again."); rl.close(); this.prompt(); } }); } this.turn = () => { console.log("Player " + this.playerTurn + "'s Turn"); this.printBoard(); this.prompt(); if ( this.playerTurn == 'X') { this.playerTurn = 'O'; } else { this.playerTurn = 'X'; } } } var game = new TicTacToe(); game.intitializeBoard(); game.determineFirstTurn(); game.board.forEach( () => { game.turn(); }); 

terminal输出:

 Player O's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player X's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player O's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player X's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player O's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player X's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player O's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player X's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy Player O's Turn [ 0, 1, 2 ] [ 3, 4, 5 ] [ 6, 7, 8 ] Enter the number of the square you wish to occupy 222222222222222222 

这是asynchronous代码的典型代码:当调用callback时,您需要继续使用相关代码。

这也可以用承诺来解决:

 this.prompt = () => { var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Promisify the question method: return new Promise( (resolve) => { rl.question('Enter the number of the square you wish to occupy\n', resolve) }) .then((input) => { if ( this.board[input] !== undefined && this.board[input] !== 'X' && this.board[input] !== 'O' ) { this.board[input] = this.playerTurn; rl.close(rl); } else { console.log("Incorrect input. Try again."); return this.prompt(); // Return a new promise } }); } 

然后在turn方法中,你需要把this.prompt()调用作为一个promise,并且向调用者返回一个promise:

 this.turn = () => { console.log("Player " + this.playerTurn + "'s Turn"); this.printBoard(); return this.prompt().then( _ => { if ( this.playerTurn == 'X') { this.playerTurn = 'O'; } else { this.playerTurn = 'X'; } }); } 

最后,在主代码中,您需要将turn的返回值视为promise,并使用reduce而不是forEach来承诺:

 game.board.reduce( prom => prom.then(game.turn), Promise.resolve() ) .then( _ => { console.log('Game over'); game.printBoard(); }); 

注意我纠正了这行代码中的一个问题,当input为0时,这将不能很好地工作

 if ( this.board[input] && ... 

相反:

 if ( this.board[input] !== undefined && ... 

readline.question不是一个阻塞调用,所以程序执行将继续。

创build顺序行为的一种方法是使readline.questioncallback调用下一个回合,即

 this.prompt = () => { var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('Enter the number of the square you wish to occupy\n', (input) => { if ( this.board[input] && this.board[input] !== 'X' && this.board[input] !== 'O' ) { this.board[input] = this.playerTurn; rl.close(); this.turn(); // once we have validated input, move to the next turn } else { console.log("Incorrect input. Try again."); rl.close(); this.prompt(); } }); } 

然后只需打开一次即可开始游戏:

 var game = new TicTacToe(); game.intitializeBoard(); game.determineFirstTurn(); game.turn();