前言
腾讯有一道这样的面试题:“请使用冯诺依曼原理,编写石头剪刀布的游戏”。不少友友看到都蒙了,偶买噶408基础不好算是碰上送命题惹。那么接下来,就由小编来带你一探究竟,你就会发现,其实也是不过如此啦~
冯诺依曼原理
经典的冯·诺依曼架构的计算机由五大部件组成:运算器、控制器、存储器、输入设备和输出设备。基于这一结构编写一个简单的石头剪刀布游戏逻辑,可以理解为在计算机程序中实现,而直接应用冯·诺依曼原理来编写游戏逻辑本身并不直观,因为原理更多是指硬件架构层面,但我们可以遵循这些基本原理来构思程序的流程
思路
用户输入石头或剪子或布,程序再随机输出石头或剪子或布,条件判断用户输赢,赢三次则结束。结合冯诺依曼原理,我们要思考:
- 如何通过输入设备——键盘 拿到用户的输入?
- 如何通过输出设备—— 输出到 命令行?
完整代码
const game = (action) => {
const arr = ['rock', 'paper', 'scissors'];
// 输入校验
if(arr.indexOf(action) === -1) {
throw new Error('用户输入错误');
}
let computerAction;
let random = Math.floor(Math.random() * 3) // [0,3)向下取整
computerAction = arr[random];
console.log('电脑出了' + computerAction);
if (computerAction == action) {
console.log('平局')
return 0; // 平局
} else if (
(computerAction == 'rock' && action == 'scissors') ||
(computerAction == 'scissors' && action == 'paper') ||
(computerAction == 'paper' && action == 'rock')
) {
console.log('你输了')
return -1;
} else {
console.log('你赢了');
return 1;
}
}
let winCount = 0;
process.stdin.on('data', (buffer) => { // 监听标准输入流
const action = buffer.toString().trim(); // trim() 去除首尾空格
const result = game(action)
if(result == 1){
winCount++;
if(winCount == 3){
console.log('不玩了');
process.exit(0); // 退出进程
}
}
})
运行结果
详细解释
process.stdin.on('data', (buffer) => { ... })
:process是后端的进程对象,process.stdin
是标准输入流,.on
监听事件。每当有数据到达时,回调函数接收一个参数 buffer
,它是一个包含接收到的数据的缓冲区对象
buffer.toString().trim()
:将输入流接收到的数据(二进制流)转换为字符串,并 .trim()
方法去除字符串首尾的空白字符,确保不会因为换行符影响对输入字符串后续的条件判断
Math.floor(Math.random() * 3)
:Math.random()
产生随机数[0,1),Math.floor()
对浮点数向下取整。这样才能随机获取0, 1, 2三个数作为数组下标
总结
整个程序被划分成了两个子函数,一个“process.stdin.on('data', (buffer) => { ... })” 用于控制进程的开始和结束,并监听输入流,一个“const game = (action) => {...}” 用于接收用户的输入,直接输出出拳结果。 通过对这个简单小游戏的探索,我们可以知道:
- process是后端的进程对象,进程是资源分配的最小单元,运行任何一个程序都要有一个依赖冯诺依曼计算设备的process对象
- 良好的编程无法脱离计算机的底层原理,存储和通信的底层是二进制
- 良好的代码是模块化的,本例中独立的出拳业务就被封装成了一个函数
- 有输入,就要做输入校验,防止用户的错误操作破坏我们的进程
关注我,让我们努力学好408,以后一起玩更高级的游戏嘿嘿~