腾讯面试官:请使用冯诺依曼原理,编写石头剪刀布游戏


theme: yu

前言

在技术驱动的今天,腾讯以其前沿的科技实力吸引着全球的顶尖人才。而在其严格的面试流程中,一道经典而富有深意的题目经常被提及——如何依据冯·诺依曼原理设计并实现一个“石头剪刀布”游戏。此题目的精髓在于,它不仅考验面试者的编程技能,更要求他们对计算机科学的基础——冯·诺依曼体系结构有深刻的理解和应用能力。

正文

题目

请使用冯诺依曼原理,编写石头剪刀布的游戏(三局两胜制)。

解答

冯诺依曼原理

什么是冯诺依曼原理?

冯·诺依曼原理,作为现代计算机体系的基石,主要包含以下几个核心要素:

  • 存储程序:程序指令和数据预先存入存储器中,计算机按序执行。
  • 二进制表示:信息和指令均以二进制形式编码。
  • 中央处理器:包含运算器和控制器,负责执行指令和控制程序流程。
  • 输入输出:与外部世界交换信息。

设计思路

基于上述原理,设计一款“石头剪刀布”游戏,我们首先需将游戏规则、用户输入、计算逻辑以及结果显示等要素映射到冯·诺依曼架构的各个组成部分。

  1. 存储程序与数据:游戏规则:石头胜剪刀,剪刀胜布,布胜石头。用户的选择以及游戏过程中的得分也在运行时动态存储。
  2. 运算器:负责处理游戏逻辑,如比较用户输入与计算机随机生成的选择,根据规则判断胜负,并更新分数。
  3. 控制器:根据程序指令序列,控制游戏流程,包括接收用户输入、调用运算逻辑、判断游戏是否结束以及输出结果。
  4. 输入输出:玩家通过键盘输入选择,程序接收这些输入并反馈游戏结果,如胜利、失败或平局。

编码前的tips

在写代码之前要注意的要点:

  • 要多写注释。
  • 模块化设计,将不同功能进行封装。
  • 代码风格。如:驼峰命名等。

代码实现

  1. 首先需要实现获取用户的输入。

    process.stdin.on('data', (buffer) => {
        const action = buffer.toString().trim();
    })
    

    process.stdin是 Node.js 中代表进程标准输入的对象。这其实是一个事件监听器,当有数据输入时,就会触发回调函数,用action常量接收用户的输入。

    你问buffer是什么?那我们输出一下吧。

    屏幕截图 2024-05-14 231126.png

    buffer是一个二进制数据。

  2. 进行模块化设计,将实现电脑随机猜拳并得出猜拳结果的功能进行封装(不要忘记注释)。

    • 对用户输入的内容进行校验,如果内容不规范就报错。

      /*
      *@func 根据用户输入的参数,输出结果
      *@return  win(1) or lose(-1) or draw(0)
      */
      const game = (action) => {
          const arr = ['rock', 'paper', 'scissors'];
          //输入校验
          if (arr.indexOf(action) == -1) {
              throw new Error('用户输入错误');
          }
      }
      
    • 通过执行Math.floor(Math.random() * 3)可以随机生成0、1、2三数之一。通过数组arr和随机下标,这样就实现了电脑的选择功能。

      /*
      *@func 根据用户输入的参数,输出结果
      *@return win(1) or lose(-1) or draw(0)
      */
      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);
      

      }

    • 对用户和电脑的输出进行判断,并且返回猜拳结果。

      /*
      *@func 根据用户输入的参数,输出结果
      *@return  win(1) or lose(-1) or draw(0)
      */
      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 (action == computerAction) {
          //平局
          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;
      }
      

      }

  3. 实现三局两胜制,对比得分选取出获胜者并且退出游戏。

    let userWinCount = 0;//用户分数
    let computerWinCount = 0;//电脑分数
    

    process.stdin.on(‘data’, (buffer) => {
    const action = buffer.toString().trim();
    const result = game(action);
    if (result == 1) {
    userWinCount++;
    if (userWinCount == 3) {
    console.log(‘恭喜你,你获胜了’);
    process.exit();
    }
    }
    else if (result == -1) {
    computerWinCount++;
    if (computerWinCount == 3) {
    console.log(‘电脑获胜了,你输了’);
    process.exit();
    }
    }
    else {
    console.log(‘平局,再来一局’);
    }
    })

到这里,整体代码就完成了。

完整代码:

let userWinCount = 0;//用户分数
let computerWinCount = 0;//电脑分数

process.stdin.on(‘data’, (buffer) => {
const action = buffer.toString().trim();
const result = game(action);
if (result == 1) {
userWinCount++;
if (userWinCount == 3) {
console.log(‘恭喜你,你获胜了’);
process.exit();
}
}
else if (result == -1) {
computerWinCount++;
if (computerWinCount == 3) {
console.log(‘电脑获胜了,你输了’);
process.exit();
}
}
else {
console.log(‘平局,再来一局’);
}
})

/*
*@func 根据用户输入的参数,输出结果
*@return win(1) or lose(-1) or draw(0)
*/
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 (action == computerAction) {
    //平局
    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;
}

}

检验结果

让我们开启人机大战吧。

eg1:

真是一场酣畅淋漓的对决呀!!!

eg2:

屏幕截图 2024-05-15 000616.png

这都能输!!!!

小结

通过这一面试题,腾讯旨在寻找那些能在平凡中见真章的程序员——他们不仅能够迅速准确地实现功能,还能在细节中展现技术深度与广度。记住,面试不仅是技术的较量,更是心态与应变能力的考验。将每一次挑战视为成长的契机,无论结果如何,都将是你技术生涯中宝贵的一页。


这是一个从 https://juejin.cn/post/7368692841299066934 下的原始话题分离的讨论话题