0

0

如何在 JavaScript 游戏中通过函数嵌套与状态管理实现回合制得分追踪

碧海醫心

碧海醫心

发布时间:2026-02-11 13:54:28

|

251人浏览过

|

来源于php中文网

原创

如何在 JavaScript 游戏中通过函数嵌套与状态管理实现回合制得分追踪

本文详解如何重构“石头剪刀布”游戏,解决因重复调用 `playround()` 导致的逻辑错乱与得分丢失问题,通过参数化设计、单次执行原则和局部变量合理作用域,实现清晰、可维护的回合得分统计机制。

在 JavaScript 初学者开发回合制游戏(如石头剪刀布)时,一个典型误区是:在同一个逻辑上下文中多次调用同一函数,却未保存其返回值。你原始代码中 game() 函数内三次调用 playRound()(一次 console.log,两次用于条件判断),每次调用都会重新执行 getPlayerChoice() 和 getComputerChoice() —— 这不仅造成用户被反复提示输入、电脑选择被重生成,更导致前后不一致的比对结果,使得分判定完全失效。

根本原因在于:playRound() 原本是“自包含型”函数(内部获取输入并返回结果),但 game() 又自行获取了 playerSelection 和 computerSelection,却未将它们传入 playRound(),反而让 playRound() 重复执行——形成逻辑割裂与资源浪费。

✅ 正确解法是践行 “单一职责 + 显式传参 + 单次执行” 原则:

Flowith
Flowith

一款GPT4驱动的节点式 AI 创作工具

下载
  1. playRound() 应专注裁决,不负责输入获取 → 改为接收 playerSelection 和 computerSelection 作为参数;
  2. game() 负责流程控制 → 每轮只调用一次 getPlayerChoice() 和 getComputerChoice(),并将结果传给 playRound();
  3. 得分变量保留在 game() 作用域内(或提升为模块级变量),避免全局污染,同时确保跨轮累积有效。

以下是优化后的核心实现(已修复拼写错误 scrissors → scissors,并增强健壮性):

立即学习Java免费学习笔记(深入)”;

// ✅ 修正拼写:Scrissors → Scissors(全代码统一)
function getPlayerChoice() {
  let playerInput = prompt("Choose rock, paper or scissors.");
  // ? 安全处理:用户点击「取消」时 prompt 返回 null
  if (playerInput === null) {
    alert("Game cancelled. Refresh to restart.");
    return null; // 中断后续流程
  }
  let playerChoice = playerInput.trim().toLowerCase();
  if (playerChoice === "rock") return "Rock";
  if (playerChoice === "paper") return "Paper";
  if (playerChoice === "scissors") return "Scissors";
  alert("Invalid input! Please enter 'rock', 'paper', or 'scissors'.");
  return getPlayerChoice(); // 递归重试(仅限合法输入)
}

function getComputerChoice() {
  const choices = ["Rock", "Paper", "Scissors"];
  return choices[Math.floor(Math.random() * choices.length)];
}

// ✅ playRound 纯裁决函数:只依赖输入参数,返回结构化结果
function playRound(player, computer) {
  if (player === computer) return { result: "tie", message: "It's a tie!" };

  const winConditions = [
    ["Rock", "Scissors"],
    ["Paper", "Rock"],
    ["Scissors", "Paper"]
  ];

  if (winConditions.some(([p, c]) => p === player && c === computer)) {
    return { result: "win", message: `You win! ${player} beats ${computer}.` };
  } else {
    return { result: "lose", message: `You lose. ${computer} beats ${player}.` };
  }
}

// ✅ game:主流程,本地维护 score,每轮只执行一次完整逻辑链
function game() {
  let playerScore = 0;
  let computerScore = 0;

  console.log("? Starting 5-round Rock-Paper-Scissors game...\n");

  for (let round = 1; round <= 5; round++) {
    console.log(`--- Round ${round} ---`);

    const playerSelection = getPlayerChoice();
    if (playerSelection === null) return; // 用户取消,提前退出

    const computerSelection = getComputerChoice();
    const roundResult = playRound(playerSelection, computerSelection);

    console.log(`You chose: ${playerSelection}`);
    console.log(`Computer chose: ${computerSelection}`);
    console.log(roundResult.message);

    // ✅ 基于结构化返回值更新分数(更可靠,避免字符串硬编码匹配)
    if (roundResult.result === "win") {
      playerScore++;
      console.log(`→ Player score: ${playerScore}`);
    } else if (roundResult.result === "lose") {
      computerScore++;
      console.log(`→ Computer score: ${computerScore}`);
    } else {
      console.log(`→ Tie! No points awarded.`);
    }
    console.log("");
  }

  // ? 终局判定
  console.log("? Final Score:");
  console.log(`Player: ${playerScore} | Computer: ${computerScore}`);
  if (playerScore > computerScore) {
    console.log("? You won the game!");
  } else if (playerScore < computerScore) {
    console.log("? You lost the game.");
  } else {
    console.log("? Game ended in a draw!");
  }
  console.log("? Game Over.");
}

// 启动游戏
game();

⚠️ 关键注意事项与进阶建议

  • 避免字符串硬匹配:原方案用 response === "You win..." 判定胜负极易出错(空格、大小写、标点微小差异即失败)。改用对象返回 { result: "win" } 是更健壮、可扩展的设计。
  • 输入容错增强:prompt() 返回 null 时必须显式处理,否则 .toLowerCase() 会抛出 TypeError: Cannot read property 'toLowerCase' of null —— 这正是你遇到的报错根源。
  • 不要滥用递归重试:getPlayerChoice() 中的递归虽能实现重试,但深层调用栈可能引发栈溢出。生产环境推荐用 while 循环替代。
  • 为 HTML 集成预留接口:若后续迁移到网页界面,可将 prompt/alert 替换为 DOM 操作(如 + button),而 playRound() 和得分逻辑完全无需修改 —— 这正是良好函数拆分的价值。
? 总结:函数不是“黑盒”,而是契约。明确每个函数的输入、输出与副作用,是写出可预测、可调试、可复用代码的第一步。得分不是凭空产生,而是由每一次确定的输入 → 确定的裁决 → 确定的状态变更所累积而成。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

243

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

685

2024.03.01

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

101

2023.09.25

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

488

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

214

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1547

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

637

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

841

2024.03.22

2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

68

2026.02.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.9万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.9万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号