腾讯面试:用冯诺依曼原理编写猜拳游戏
前言
这篇文章着重想和大家讲讲,大厂的面试和中小厂的面试差异到底在哪里,真的是知识点大家没有掌握全面吗?还是这其中有多少细节是我们没有认清的?
首先我们回归这道题目,这道题目提到了冯诺依曼原理,在大学期间,我们科班同学应该都学过计算机组成原理、计算机网络、操作系统...这一系列课程,事实上,这一系列课程对我们构建计算机基础至关重要。
冯诺依曼原理
- 采用二进制数制:计算机内部的信息表示和运算都采用二进制数字 0 和 1。
- 存储程序控制:程序和数据被事先存储在计算机的存储器中,计算机在执行时能自动地、连续地从存储器中依次取出指令并执行。
- 计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成:
- 运算器:负责进行算术和逻辑运算。
- 控制器:对计算机的各部件进行统一的控制和协调。
- 存储器:用于存储程序和数据。
- 输入设备:将外部信息输入到计算机中。
- 输出设备:将计算机处理的结果输出给用户。
分析题目
既然面试官让我们使用冯诺依曼原理来完成这一简单程序的设计,那么首先猜拳游戏,我们得有人猜拳吧?既然有人猜拳,我们就首先得有输入设备输入我们到底是出拳头还是剪刀还是石头。
- 通过键盘输入设备拿到用户的输入
- 后端运行js,访问输入设备stdin
- 输出设备输出到命令行
process.stdin.on('data', (buffer) => {
// buffer 是一个二进制数据 存储和通信的底层是二进制数据
// console.log(buffer);
const action = buffer.toString().trim()
// console.log(action, '------------');
监听用户在标准输入(stdin)(通常是终端)的输入事件。
当用户输入数据时,会触发 data
事件,此时接收到的 buffer
是一个二进制数据。通过 buffer.toString().trim()
将二进制数据转换为字符串,并去除前后的空格,得到用户输入的有效动作 action
。这为后续的游戏逻辑处理提供了用户的输入信息。
- 接下来就是需要我们转换到业务层了,这边第一个小细节:函数的封装,当代码量大了一些,我们需要将程序封装出去,然后复用,一个是代码的可读性好,一个是程序的可维护性。
/**
* @func 根据用户输入,输出胜或赢
* @return win or lose
*/
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);
computerAction = arr[random];
console.log('电脑出了:' + computerAction);
if (computerAction == action) {
return 0; //平局
} else if (
(action == 'rock' && computerAction == 'scissors')
|| (action == 'paper' && computerAction == 'rock')
|| (action == 'scissors' && computerAction == 'paper')) {
return 1; // 你赢了
} else {
return -1;// 你输了
}
}
- 第二个细节:代码的可读性,多写
注释
,方便自己也贡献他人,代码更加美观与可读。 - 在
业务层
game函数中,我们定义了一个数组,内容为剪刀石头布 - 细节三:
判断用户输入是否合法
,一个好的程序应当经得起检验,而不是来了一个错误的数据我们也不给报错,程序直接忽视这些问题继续执行,这样的程序,当业务越来越大一定会出问题。 - 判断输入是否合法的
逻辑
是:用户输入的内容是否与我们定义好的剪刀石头布一致,得按规矩办事,否则就不给办,通过indexOf方法
可以判断数组中这个值是否存在,如果存在则返回值的下标,如果不存在则返回-1 - 通过随机生成一个索引值
random
值为0~1,*3以后就变成了0~3
,但是这其中会包含小数因此我们可以通过Math.floor方法向下取整得到0-1-2,分别对应数组下标,这样随机获取数组中的剪刀石头布computerAction = arr[random]
- 最后执行我们的逻辑,判断我们输入的action与随机出拳谁获胜的逻辑。
业务逻辑完成之后,我们回到我们的监听事件
,当获胜3局以后就把监听事件结束掉,因此我们可以先定义一个标志winCount
let winCount = 0;
process.stdin.on('data', (buffer) => {
// buffer 是一个二进制数据 存储和通信的底层是二进制数据
// console.log(buffer);
const action = buffer.toString().trim()
// console.log(action, '------------');
// 独立随机出拳业务
const result = game(action)
if (result == 0) {
console.log('平局');
} else if (result == 1) {
console.log('你赢了');
} else {
console.log('你输了');
}
if (result == 1) {
winCount++;
}
if (winCount == 3) {
console.log('恭喜你,你赢了!');
process.exit();
}
})
- 当然,在我编写的这份代码里并没有把所有的情况写全,例如机器人赢的次数,如果机器人赢了3局这个程序也应该结束,我们user赢的次数,大家也可以尽可能的将程序逻辑写的更加丰富。
小结
其实这一整个逻辑过程并不重要,每个游戏每份程序都有自己的业务逻辑,我更想向大家表达的是这里面的各种细节。 例如:
- 进入大厂需要具备什么?扎实的计算机基础,理解计算机的底层逻辑、原理
- 良好的代码习惯,封装复用函数...代码的可读性...
- 严谨的逻辑能力业务能力、程序的健壮性,判断输入是否合法...,如果不合法应该怎么办,直接报错?报错后能否给出提示程序继续向下走?
转载自:https://juejin.cn/post/7368767452614901795