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.question
callback调用下一个回合,即
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();