面试官最爱问的业务逻辑:《石头、剪刀、布》— 冯·诺依曼原理下的人机对决
在腾讯的面试中给出过这样一道题:根据冯诺·依曼原理,编写出一个三局两胜制的剪刀石头布游戏。
很多人一听当场就蒙了,冯·诺依曼是谁啊,冯·诺伊曼原理又是啥啊?没关系,这又没在面试呢,咱不知道还不能百度么,于是:
冯诺依曼理论要点:
1、计算机硬件设备由存储器、运算器、控制器、输入设备和输出设备5部分组成。
2、存储程序思想——把计算过程描述为由许多命令按一定顺序组成的程序,然后把程序和数据一起输入计算机,计算机对已存入的程序和数据处理后,输出结果。
3、美籍匈牙利科学家冯·诺依曼最先提出程序存储的思想,并成功将其运用在计算机的设计之中,根据这一原理制造的计算机被称为冯·诺依曼结构计算机,由于他对现代计算机技术的突出贡献,因此冯·诺依曼又被称为“计算机之父”。
简单来说这道题考察的就是我们对计算机底层原理的熟知程度,良好代码所必需的模块化,业务逻辑中不可缺少的参数校验方面。
游戏设计思路:
输入:玩家在终端输入rock
、scissors
、paper
,通过键盘拿到玩家的输入。
处理:终端接收到数据,随机生成rock
、scissors
、paper
中的一个对抗玩家,根据游戏规则判断输赢或平局。
输出:显示游戏结果,累计玩家与电脑的胜负次数,当一方胜利次数到达2时,宣布获胜者。
完整代码:
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) {
console.log("平局!");
return 0;
}else if (computerAction == "rock" && action == "scissors" ||
computerAction == "paper" && action == "rock" ||
computerAction == "scissors" && action == "paper") {
console.log("你输了!");
return 'lose';
}else {
console.log("你赢了!");
return 'win';
}
}
let winCount = 0;
let loseCount = 0;
process.stdin.on('data', (buffer) => {
const action = buffer.toString().trim();
const result = game(action);
if (result === 'win') {
winCount++;
if (winCount === 2) {
console.log('你赢得了比赛!');
process.exit();
}
} else if (result === 'lose') {
loseCount++;
if (loseCount === 2) {
console.log('电脑赢得了比赛!');
process.exit();
}
}
})
代码说明:
首先建立一个game
函数去接收参数action
,action
为玩家在数组const arr=["rock", "paper", "scissors"]
中选择的一个行动,同时在这个地方设置了参数校验,如果玩家输入的并非数组中的元素,则抛出错误:“用户输入错误”。
const game = (action) => {
const arr=["rock", "paper", "scissors"];
if (arr.indexOf(action) == -1) {
throw new Error("用户输入错误");
}
玩家做出了行动,相应的电脑几乎同时也做出了行动行动,此处通过生成一个随机数 random
来确定计算机选择的动作。
let random = Math.floor(Math.random()*3);
computerAction = arr[random];
console.log("电脑出了"+computerAction);
根据玩家与电脑做出的行动,电脑给出以下三种判断,分别是"平局!"、"你输了!"、"你赢了!",需要注意的是,题目给出的是设计一个三局两胜制的猜拳游戏,于是我们又分别设立winCount
、loseCount
两个计时器,分别计数胜利局数和失败局数。
if (computerAction == action) {
console.log("平局!");
return 0;
}else if (computerAction == "rock" && action == "scissors" ||
computerAction == "paper" && action == "rock" ||
computerAction == "scissors" && action == "paper") {
console.log("你输了!");
return -1;
}else {
console.log("你赢了!");
return 1;
}
}
let winCount = 0;
let loseCount = 0;
后端运行 js 访问输出设备stdin,当用户输入时触发回调函数,最终当任意一方的计数器达到2时,宣布获胜者,并结束整个进程。
if (result === 'win') {
winCount++;
if (winCount === 2) {
console.log('你赢得了比赛!');
process.exit();
}
} else if (result === 'lose') {
loseCount++;
if (loseCount === 2) {
console.log('电脑赢得了比赛!');
process.exit();
}
}
开始游戏:
游戏开始,通过终端输入我们的选择,当我们赢得两场次时,电脑宣布玩家的胜利,至此,游戏运行成功!

总结:
正如开头所说,面试考察这种业务逻辑方面题,最重要的就是看我们对计算机底层原理的熟知程度,比如在这个游戏中,就包括了随机数生成和基本的条件判断。同时做到模块化编程,多使用函数来组织和封装游戏的逻辑。模块化设计的目的就是展现我们所写代码的可读性和可维护性。良好的模块化能够将复杂的问题分解为更小的可管理的部分。最后一点就是业务逻辑中的最基本也是最容易忽视的参数校验,用来规范代码的输入。
转载自:https://juejin.cn/post/7385832570183450662