为了打发无聊的时间,小蓝开发了一款人机对战的猜硬币游戏,页面中一共有 9 个杯子,系统会随机挑选 3 个杯子在里面放入硬币,玩家通过输入含有杯子序号的字符串进行猜选,但是遇到了一些问题。 本题需要你帮助小蓝完成猜硬币游戏。
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css
├── effect.gif
├── images
├── index.html
└── js
├── findCoin.js
└── index.js
其中:
css
是样式文件夹。images
是图片文件夹。index.html
是主页面。js/index.js
是硬币渲染和动画逻辑。js/findCoin.js
是需要补充代码的 js 文件。effect.gif
是最终实现的效果图。注意:打开环境后发现缺少项目代码,请手动键入下述命令进行下载:
cd /home/project
wget https://labfile.oss.aliyuncs.com/courses/9790/04.zip && unzip 04.zip && rm 04.zip
在浏览器中预览 index.html
页面效果如下:
请在
js/findCoin.js
文件中补全findNum
和randomCoin
函数代码,最终实现猜硬币游戏。 具体需求如下:
1-9
的数字,并根据数字打开对应的杯子。 完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
/**
* @param {*} input_values input 框中输入的值
* @returns Array 将输入的值中 1-9 组成一个数组
*/
// 将输入的值中 1-9 组成一个数组
function findNum(input_values) {
// TODO:待补充代码
return input_values.replace(/[^0-9]/g,'').split('').map(Number)
}
// 将 1-9 中三个不重复的随机数放入数组中,并返回这个数组
let randomCoin = () => {
let randomNumArr = [];
// TODO:待补充代码
let set = new Set()
while(set.size < 3){
let ran = Math.ceil((Math.random()*9))
set.add(ran)
}
randomNumArr = [...set]
return randomNumArr;
};
// 请勿删除和修改下面代码
try {
module.exports = { randomCoin, findNum };
} catch (e) {}
<!DOCTYPE html>
<html>
<head>
<title>猜硬币</title>
<meta charset="utf-8" />
<link href="./css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="content">
<p id="gameText"></p>
<ul></ul>
<div class="killout">
<label for="killoutInput" style="color: #999">
说明:填入序号,填入你猜测有硬币的杯子,可以输入任意值,只要输入的值中包含
"1-9",就会根据对应的数字打开杯子<br />
<input
id="killoutInput"
type="text"
placeholder="填写你需要查找的位置序号"
/>
</label>
</div>
<div class="btnbox">
<button class="btn">确定</button>
</div>
<p id="result"></p>
</div>
<script src="./js/findCoin.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
<!DOCTYPE html>
:声明文档类型为 HTML5。<title>
标签:设置页面标题为 “猜硬币”。<meta charset="utf-8">
:设置页面的字符编码为 UTF-8。<link>
标签:引入外部的 CSS 文件 style.css
,用于设置页面的样式。<div id="content">
:页面的主要容器,包含了游戏的所有元素。<p id="gameText">
:用于显示游戏的提示信息或结果信息。<ul>
:用于显示杯子的列表。<div class="killout">
:包含了游戏的说明文本和输入框,用户可以在输入框中输入猜测有硬币的杯子序号。<input id="killoutInput">
:用户输入猜测的杯子序号的输入框。<div class="btnbox">
:包含了一个按钮,用于触发游戏的操作。<button class="btn">
:按钮,初始文本为 “确定”,点击后执行相应的游戏逻辑。<p id="result">
:可能用于显示游戏的结果(当前代码中未充分使用)。<script src="./js/findCoin.js"></script>
和 <script src="./js/index.js"></script>
:引入了两个外部的 JavaScript 文件,用于实现游戏的逻辑。html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
font,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend {
margin: 0;
padding: 0;
font-size: 100%;
border: 0;
outline: 0;
background: transparent;
}
ol,
ul {
list-style: none;
}
:focus {
outline: 0;
}
#content {
padding-top: 40px;
}
#content ul {
margin: 0 auto;
width: 70%;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.btnbox {
width: 100%;
margin: 0 auto;
text-align: center;
}
#content ul li {
margin: 20px;
width: 8vw;
height: 8vw;
}
#content ul li:last-child {
margin-right: 0;
}
#content ul li a {
position: relative;
display: block;
width: 100%;
height: 100%;
perspective: 800px;
}
#content ul li a > div {
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
color: #fff;
overflow: hidden;
transform-style: preserve-3d;
transition: 0.8s ease-in-out;
backface-visibility: hidden;
}
#content ul li a div:first-child {
display: flex;
justify-content: center;
transform: rotateY(0);
z-index: 2;
}
#content ul li a div:last-child {
position: relative;
display: block;
width: 100%;
height: 100%;
perspective: 800px;
}
#content ul li a > div {
width: 100%;
height: 100%;
color: #fff;
transition: 0.8s ease-in-out;
backface-visibility: hidden;
}
#content ul li a div:first-child {
display: flex;
justify-content: center;
z-index: 2;
}
#content ul li a div h1 {
text-align: center;
line-height: 90px;
font-size: 12px;
}
#content ul li a div img {
max-width: 100%;
}
.rotatey30 {
transform: translate(0, -15px) rotate(-30deg) !important;
}
.btn,
.btn-all {
margin-top: 60px;
display: inline-block;
color: #0099cc;
background: #2e7eee;
border-radius: 10px;
text-decoration: none;
text-transform: uppercase;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
transition-duration: 0.4s;
cursor: pointer;
}
.cardnum {
position: absolute;
font-size: 12px;
left: 45%;
top: 10px;
}
#gameText,
#result {
text-align: center;
padding-bottom: 20px;
}
.killout {
text-align: center;
}
.killout input {
display: inline-block;
}
.z {
position: relative;
}
.z .cup,
.b .cup {
transform: rotate(180deg);
display: inline-block;
transition: all 1s ease-in-out;
}
.coin {
position: absolute;
width: 30px;
height: auto;
left: 50%;
bottom: 0;
z-index: -1;
}
sup {
text-align: center;
line-height: 20px;
width: 20px;
height: 20px;
position: absolute;
font-size: 12px;
z-index: 10000;
color: #fff;
left: 50%;
top: 50%;
margin-left: -5px;
margin-top: -10px;
border-radius: 50%;
}
#killoutInput {
width: 200px;
margin-top: 40px;
box-sizing: border-box;
font-variant: tabular-nums;
list-style: none;
position: relative;
display: inline-block;
padding: 4px 11px;
color: #000000d9;
font-size: 14px;
line-height: 1.5715;
background-color: #fff;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 2px;
transition: all 0.3s;
}
#content
:设置顶部内边距为 40px。#content ul
:设置列表的宽度为 70%,居中显示,使用弹性盒模型布局,使杯子列表可以自动换行并居中对齐。#content ul li
:设置每个杯子的外边距、宽度和高度,使用视口宽度单位 vw
来适应不同屏幕尺寸。#content ul li a
:设置杯子的定位和透视效果,为 3D 动画做准备。#content ul li a > div
:设置杯子的内部元素的定位、颜色、溢出处理、3D 转换样式和过渡效果,以及背面不可见。.rotatey30
:定义了一个动画类,用于将杯子旋转一定角度,模拟打开杯子的效果。.btn
和 .btn-all
:设置按钮的样式,包括颜色、背景、边框、内边距、文本样式和过渡效果。#gameText
和 #result
:设置文本的对齐方式和底部内边距。.killout
和 .killout input
:设置游戏说明和输入框的样式。.z
和 .z .cup
:设置杯子的定位和旋转样式。.coin
:设置硬币的定位和样式。sup
:设置杯子上序号的样式。#killoutInput
:设置输入框的样式,包括宽度、内边距、颜色、边框和过渡效果。//index.js
// 初始化页面效果
let cardList;
let init = () => {
cardList = [];
// 根据随机数组生成硬币位置
let gendercarlist = () => {
let arr = randomCoin();
for (let index = 0; index < 9; index++) {
cardList.push({
id: index + 1,
category: `nomoney`,
name: "空",
});
}
for (let index = 0; index < arr.length; index++) {
const item = arr[index];
cardList[item - 1].category = "money";
cardList[item - 1].name = "硬币";
}
return cardList;
};
let content = document.querySelector("#content ul");
cardList = gendercarlist();
content.innerHTML = "";
for (let index = 0; index < cardList.length; index++) {
let oneCard = cardList[index];
content.innerHTML += `<li>
<a href="javascript:void(0)">
<div class="z">
<img class='cup' src="./images/cup.svg">
<sup>${index + 1}</sup>
</div>
${
oneCard.category == "money"
? `<img class='coin' src="./images/coin.svg">`
: ""
}
</a>
</li>`;
}
};
init();
let gameText = document.querySelector("#gameText");
let btnbox = document.querySelector(".btn");
let select_input = document.getElementById("killoutInput");
let ul = document.getElementsByTagName("ul")[0];
let flag = true;
// 点击确定按钮的逻辑
btnbox.addEventListener("click", function () {
flag = !flag;
if (flag) {
this.innerHTML = "确定";
select_input.value = "";
gameText.innerHTML = ``;
init();
} else {
this.innerHTML = "重置";
let select_values = select_input.value;
let res = findNum(select_values); // 找到输入值中 1-9 的数字
let result = cardList.filter((item) => res.includes(item.id));
let length = result.filter((item) => item.category == "money").length;
if (length) {
gameText.innerHTML = `恭喜你,找到了${length}个硬币`;
} else {
gameText.innerHTML = `很遗憾,没有找到硬币`;
}
// 打开杯子
annimateCard(select_values);
}
});
// 给选择的杯子添加动画
function annimateCard(select_values) {
let domz = document.querySelectorAll(".z");
let res = findNum(select_values);
for (let index = 0; index < domz.length; index++) {
if (res.includes(index + 1)) {
domz[index].classList.add("rotatey30");
}
}
}
init
: cardList
数组,用于存储每个杯子的信息。gendercarlist
函数生成硬币的随机位置。cardList
,根据每个杯子是否有硬币,动态生成 HTML 结构并添加到页面的 <ul>
元素中。#gameText
、.btn
、#killoutInput
和 <ul>
元素,用于后续的操作和交互。flag
变量,用于判断按钮的状态(确定或重置)。flag
为 true
时,将按钮文本设置为 “确定”,清空输入框和游戏提示信息,重新初始化游戏。flag
为 false
时,将按钮文本设置为 “重置”,获取输入框的值,调用 findNum
函数提取输入值中 1-9 的数字。cardList
,统计找到的硬币数量,并根据结果更新游戏提示信息。annimateCard
函数,根据输入的数字为对应的杯子添加旋转动画,模拟打开杯子的效果。annimateCard
: findNum
函数提取输入值中 1-9 的数字。rotatey30
类,触发旋转动画。/**
* @param {*} input_values input 框中输入的值
* @returns Array 将输入的值中 1-9 组成一个数组
*/
// 将输入的值中 1-9 组成一个数组
function findNum(input_values) {
// TODO:待补充代码
return input_values.replace(/[^0-9]/g,'').split('').map(Number)
}
// 将 1-9 中三个不重复的随机数放入数组中,并返回这个数组
let randomCoin = () => {
let randomNumArr = [];
// TODO:待补充代码
let set = new Set()
while(set.size < 3){
let ran = Math.ceil((Math.random()*9))
set.add(ran)
}
randomNumArr = [...set]
return randomNumArr;
};
// 请勿删除和修改下面代码
try {
module.exports = { randomCoin, findNum };
} catch (e) {}
还有这段
findNum
函数
/**
* @param {*} input_values input 框中输入的值
* @returns Array 将输入的值中 1-9 组成一个数组
*/
// 将输入的值中 1-9 组成一个数组
function findNum(input_values) {
// TODO:待补充代码
return input_values.replace(/[^0-9]/g,'').split('').map(Number)
}
findNum
函数的作用是从用户在输入框中输入的值中提取出 1 到 9 的数字,并将这些数字组成一个数组返回。input_values.replace(/[^0-9]/g,'')
:使用正则表达式 /[^0-9]/g
,[^0-9]
表示匹配除了数字(0 到 9)之外的任意字符,g
是全局匹配标志。replace
方法将输入值中所有非数字字符替换为空字符串,这样就得到了只包含数字的字符串。.split('')
:将得到的只包含数字的字符串拆分成单个字符组成的数组,例如字符串 "123"
会被拆分成 ["1", "2", "3"]
。.map(Number)
:使用 map
方法遍历数组中的每个元素,将每个元素(字符串形式的数字)转换为数字类型。例如 ["1", "2", "3"]
会被转换为 [1, 2, 3]
。randomCoin
函数
// 将 1-9 中三个不重复的随机数放入数组中,并返回这个数组
let randomCoin = () => {
let randomNumArr = [];
// TODO:待补充代码
let set = new Set()
while(set.size < 3){
let ran = Math.ceil((Math.random()*9))
set.add(ran)
}
randomNumArr = [...set]
return randomNumArr;
};
randomCoin
函数的作用是从 1 到 9 的数字中随机选取三个不重复的数字,并将这三个数字组成一个数组返回,用于模拟硬币随机放置的位置。let set = new Set()
:创建一个 Set
对象,Set
是 JavaScript 中的一种数据结构,它的特点是存储的元素唯一,不会有重复值。while(set.size < 3)
:当 Set
对象中的元素数量小于 3 时,进入循环。let ran = Math.ceil((Math.random()*9))
:生成一个 1 到 9 之间的随机整数。Math.random()
会返回一个大于等于 0 且小于 1 的随机小数,乘以 9 后得到一个大于等于 0 且小于 9 的随机小数,再使用 Math.ceil()
方法对这个小数向上取整,就得到了 1 到 9 之间的一个随机整数。set.add(ran)
:将生成的随机整数添加到 Set
对象中。由于 Set
的元素唯一性,重复的数字不会被添加进去。randomNumArr = [...set]
:当 Set
对象中元素数量达到 3 个时,使用扩展运算符 ...
将 Set
对象转换为数组,并赋值给 randomNumArr
。randomNumArr
数组。模块导出部分
// 请勿删除和修改下面代码
try {
module.exports = { randomCoin, findNum };
} catch (e) {}
这部分代码的作用是将 randomCoin
和 findNum
这两个函数导出,以便在其他模块中可以导入和使用这两个函数。module.exports
是 Node.js 中用于导出模块成员的方式,通过这种方式,其他文件可以使用 require
函数来引入这两个函数并调用。try-catch
块用于捕获可能出现的错误,即使在导出过程中出现异常,也不会导致程序崩溃。
四、工作流程▶️