-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
296 lines (254 loc) · 10.1 KB
/
Copy pathscript.js
File metadata and controls
296 lines (254 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
// 不同难度级别的练习文本 - 连续故事
const practiceTexts = {
easy: [
"从前有一只胖猫。",
"它的名字叫大橘。",
"大橘很喜欢吃饭。",
"有一天,它吃了很多鱼。",
"然后它遇见了一只狗。",
"狗的名字叫小黑。",
"小黑看起来很凶。",
"大橘却不怕它。",
"它们开始一起玩。",
"最后成了好朋友。"
],
medium: [
"大橘是一只非常胖的猫。",
"它每天最喜欢做的事就是吃东西。",
"有一天,主人给了它一大碗鱼罐头。",
"大橘狼吞虎咽地吃完了所有的鱼。",
"吃饱后,它摇摇晃晃地走到院子里。",
"突然,它看到一只黑色的狗正在翻垃圾桶。",
"小黑狗看到大橘,立刻露出了锋利的牙齿。",
"大橘却不害怕,反而向小黑狗走去。",
"它从口袋里掏出一块剩下的鱼干递给小黑。",
"小黑狗闻了闻,开心地吃了起来,它们成了朋友。"
],
hard: [
"在一个阳光明媚的下午,大橘猫正躺在沙发上晒太阳。",
"主人走过来,手里拿着它最喜欢的三文鱼罐头。",
"大橘立刻跳起来,眼睛直勾勾地盯着罐头。",
"它狼吞虎咽地吃完了整碗三文鱼,肚子撑得圆滚滚的。",
"吃饱喝足后,大橘决定到院子里散步消化一下。",
"刚走到门口,它就看到一只陌生的黑狗正在翻垃圾桶。",
"黑狗听到声音,猛地转过头,露出了尖锐的牙齿。",
"大橘吓了一跳,但很快发现黑狗只是饿了。",
"它想起口袋里还有主人给的小鱼干,于是掏出来递给黑狗。",
"黑狗犹豫了一下,然后小心翼翼地接过鱼干吃了起来。",
"吃完后,黑狗对大橘摇了摇尾巴,表示感谢。",
"从那天开始,黑狗每天都会来院子里找大橘玩。",
"它们一起追逐蝴蝶,一起晒太阳,成了最好的朋友。",
"有一天,大橘不小心从树上摔了下来,腿受伤了。",
"黑狗看到后,立刻跑回家叼来了主人的药箱。",
"主人帮大橘包扎好伤口后,大橘和黑狗的友谊更加深厚了。",
"现在,它们每天都形影不离,一起度过快乐的时光。"
]
};
// DOM 元素
const elements = {
levelBtns: document.querySelectorAll('.level-btn'),
targetText: document.getElementById('target-text'),
userInput: document.getElementById('user-input'),
startBtn: document.getElementById('start-btn'),
nextBtn: document.getElementById('next-btn'),
resetBtn: document.getElementById('reset-btn'),
time: document.getElementById('time'),
accuracy: document.getElementById('accuracy'),
speed: document.getElementById('speed'),
feedback: document.getElementById('feedback'),
feedbackTitle: document.getElementById('feedback-title'),
feedbackMessage: document.getElementById('feedback-message'),
feedbackBtn: document.getElementById('feedback-btn')
};
// 游戏状态
let gameState = {
currentLevel: 'easy',
currentText: '',
startTime: 0,
endTime: 0,
isPlaying: false,
correctChars: 0,
totalChars: 0,
currentIndex: 0 // 当前练习文本的索引
};
// 初始化
function init() {
setupEventListeners();
updateTargetText();
}
// 设置事件监听器
function setupEventListeners() {
// 难度选择按钮
elements.levelBtns.forEach(btn => {
btn.addEventListener('click', () => {
if (gameState.isPlaying) return;
elements.levelBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
gameState.currentLevel = btn.dataset.level;
gameState.currentIndex = 0; // 切换难度后从第一题开始
updateTargetText();
});
});
// 开始按钮
elements.startBtn.addEventListener('click', startGame);
// 重置按钮
elements.resetBtn.addEventListener('click', resetGame);
// 用户输入
elements.userInput.addEventListener('input', handleUserInput);
// 回车键处理
elements.userInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && gameState.isPlaying) {
const userInput = elements.userInput.value;
const targetText = gameState.currentText;
// 检查输入是否正确
if (userInput === targetText) {
// 输入正确,结束游戏并进入下一题
endGame();
// 短暂延迟后自动进入下一题
setTimeout(() => {
// 隐藏反馈弹窗
elements.feedback.classList.remove('show');
// 进入下一题
nextQuestion();
}, 1500); // 1.5秒延迟,让用户有足够时间看到反馈
} else {
// 输入错误,显示错误提示
alert('输入错误,请重新输入!');
// 保留当前步骤,不进入下一题
}
}
});
// 反馈按钮
elements.feedbackBtn.addEventListener('click', resetGame);
// 下一步按钮
elements.nextBtn.addEventListener('click', () => {
if (!gameState.isPlaying) {
// 隐藏反馈弹窗
elements.feedback.classList.remove('show');
// 进入下一题
nextQuestion();
}
});
}
// 更新目标文本
function updateTargetText() {
const texts = practiceTexts[gameState.currentLevel];
// 确保索引在有效范围内
gameState.currentIndex = gameState.currentIndex % texts.length;
gameState.currentText = texts[gameState.currentIndex];
elements.targetText.textContent = gameState.currentText;
}
// 开始游戏
function startGame() {
gameState.isPlaying = true;
gameState.startTime = Date.now();
gameState.correctChars = 0;
gameState.totalChars = 0;
elements.userInput.disabled = false;
elements.userInput.value = '';
elements.userInput.focus();
elements.startBtn.disabled = true;
elements.nextBtn.disabled = true;
elements.resetBtn.disabled = false;
// 开始计时
startTimer();
}
// 重置游戏
function resetGame() {
gameState.isPlaying = false;
gameState.currentIndex = 0; // 重置为第一题
elements.userInput.disabled = true;
elements.userInput.value = '';
elements.startBtn.disabled = false;
elements.nextBtn.disabled = true;
elements.resetBtn.disabled = true;
elements.time.textContent = '0s';
elements.accuracy.textContent = '0%';
elements.speed.textContent = '0 WPM';
updateTargetText();
// 隐藏反馈
elements.feedback.classList.remove('show');
}
// 开始计时
function startTimer() {
function updateTime() {
if (!gameState.isPlaying) return;
const elapsedTime = Math.floor((Date.now() - gameState.startTime) / 1000);
elements.time.textContent = `${elapsedTime}s`;
requestAnimationFrame(updateTime);
}
updateTime();
}
// 处理用户输入
function handleUserInput() {
if (!gameState.isPlaying) return;
const userInput = elements.userInput.value;
const targetText = gameState.currentText;
// 计算正确率
gameState.totalChars = userInput.length;
gameState.correctChars = 0;
for (let i = 0; i < userInput.length; i++) {
if (i < targetText.length && userInput[i] === targetText[i]) {
gameState.correctChars++;
}
}
const accuracy = gameState.totalChars > 0 ? Math.round((gameState.correctChars / gameState.totalChars) * 100) : 0;
elements.accuracy.textContent = `${accuracy}%`;
// 计算速度(WPM - 每分钟单词数)
const elapsedTime = (Date.now() - gameState.startTime) / 1000 / 60; // 转换为分钟
const words = userInput.length / 5; // 假设平均每个单词5个字符
const wpm = elapsedTime > 0 ? Math.round(words / elapsedTime) : 0;
elements.speed.textContent = `${wpm} WPM`;
}
// 结束游戏
function endGame() {
gameState.isPlaying = false;
gameState.endTime = Date.now();
const elapsedTime = Math.floor((gameState.endTime - gameState.startTime) / 1000);
const accuracy = Math.round((gameState.correctChars / gameState.totalChars) * 100);
const words = gameState.currentText.length / 5;
const wpm = Math.round(words / (elapsedTime / 60));
// 更新显示
elements.time.textContent = `${elapsedTime}s`;
elements.accuracy.textContent = `${accuracy}%`;
elements.speed.textContent = `${wpm} WPM`;
// 启用下一步按钮
elements.nextBtn.disabled = false;
// 显示反馈
showFeedback(elapsedTime, accuracy, wpm);
}
// 进入下一题
function nextQuestion() {
// 增加当前索引,进入下一题
gameState.currentIndex++;
// 更新目标文本
updateTargetText();
// 开始新游戏
startGame();
}
// 显示反馈
function showFeedback(time, accuracy, speed) {
// 根据成绩生成不同的反馈
let title = '练习完成!';
let message = '';
if (accuracy >= 90 && speed >= 20) {
title = '太棒了!🎉';
message = `用时 ${time} 秒\n正确率 ${accuracy}%\n速度 ${speed} WPM\n你是打字小高手!`;
} else if (accuracy >= 70 && speed >= 10) {
title = '做得不错!👏';
message = `用时 ${time} 秒\n正确率 ${accuracy}%\n速度 ${speed} WPM\n继续加油!`;
} else {
title = '继续努力!💪';
message = `用时 ${time} 秒\n正确率 ${accuracy}%\n速度 ${speed} WPM\n多练习会更好!`;
}
elements.feedbackTitle.textContent = title;
elements.feedbackMessage.textContent = message;
elements.feedback.classList.add('show');
// 添加庆祝动画
elements.feedback.classList.add('celebrate');
setTimeout(() => {
elements.feedback.classList.remove('celebrate');
}, 500);
}
// 初始化游戏
init();