
在学习javascript并尝试构建一个简单的“剪刀石头布”游戏时,开发者常常会利用confirm和prompt等浏览器内置函数与用户进行交互。然而,这些函数在特定场景下的行为特性,如果处理不当,可能会导致一些意料之外的问题。本教程将针对两个常见问题进行深入分析和修复,以帮助您构建一个更健壮、更完整的游戏。
问题一:prompt输入处理不当
原始代码在用户点击prompt对话框的“确定”按钮但未输入任何内容时,以及点击“取消”按钮时,都未能正确地引导用户或处理输入。具体表现为:
- 当用户未输入任何内容直接点击“确定”时,期望提示“你没有选择r, p, s”,但实际并未出现。
- 当用户点击“取消”时,期望提示“改变主意了?没关系”,但可能也未能正确触发。
问题分析:
prompt函数在不同操作下的返回值有所不同:
- 如果用户输入内容并点击“确定”,它返回用户输入的字符串。
- 如果用户未输入任何内容但点击“确定”,它返回一个空字符串 ""。
- 如果用户点击“取消”,它返回 null。
在JavaScript中,null和空字符串 "" 都被认为是“假值”(falsy values)。因此,原始代码中的 if (startgame) 条件在用户点击“确定”但未输入,或者点击“取消”时,都会被评估为 false,导致逻辑分支未能按预期执行。
立即学习“Java免费学习笔记(深入)”;
解决方案:
我们需要区分用户是点击了“取消”还是点击了“确定”但输入为空。
- 对于点击“取消”的情况,startgame 将是 null。
- 对于点击“确定”但输入为空的情况,startgame 将是 ""。
我们可以通过检查 startgame !== null 来判断用户是否点击了“取消”,然后进一步检查 playerchoice 是否为空或无效。
示例代码:
let playgame = confirm("Do you want to play game?");
if (playgame) {
let startgame = prompt("Choose from r, p, s?");
// 检查用户是否点击了“取消”
if (startgame !== null) { // 用户没有点击“取消”
let playerchoice = startgame.trim().toLowerCase(); // 清除空格并转小写
// 检查玩家输入是否有效
if (playerchoice === "r" || playerchoice === "s" || playerchoice === "p") {
// 游戏核心逻辑
// ... (此处省略,将在问题二中详细说明)
} else {
// 用户输入无效(包括空字符串)
alert("你没有选择 r, p, s");
}
} else {
// 用户点击了“取消”
alert("改变主意了?没关系");
}
} else {
alert("下次再玩吧!");
}注意事项:
- trim() 方法用于去除字符串两端的空白字符,这有助于处理用户可能输入的空格。
- toLowerCase() 方法将输入转换为小写,确保大小写不敏感的比较。
- 更完善的输入验证可以结合 while 循环,直到用户输入有效内容为止。
问题二:游戏胜负判断逻辑不完整
原始代码在判断游戏结果时,只覆盖了平局和部分玩家获胜的情况,导致许多对战组合未能正确判定胜负,有时甚至需要重复输入才能看到结果。
问题分析:
剪刀石头布游戏有九种可能的对战组合(玩家出拳3种 × 电脑出拳3种):
| 玩家出拳 | 电脑出拳 | 结果 |
|---|---|---|
| r (石头) | r (石头) | 平局 |
| r (石头) | p (布) | 电脑获胜 |
| r (石头) | s (剪刀) | 玩家获胜 |
| p (布) | r (石头) | 玩家获胜 |
| p (布) | p (布) | 平局 |
| p (布) | s (剪刀) | 电脑获胜 |
| s (剪刀) | r (石头) | 电脑获胜 |
| s (剪刀) | p (布) | 玩家获胜 |
| s (剪刀) | s (剪刀) | 平局 |
原始代码只处理了平局,以及 playerchoice === "p" && computer === "r" 和 playerchoice === "s" && computer === "p" 这两种玩家获胜的情况。它错误地将 playerchoice === "r" && computer === "s" 判断为电脑获胜,并且遗漏了所有电脑获胜的情况。
解决方案:
我们需要使用 if...else if...else 结构来确保所有可能的对战结果都被正确覆盖,并且逻辑是互斥的。
示例代码:
// ... (接问题一的输入处理代码)
if (playerchoice === "r" || playerchoice === "s" || playerchoice === "p") {
// 电脑随机选择
let compchoiceNum = Math.floor(Math.random() * 3); // 0, 1, 2
let computer;
if (compchoiceNum === 0) {
computer = "r";
} else if (compchoiceNum === 1) {
computer = "p"; // 修正:原来是s,应该对应p
} else { // compchoiceNum === 2
computer = "s"; // 修正:原来是p,应该对应s
}
// 提示电脑的选择
alert(`玩家选择了: ${playerchoice.toUpperCase()}\n电脑选择了: ${computer.toUpperCase()}`);
// 判断胜负
if (playerchoice === computer) {
alert("平局!");
} else if (
(playerchoice === "r" && computer === "s") || // 石头胜剪刀
(playerchoice === "p" && computer === "r") || // 布胜石头
(playerchoice === "s" && computer === "p") // 剪刀胜布
) {
alert("玩家获胜!");
} else {
// 其他所有情况都是电脑获胜
alert("电脑获胜!");
}
} else {
alert("你没有选择 r, p, s");
}
// ... (接问题一的输入处理代码)代码修正说明:
-
电脑选择修正: Math.floor(Math.random() * 3) 会生成 0, 1, 2。为了与 'r', 'p', 's' 对应,我们重新分配了值:
- 0 对应 'r'
- 1 对应 'p'
- 2 对应 's'
- 这样可以更清晰地将数字映射到选项。
-
胜负判断逻辑:
- 首先判断平局。
- 然后使用 else if 判断玩家获胜的所有组合。
- 最后使用 else 语句,覆盖所有剩余情况,即电脑获胜。这种结构确保了逻辑的完整性和互斥性。
- 增加提示: 在判断结果前,先提示玩家和电脑各自的选择,可以增强游戏的互动性。
完整优化后的代码示例
将上述两部分的修复合并,可以得到一个更完善的剪刀石头布游戏代码:
let playgame = confirm("你想玩游戏吗?");
if (playgame) {
let isValidInput = false;
let playerchoice;
// 使用循环确保玩家输入有效
while (!isValidInput) {
let startgame = prompt("请选择:r (石头), p (布), s (剪刀)");
if (startgame === null) { // 用户点击了“取消”
alert("改变主意了?没关系,下次再玩。");
playgame = false; // 退出游戏
break; // 退出循环
}
playerchoice = startgame.trim().toLowerCase();
if (playerchoice === "r" || playerchoice === "s" || playerchoice === "p") {
isValidInput = true; // 输入有效,退出循环
} else {
alert("无效输入。请选择 r, p, 或 s。");
}
}
if (playgame) { // 只有当用户没有取消游戏时才继续
// 电脑随机选择
const compchoiceNum = Math.floor(Math.random() * 3); // 0, 1, 2
let computer;
if (compchoiceNum === 0) {
computer = "r";
} else if (compchoiceNum === 1) {
computer = "p";
} else {
computer = "s";
}
// 提示玩家和电脑的选择
alert(`你选择了: ${playerchoice.toUpperCase()}\n电脑选择了: ${computer.toUpperCase()}`);
// 判断胜负
if (playerchoice === computer) {
alert("平局!");
} else if (
(playerchoice === "r" && computer === "s") || // 石头胜剪刀
(playerchoice === "p" && computer === "r") || // 布胜石头
(playerchoice === "s" && computer === "p") // 剪刀胜布
) {
alert("恭喜你,玩家获胜!");
} else {
alert("很遗憾,电脑获胜!");
}
}
} else {
alert("下次再玩吧!");
}总结
通过本教程,我们解决了JavaScript剪刀石头布游戏中常见的两个问题:prompt输入处理的健壮性以及游戏胜负判断逻辑的完整性。关键在于理解prompt在不同用户操作下的返回值,并利用if...else if...else结构确保所有游戏逻辑分支都被正确覆盖。此外,引入输入验证循环和清晰的提示信息,能够显著提升用户体验和代码的可靠性。这些改进不仅修复了现有问题,也为构建更复杂的交互式Web应用奠定了基础。










