|
|
class TypingLogic:
|
|
|
def __init__(self, learning_content: str):
|
|
|
"""
|
|
|
初始化打字逻辑状态。。。。
|
|
|
- 存储学习材料
|
|
|
- 初始化当前索引为0
|
|
|
- 初始化错误计数为0
|
|
|
"""
|
|
|
self.learning_content = learning_content
|
|
|
self.current_index = 0
|
|
|
self.error_count = 0
|
|
|
self.total_chars = len(learning_content)
|
|
|
self.typed_chars = 0
|
|
|
|
|
|
def check_input(self, user_text: str) -> dict:
|
|
|
"""
|
|
|
检查用户输入与学习材料的匹配情况
|
|
|
- 逐字符比较逻辑
|
|
|
- 进度跟踪
|
|
|
- 准确率计算
|
|
|
- 返回字典包含:
|
|
|
* correct: 布尔值,当前输入是否正确
|
|
|
* expected: 字符串,当前期望的字符
|
|
|
* position: 整数,当前位置
|
|
|
* completed: 布尔值,是否完成
|
|
|
* accuracy: 浮点数,准确率
|
|
|
"""
|
|
|
# 保存当前索引用于返回
|
|
|
current_position = len(user_text)
|
|
|
|
|
|
# 临时保存原始的typed_chars值用于准确率计算
|
|
|
original_typed_chars = self.typed_chars
|
|
|
|
|
|
# 更新已输入字符数
|
|
|
self.typed_chars = len(user_text)
|
|
|
|
|
|
# 如果用户输入的字符数超过了学习材料的长度,截取到相同长度
|
|
|
if len(user_text) > self.total_chars:
|
|
|
user_text = user_text[:self.total_chars]
|
|
|
current_position = len(user_text)
|
|
|
|
|
|
# 检查当前输入是否正确
|
|
|
correct = True
|
|
|
expected_char = ''
|
|
|
if self.current_index < self.total_chars:
|
|
|
expected_char = self.learning_content[self.current_index]
|
|
|
if len(user_text) > self.current_index and user_text[self.current_index] != expected_char:
|
|
|
correct = False
|
|
|
else:
|
|
|
# 已经完成所有输入
|
|
|
# 恢复原始的typed_chars值用于准确率计算
|
|
|
accuracy = self._calculate_accuracy()
|
|
|
self.typed_chars = original_typed_chars
|
|
|
return {
|
|
|
"correct": True,
|
|
|
"expected": "",
|
|
|
"position": self.current_index,
|
|
|
"completed": True,
|
|
|
"accuracy": accuracy
|
|
|
}
|
|
|
|
|
|
# 检查是否完成
|
|
|
completed = current_position >= self.total_chars
|
|
|
|
|
|
# 计算准确率
|
|
|
accuracy = self._calculate_accuracy()
|
|
|
# 恢复原始的typed_chars值
|
|
|
self.typed_chars = original_typed_chars
|
|
|
|
|
|
return {
|
|
|
"correct": correct,
|
|
|
"expected": expected_char,
|
|
|
"position": current_position,
|
|
|
"completed": completed,
|
|
|
"accuracy": accuracy
|
|
|
}
|
|
|
|
|
|
def update_position(self, user_text: str):
|
|
|
"""
|
|
|
更新当前索引和错误计数
|
|
|
- 根据用户输入更新当前位置
|
|
|
- 计算并更新错误计数
|
|
|
"""
|
|
|
new_position = len(user_text)
|
|
|
|
|
|
# 计算新增的错误数
|
|
|
for i in range(self.current_index, min(new_position, self.total_chars)):
|
|
|
if user_text[i] != self.learning_content[i]:
|
|
|
self.error_count += 1
|
|
|
|
|
|
# 更新当前索引
|
|
|
self.current_index = new_position
|
|
|
|
|
|
def get_expected_text(self, length: int = 10) -> str:
|
|
|
"""
|
|
|
获取用户接下来应该输入的内容
|
|
|
- 返回从当前位置开始的一定长度文本(如10个字符)
|
|
|
- 处理文本结束情况
|
|
|
"""
|
|
|
start_pos = self.current_index
|
|
|
end_pos = min(start_pos + length, self.total_chars)
|
|
|
return self.learning_content[start_pos:end_pos]
|
|
|
|
|
|
def get_progress(self) -> dict:
|
|
|
"""
|
|
|
获取当前学习进度统计
|
|
|
- current: 整数,当前位置
|
|
|
- total: 整数,总长度
|
|
|
- percentage: 浮点数,完成百分比
|
|
|
- remaining: 整数,剩余字符数
|
|
|
"""
|
|
|
current = self.current_index
|
|
|
total = self.total_chars
|
|
|
percentage = (current / total * 100) if total > 0 else 0
|
|
|
remaining = max(0, total - current)
|
|
|
|
|
|
return {
|
|
|
"current": current,
|
|
|
"total": total,
|
|
|
"percentage": percentage,
|
|
|
"remaining": remaining
|
|
|
}
|
|
|
|
|
|
def reset(self, new_content: str = None):
|
|
|
"""
|
|
|
重置打字状态
|
|
|
- 重置当前索引为0
|
|
|
- 重置错误计数
|
|
|
- 如果提供了新内容,更新学习材料
|
|
|
"""
|
|
|
if new_content is not None:
|
|
|
self.learning_content = new_content
|
|
|
self.total_chars = len(new_content)
|
|
|
self.current_index = 0
|
|
|
self.error_count = 0
|
|
|
self.typed_chars = 0
|
|
|
|
|
|
def get_statistics(self) -> dict:
|
|
|
"""
|
|
|
获取打字统计信息
|
|
|
- total_chars: 整数,总字符数
|
|
|
- typed_chars: 整数,已输入字符数
|
|
|
- error_count: 整数,错误次数
|
|
|
- accuracy_rate: 浮点数,准确率
|
|
|
"""
|
|
|
return {
|
|
|
"total_chars": self.total_chars,
|
|
|
"typed_chars": self.typed_chars,
|
|
|
"error_count": self.error_count,
|
|
|
"accuracy_rate": self._calculate_accuracy()
|
|
|
}
|
|
|
|
|
|
def _calculate_accuracy(self) -> float:
|
|
|
"""
|
|
|
计算准确率
|
|
|
"""
|
|
|
# 防止递归的保护措施
|
|
|
if hasattr(self, '_calculating_accuracy') and self._calculating_accuracy:
|
|
|
return 0.0
|
|
|
|
|
|
if self.typed_chars == 0:
|
|
|
return 0.0
|
|
|
|
|
|
# 设置递归保护标志
|
|
|
self._calculating_accuracy = True
|
|
|
|
|
|
try:
|
|
|
# 准确率 = (已输入字符数 - 错误次数) / 已输入字符数
|
|
|
accuracy = (self.typed_chars - self.error_count) / self.typed_chars
|
|
|
return max(0.0, min(1.0, accuracy)) # 确保准确率在0.0到1.0之间
|
|
|
except (ZeroDivisionError, RecursionError):
|
|
|
return 0.0
|
|
|
finally:
|
|
|
# 清除递归保护标志
|
|
|
self._calculating_accuracy = False |