js --pro1猜数字

60 阅读2分钟

Project1-猜数字

command + S,保存文件; command + k,清空终端 按cl并空格自动转成console.log(); 字符串拼接用 +=;

给定1-20的随机数字,用户猜测是什么数字,根据大小给予用户提示是太大还是太小,初始给一个20的分数,每错一次减1,当分数到0游戏失败。

1、鲁棒性检查

let secretNumber = Math.trunc(Math.random() * 20) + 1; //1-20
let score = 20;
console.log(`secretNumber is ${secretNumber}`);
//给check按钮添加事件处理,传入动作(点击)和函数两个参数(函数也是一种值,可以作为实参被传递),我们先直接在该函数参数里写函数体。
//当用户点击按钮,就会触发该点击事件,它会执行函数,函数应该先进行鲁棒性检查,再对比输入的数字与secret数字。
document.querySelector('.btn.check').addEventListener('click', function () {
  //⚠️我们在html的input标签中指定了输入类型得是number,所以用户无法输入字符,但可以啥也不输入
  //所以鲁棒性只需检查:用户是否输入了
  //⚠️从页面传入的内容都是string类型!所以若用户什么也没输入,传入的是''
  //所以我们的思路:先对传入的字符串检查是否为空字符串,再转换成Number类型比较大小
  //注意为什么不要先转换再检查鲁棒性,因为''转换成Number类型会变成0,就无法和输入的数字0区分了。

  //鲁棒性检查:
  const userInput = document.querySelector('.guess').value; //input元素的内容用.value去获取
  console.log(userInput, typeof userInput);
  if (userInput === '') {
    document.querySelector('.message').textContent = '🈲 No Number!';
    return;
  }

2、处理游戏失败

结论:游戏失败的条件是score <==1;而不是score <==0!在代码中,为了防止游戏失败后用户继续点击check导致score继续变化,我们把判断是否继续游戏的条件写成score <==1,总而言之,记住,能写成<== 或>==就写成。

额外:游戏胜利和失败游戏都应该结束,就不能再猜了,为了实现这个,增加一个变量playing = true;当游戏胜利或失败,设置为false,只有playing为true,两个主函数的逻辑才能继续

//转换成Number:
  const guess = Number(userInput);
  //先构建三种情况下score的变化和UI的更新,再考虑怎么处理游戏失败。
  //⚠️⚠️当分数到0时游戏失败,但这里有个注意点:
  //游戏失败的节点应该是:当score为1时(仅剩1次机会),用户再次check,但依然错误。
  //代码运行逻辑上则是:用户点击check,事件执行函数,发现猜测的数字又不对,进入过大或过小分支
  //然后检查score,发现<==1(用<==1,防止归零后用户还点击check),那么进行游戏失败的相关更新;
  //否则游戏继续(指进行猜测数字过大/过小的更新)

  if (guess === secretNumber) {
   //猜对了,score不需更新,只有猜错了,score-1 document.querySelector('.message').textContent = '🎉 Correct Number!';
    document.querySelector('.number').textContent = secretNumber;
    //在css中,写作backgroud-color,但js中需写成驼峰法:
    document.querySelector('body').style.backgroundColor = '#60b347'; //需写成字符串
    document.querySelector('.number').style.width = '30rem'; //
  }
  if (guess < secretNumber) {
    if (score <= 1) {
      //游戏失败
      //不是<=0!
      document.querySelector('.message').textContent = '💥 You lost the game!';
      document.querySelector('.score').textContent = 0; //直接更新成0.
    } else {
      //score > 1
      document.querySelector('.message').textContent = '📉 Too low!!';
      score--;
      document.querySelector('.score').textContent = score;
      return;
    }
  }
  if (guess > secretNumber) {
    if (score <= 1) {
      //游戏失败
      //you
      document.querySelector('.message').textContent = '💥 You lost the game!';
      document.querySelector('.score').textContent = 0;
    } else {
      document.querySelector('.message').textContent = 'Bigger!!';
      score--;
      document.querySelector('.score').textContent = score;
      return;
    }
  }
});


先说直觉版(人类思维):

游戏有 20 分,每猜错一次扣 1 分。

当分数变成 0,说明你没机会了 → 游戏结束。

所以你脑子里是这么想的:

“只要分数大于 0,我就还能再猜;

当我按下按钮并扣到 0 的那一刻,我就输了。”


🧠再说程序版(计算机思维):

计算机不会主动知道“这是你最后一次机会”

它只会在你点击按钮那一刻执行一次事件函数。

逻辑顺序是这样的:

  1. 你点击“Check!”

  2. 程序执行函数体(一次判断流程)

  3. 在函数执行期间:

    • 它先去检查你输入的数字;
    • 再去看你当前的分数;
    • 再决定是否还要继续游戏(继续游戏指的是处理过大/过小)。 换句话说,对程序而言:

游戏失败”不是当 score <== 0 时触发的,

而是当本轮操作将要让分数变成 0时触发的。

计算机要提前一步识别“下一个状态就是失败”, 而如果判断写成 score <== 0:

  • 当 score === 1 时,程序会进入“继续”分支(处理过大/过小);
  • 扣完分后 score 变成 0;
  • 但本轮已经执行完毕,没有再去检查;
  • 结果就是:你已经输了,但游戏界面还没提示失败。

3.重置游戏

//重新开始游戏
document.querySelector('.btn.again').addEventListener('click', function () {
  //重置变量:随机数、分数
  secretNumber = Math.trunc(Math.random() * 20) + 1; //1-20
  score = 20;
  console.log(`secretNumber is ${secretNumber}`);
  //重置html:
  document.querySelector('.message').textContent = 'Start guessing...';
  document.querySelector('.score').textContent = 20;
  document.querySelector('.guess').value = '';
  document.querySelector('.number').textContent = '?';
  //重置css:
  document.querySelector('body').style.backgroundColor = '#222';
  document.querySelector('.number').style.width = '15rem';
});

4.最高分

只需游戏结束的时候更新最高分:但游戏失败代表分数扣到0了,所以没必要更新最高分,因为0肯定<=最高分;所以只需要在猜对的时候,取当前最高分和当前分数更高的那个到最高分里,并更新html。 更新最高分,不仅要更新变量,也要更新html.

5.重构:不要重复自己原则

重构1-把两个几乎相同的分支合并为一个

  //重构1,把两个几乎相同的分支合并为一个:过大过小两个分支只有Too high/Too low文本更新不一样
  if (guess !== secretNumber) {
    if (score <= 1) {
      document.querySelector('.message').textContent = '💥 You lost the game!';
      document.querySelector('.score').textContent = 0; //直接更新成0.
    } else {
      document.querySelector('.message').textContent =
        guess > secretNumber ? '📈 Too High' : '📉 Too low';
      score--;
      document.querySelector('.score').textContent = score;
    }
  }

重构2-构造函数消除重复

对message 文本元素的更新出现了很多行:

Screenshot 2025-11-09 at 10.44.46 AM.png 还有对number文本元素的更新也是,生成随机数也是,所以我们构造函数去更新这些html文本和生成随机数。

const displayMessage = function (message) {
  document.querySelector('.message').textContent = message;
};
const displayNumber = function (number) {
  document.querySelector('.number').textContent = number;
};
const createSecretNumber = function () {
  return Math.trunc(Math.random() * 20) + 1; //1-20
};

let secretNumber = createSecretNumber(); //Math.trunc(Math.random() * 20) + 1; //1-20
let score = 20;
let highScore = 0;
console.log(`secretNumber is ${secretNumber}`);