style: 代码格式化
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
from .sm2 import SM2Algorithm
|
||||
|
||||
__all__ = [
|
||||
'SM2Algorithm',
|
||||
"SM2Algorithm",
|
||||
]
|
||||
|
||||
algorithms = {
|
||||
"SM-2": SM2Algorithm,
|
||||
"supermemo2": SM2Algorithm,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import heurams.services.timer as timer
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class BaseAlgorithm:
|
||||
algo_name = "BaseAlgorithm"
|
||||
|
||||
class AlgodataDict(TypedDict):
|
||||
efactor: float
|
||||
real_rept: int
|
||||
real_rept: int
|
||||
rept: int
|
||||
interval: int
|
||||
last_date: int
|
||||
@@ -15,31 +16,33 @@ class BaseAlgorithm:
|
||||
last_modify: float
|
||||
|
||||
defaults = {
|
||||
'real_rept': 0,
|
||||
'rept': 0,
|
||||
'interval': 0,
|
||||
'last_date': 0,
|
||||
'next_date': 0,
|
||||
'is_activated': 0,
|
||||
'last_modify': timer.get_timestamp()
|
||||
"real_rept": 0,
|
||||
"rept": 0,
|
||||
"interval": 0,
|
||||
"last_date": 0,
|
||||
"next_date": 0,
|
||||
"is_activated": 0,
|
||||
"last_modify": timer.get_timestamp(),
|
||||
}
|
||||
|
||||
|
||||
@classmethod
|
||||
def revisor(cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False) -> None:
|
||||
def revisor(
|
||||
cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False
|
||||
) -> None:
|
||||
"""迭代记忆数据"""
|
||||
pass
|
||||
|
||||
|
||||
@classmethod
|
||||
def is_due(cls, algodata) -> int:
|
||||
"""是否应该复习"""
|
||||
return 1
|
||||
|
||||
|
||||
@classmethod
|
||||
def rate(cls, algodata) -> str:
|
||||
"""获取评分信息"""
|
||||
return ""
|
||||
|
||||
|
||||
@classmethod
|
||||
def nextdate(cls, algodata) -> int:
|
||||
"""获取下一次记忆时间戳"""
|
||||
return -1
|
||||
return -1
|
||||
|
||||
@@ -1 +1 @@
|
||||
# FSRS 算法模块, 尚未就绪
|
||||
# FSRS 算法模块, 尚未就绪
|
||||
|
||||
@@ -2,12 +2,13 @@ from .base import BaseAlgorithm
|
||||
import heurams.services.timer as timer
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class SM2Algorithm(BaseAlgorithm):
|
||||
algo_name = "SM-2"
|
||||
|
||||
class AlgodataDict(TypedDict):
|
||||
efactor: float
|
||||
real_rept: int
|
||||
real_rept: int
|
||||
rept: int
|
||||
interval: int
|
||||
last_date: int
|
||||
@@ -16,66 +17,72 @@ class SM2Algorithm(BaseAlgorithm):
|
||||
last_modify: float
|
||||
|
||||
defaults = {
|
||||
'efactor': 2.5,
|
||||
'real_rept': 0,
|
||||
'rept': 0,
|
||||
'interval': 0,
|
||||
'last_date': 0,
|
||||
'next_date': 0,
|
||||
'is_activated': 0,
|
||||
'last_modify': timer.get_timestamp()
|
||||
"efactor": 2.5,
|
||||
"real_rept": 0,
|
||||
"rept": 0,
|
||||
"interval": 0,
|
||||
"last_date": 0,
|
||||
"next_date": 0,
|
||||
"is_activated": 0,
|
||||
"last_modify": timer.get_timestamp(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def revisor(cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False):
|
||||
"""SM-2 算法迭代决策机制实现
|
||||
根据 quality(0 ~ 5) 进行参数迭代最佳间隔
|
||||
quality 由主程序评估
|
||||
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数
|
||||
@classmethod
|
||||
def revisor(
|
||||
cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False
|
||||
):
|
||||
"""SM-2 算法迭代决策机制实现
|
||||
根据 quality(0 ~ 5) 进行参数迭代最佳间隔
|
||||
quality 由主程序评估
|
||||
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数
|
||||
"""
|
||||
if feedback == -1:
|
||||
return
|
||||
|
||||
algodata[cls.algo_name]['efactor'] = algodata[cls.algo_name]['efactor'] + (
|
||||
algodata[cls.algo_name]["efactor"] = algodata[cls.algo_name]["efactor"] + (
|
||||
0.1 - (5 - feedback) * (0.08 + (5 - feedback) * 0.02)
|
||||
)
|
||||
algodata[cls.algo_name]['efactor'] = max(1.3, algodata[cls.algo_name]['efactor'])
|
||||
algodata[cls.algo_name]["efactor"] = max(
|
||||
1.3, algodata[cls.algo_name]["efactor"]
|
||||
)
|
||||
|
||||
if feedback < 3:
|
||||
algodata[cls.algo_name]['rept'] = 0
|
||||
algodata[cls.algo_name]['interval'] = 0
|
||||
algodata[cls.algo_name]["rept"] = 0
|
||||
algodata[cls.algo_name]["interval"] = 0
|
||||
else:
|
||||
algodata[cls.algo_name]['rept'] += 1
|
||||
algodata[cls.algo_name]["rept"] += 1
|
||||
|
||||
algodata[cls.algo_name]['real_rept'] += 1
|
||||
algodata[cls.algo_name]["real_rept"] += 1
|
||||
|
||||
if is_new_activation:
|
||||
algodata[cls.algo_name]['rept'] = 0
|
||||
algodata[cls.algo_name]['efactor'] = 2.5
|
||||
algodata[cls.algo_name]["rept"] = 0
|
||||
algodata[cls.algo_name]["efactor"] = 2.5
|
||||
|
||||
if algodata[cls.algo_name]['rept'] == 0:
|
||||
algodata[cls.algo_name]['interval'] = 1
|
||||
elif algodata[cls.algo_name]['rept'] == 1:
|
||||
algodata[cls.algo_name]['interval'] = 6
|
||||
if algodata[cls.algo_name]["rept"] == 0:
|
||||
algodata[cls.algo_name]["interval"] = 1
|
||||
elif algodata[cls.algo_name]["rept"] == 1:
|
||||
algodata[cls.algo_name]["interval"] = 6
|
||||
else:
|
||||
algodata[cls.algo_name]['interval'] = round(
|
||||
algodata[cls.algo_name]['interval'] * algodata[cls.algo_name]['efactor']
|
||||
algodata[cls.algo_name]["interval"] = round(
|
||||
algodata[cls.algo_name]["interval"] * algodata[cls.algo_name]["efactor"]
|
||||
)
|
||||
|
||||
algodata[cls.algo_name]['last_date'] = timer.get_daystamp()
|
||||
algodata[cls.algo_name]['next_date'] = timer.get_daystamp() + algodata[cls.algo_name]['interval']
|
||||
algodata[cls.algo_name]['last_modify'] = timer.get_timestamp()
|
||||
|
||||
algodata[cls.algo_name]["last_date"] = timer.get_daystamp()
|
||||
algodata[cls.algo_name]["next_date"] = (
|
||||
timer.get_daystamp() + algodata[cls.algo_name]["interval"]
|
||||
)
|
||||
algodata[cls.algo_name]["last_modify"] = timer.get_timestamp()
|
||||
|
||||
@classmethod
|
||||
def is_due(cls, algodata):
|
||||
return (algodata[cls.algo_name]['next_date'] <= timer.get_daystamp())
|
||||
|
||||
return algodata[cls.algo_name]["next_date"] <= timer.get_daystamp()
|
||||
|
||||
@classmethod
|
||||
def rate(cls, algodata):
|
||||
return str(algodata[cls.algo_name]['efactor'])
|
||||
|
||||
return str(algodata[cls.algo_name]["efactor"])
|
||||
|
||||
@classmethod
|
||||
def nextdate(cls, algodata) -> int:
|
||||
return algodata[cls.algo_name]['next_date']
|
||||
return algodata[cls.algo_name]["next_date"]
|
||||
|
||||
@@ -21,4 +21,4 @@ __all__ = [
|
||||
"load_nucleon",
|
||||
"load_electron",
|
||||
"atom_registry",
|
||||
]
|
||||
]
|
||||
|
||||
@@ -9,6 +9,7 @@ import json
|
||||
import bidict
|
||||
from heurams.context import config_var
|
||||
|
||||
|
||||
class AtomRegister(TypedDict):
|
||||
nucleon: Nucleon
|
||||
nucleon_path: pathlib.Path
|
||||
@@ -21,7 +22,8 @@ class AtomRegister(TypedDict):
|
||||
orbital_fmt: str
|
||||
runtime: dict
|
||||
|
||||
class Atom():
|
||||
|
||||
class Atom:
|
||||
"""
|
||||
统一处理一系列对象的所有信息与持久化:
|
||||
关联电子 (算法数据)
|
||||
@@ -30,11 +32,11 @@ class Atom():
|
||||
以及关联路径
|
||||
"""
|
||||
|
||||
def __init__(self, ident = ""):
|
||||
def __init__(self, ident=""):
|
||||
self.ident = ident
|
||||
atom_registry[ident] = self
|
||||
# self.is_evaled = False
|
||||
self.registry: AtomRegister = { # type: ignore
|
||||
self.registry: AtomRegister = { # type: ignore
|
||||
"nucleon": None,
|
||||
"nucleon_path": None,
|
||||
"nucleon_fmt": "toml",
|
||||
@@ -42,7 +44,7 @@ class Atom():
|
||||
"electron_path": None,
|
||||
"electron_fmt": "json",
|
||||
"orbital": None,
|
||||
"orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置
|
||||
"orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置
|
||||
"orbital_fmt": "toml",
|
||||
}
|
||||
self.do_eval()
|
||||
@@ -53,16 +55,17 @@ class Atom():
|
||||
self.do_eval()
|
||||
else:
|
||||
raise ValueError("不受支持的原子元数据链接操作")
|
||||
|
||||
|
||||
def do_eval(self):
|
||||
"""
|
||||
执行并以结果替换当前单元的所有 eval 语句
|
||||
TODO: 带有限制的 eval, 异步/多线程执行避免堵塞
|
||||
"""
|
||||
|
||||
# eval 环境设置
|
||||
def eval_with_env(s: str):
|
||||
try:
|
||||
nucleon = self.registry['nucleon']
|
||||
nucleon = self.registry["nucleon"]
|
||||
default = config_var.get()["puzzles"]
|
||||
metadata = nucleon.metadata
|
||||
except:
|
||||
@@ -72,7 +75,7 @@ class Atom():
|
||||
except Exception as e:
|
||||
ret = f"此 eval 实例发生错误: {e}"
|
||||
return ret
|
||||
|
||||
|
||||
def traverse(data, modifier):
|
||||
if isinstance(data, dict):
|
||||
for key, value in data.items():
|
||||
@@ -89,10 +92,9 @@ class Atom():
|
||||
if data.startswith("eval:"):
|
||||
return modifier(data[5:])
|
||||
return data
|
||||
|
||||
|
||||
traverse(self.registry["nucleon"], eval_with_env)
|
||||
traverse(self.registry["orbital"], eval_with_env)
|
||||
|
||||
|
||||
def persist(self, key):
|
||||
path: pathlib.Path | None = self.registry[key + "_path"]
|
||||
@@ -109,7 +111,7 @@ class Atom():
|
||||
raise KeyError("不受支持的持久化格式")
|
||||
else:
|
||||
raise TypeError("对未初始化的路径对象操作")
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key in self.registry:
|
||||
return self.registry[key]
|
||||
@@ -124,5 +126,6 @@ class Atom():
|
||||
@staticmethod
|
||||
def placeholder():
|
||||
return (Electron.placeholder(), Nucleon.placeholder(), {})
|
||||
|
||||
|
||||
|
||||
atom_registry: bidict.bidict[str, Atom] = bidict.bidict()
|
||||
|
||||
@@ -2,12 +2,13 @@ import heurams.services.timer as timer
|
||||
from heurams.context import config_var
|
||||
from heurams.kernel.algorithms import algorithms
|
||||
|
||||
|
||||
class Electron:
|
||||
"""电子: 记忆分析元数据及算法"""
|
||||
|
||||
def __init__(self, ident: str, algodata: dict = {}, algo_name: str = "supermemo2"):
|
||||
"""初始化电子对象 (记忆数据)
|
||||
|
||||
|
||||
Args:
|
||||
ident: 算法的唯一标识符, 用于区分不同的算法实例, 使用 algodata[ident] 获取
|
||||
algodata: 算法数据字典, 包含算法的各项参数和设置
|
||||
@@ -28,34 +29,34 @@ class Electron:
|
||||
|
||||
def activate(self):
|
||||
"""激活此电子"""
|
||||
self.algodata[self.algo]['is_activated'] = 1
|
||||
self.algodata[self.algo]['last_modify'] = timer.get_timestamp()
|
||||
self.algodata[self.algo]["is_activated"] = 1
|
||||
self.algodata[self.algo]["last_modify"] = timer.get_timestamp()
|
||||
|
||||
def modify(self, var: str, value):
|
||||
"""修改 algodata[algo] 中子字典数据"""
|
||||
if var in self.algodata[self.algo]:
|
||||
self.algodata[self.algo][var] = value
|
||||
self.algodata[self.algo]['last_modify'] = timer.get_timestamp()
|
||||
self.algodata[self.algo]["last_modify"] = timer.get_timestamp()
|
||||
else:
|
||||
print(f"警告: '{var}' 非已知元数据字段")
|
||||
|
||||
def is_due(self):
|
||||
"""是否应该复习"""
|
||||
return self.algo.is_due(self.algodata)
|
||||
|
||||
|
||||
def is_activated(self):
|
||||
return self.algodata[self.algo]['is_activated']
|
||||
|
||||
return self.algodata[self.algo]["is_activated"]
|
||||
|
||||
def rate(self):
|
||||
"评价"
|
||||
return self.algo.rate(self.algodata)
|
||||
|
||||
|
||||
def nextdate(self) -> int:
|
||||
return self.algo.nextdate(self.algodata)
|
||||
|
||||
def revisor(self, quality: int = 5, is_new_activation: bool = False):
|
||||
"""算法迭代决策机制实现
|
||||
|
||||
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数 (0-5)
|
||||
is_new_activation (bool): 是否为初次激活
|
||||
@@ -93,7 +94,7 @@ class Electron:
|
||||
if key == "ident":
|
||||
raise AttributeError("ident 应为只读")
|
||||
self.algodata[self.algo][key] = value
|
||||
self.algodata[self.algo]['last_modify'] = timer.get_timestamp()
|
||||
self.algodata[self.algo]["last_modify"] = timer.get_timestamp()
|
||||
|
||||
def __len__(self):
|
||||
"""仅返回当前算法的配置数量"""
|
||||
@@ -102,4 +103,4 @@ class Electron:
|
||||
@staticmethod
|
||||
def placeholder():
|
||||
"""生成一个电子占位符"""
|
||||
return Electron("电子对象样例内容", {})
|
||||
return Electron("电子对象样例内容", {})
|
||||
|
||||
@@ -6,17 +6,18 @@ import toml
|
||||
import json
|
||||
from copy import deepcopy
|
||||
|
||||
def load_nucleon(path: pathlib.Path, fmt = "toml"):
|
||||
|
||||
def load_nucleon(path: pathlib.Path, fmt="toml"):
|
||||
with open(path, "r") as f:
|
||||
dictdata = dict()
|
||||
dictdata = toml.load(f) # type: ignore
|
||||
dictdata = toml.load(f) # type: ignore
|
||||
lst = list()
|
||||
nested_data = dict()
|
||||
# 修正 toml 解析器的不管嵌套行为
|
||||
for key, value in dictdata.items():
|
||||
if "__metadata__" in key: # 以免影响句号
|
||||
if '.' in key:
|
||||
parts = key.split('.')
|
||||
if "__metadata__" in key: # 以免影响句号
|
||||
if "." in key:
|
||||
parts = key.split(".")
|
||||
current = nested_data
|
||||
for part in parts[:-1]:
|
||||
if part not in current:
|
||||
@@ -29,23 +30,31 @@ def load_nucleon(path: pathlib.Path, fmt = "toml"):
|
||||
for item, attr in nested_data.items():
|
||||
if item == "__metadata__":
|
||||
continue
|
||||
lst.append((Nucleon(hasher.hash(item), attr, deepcopy(nested_data['__metadata__'])), deepcopy(nested_data["__metadata__"]["orbital"])))
|
||||
lst.append(
|
||||
(
|
||||
Nucleon(
|
||||
hasher.hash(item), attr, deepcopy(nested_data["__metadata__"])
|
||||
),
|
||||
deepcopy(nested_data["__metadata__"]["orbital"]),
|
||||
)
|
||||
)
|
||||
return lst
|
||||
|
||||
def load_electron(path: pathlib.Path, fmt = "json") -> dict:
|
||||
|
||||
def load_electron(path: pathlib.Path, fmt="json") -> dict:
|
||||
"""从文件路径加载电子对象
|
||||
|
||||
Args:
|
||||
path (pathlib.Path): 路径
|
||||
fmt (str): 文件格式(可选, 默认 json)
|
||||
|
||||
|
||||
Returns:
|
||||
dict: 键名是电子对象名称, 值是电子对象
|
||||
"""
|
||||
with open(path, "r") as f:
|
||||
dictdata = dict()
|
||||
dictdata = json.load(f) # type: ignore
|
||||
dictdata = json.load(f) # type: ignore
|
||||
dic = dict()
|
||||
for item, attr in dictdata.items():
|
||||
dic[item] = (Electron(hasher.hash(item), attr))
|
||||
return dic
|
||||
dic[item] = Electron(hasher.hash(item), attr)
|
||||
return dic
|
||||
|
||||
@@ -29,12 +29,13 @@ class Nucleon:
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.ident)
|
||||
|
||||
|
||||
def do_eval(self):
|
||||
"""
|
||||
执行并以结果替换当前单元的所有 eval 语句
|
||||
TODO: 带有限制的 eval, 异步/多线程执行避免堵塞
|
||||
"""
|
||||
|
||||
# eval 环境设置
|
||||
def eval_with_env(s: str):
|
||||
try:
|
||||
@@ -43,7 +44,7 @@ class Nucleon:
|
||||
except Exception as e:
|
||||
ret = f"此 eval 实例发生错误: {e}"
|
||||
return ret
|
||||
|
||||
|
||||
def traverse(data, modifier):
|
||||
if isinstance(data, dict):
|
||||
for key, value in data.items():
|
||||
@@ -60,9 +61,10 @@ class Nucleon:
|
||||
if data.startswith("eval:"):
|
||||
return modifier(data[5:])
|
||||
return data
|
||||
|
||||
|
||||
traverse(self.payload, eval_with_env)
|
||||
traverse(self.metadata, eval_with_env)
|
||||
|
||||
@staticmethod
|
||||
def placeholder():
|
||||
"""生成一个占位原子核"""
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class OrbitalSchedule(TypedDict):
|
||||
quick_review: list
|
||||
recognition: list
|
||||
final_review: list
|
||||
|
||||
|
||||
class Orbital(TypedDict):
|
||||
schedule: OrbitalSchedule
|
||||
puzzles: dict
|
||||
|
||||
|
||||
|
||||
"""一份示例
|
||||
["__metadata__.orbital.puzzles"] # 谜题定义
|
||||
@@ -20,4 +22,4 @@ class Orbital(TypedDict):
|
||||
quick_review = [["FillBlank", "1.0"], ["SelectMeaning", "0.5"], ["recognition", "1.0"]]
|
||||
recognition = [["recognition", "1.0"]]
|
||||
final_review = [["FillBlank", "0.7"], ["SelectMeaning", "0.7"], ["recognition", "1.0"]]
|
||||
"""
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from heurams.context import config_var
|
||||
import pathlib
|
||||
|
||||
|
||||
def probe_by_filename(filename):
|
||||
"""探测指定文件 (无扩展名) 的所有信息"""
|
||||
paths: dict = config_var.get().get("paths")
|
||||
@@ -8,17 +9,18 @@ def probe_by_filename(filename):
|
||||
result = {}
|
||||
for item, attr in paths.items():
|
||||
for i in formats:
|
||||
attr: pathlib.Path = pathlib.Path(attr) / filename + '.' + i
|
||||
attr: pathlib.Path = pathlib.Path(attr) / filename + "." + i
|
||||
if attr.exists():
|
||||
result[item.replace("_dir", "")] = str(attr)
|
||||
return result
|
||||
|
||||
def probe_all(is_stem = 1):
|
||||
|
||||
def probe_all(is_stem=1):
|
||||
"""依据目录探测所有信息
|
||||
|
||||
|
||||
Args:
|
||||
is_stem (boolean): 是否**删除**文件扩展名
|
||||
|
||||
|
||||
Returns:
|
||||
dict: 有三项, 每一项的键名都是文件组类型, 值都是文件组列表, 只包含文件名
|
||||
"""
|
||||
@@ -35,7 +37,9 @@ def probe_all(is_stem = 1):
|
||||
result[item.replace("_dir", "")].append(str(i.name))
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
|
||||
print(os.getcwd())
|
||||
print(probe_all())
|
||||
|
||||
@@ -10,10 +10,10 @@ from .mcq import MCQPuzzle
|
||||
from .recognition import RecognitionPuzzle
|
||||
|
||||
__all__ = [
|
||||
'BasePuzzle',
|
||||
'ClozePuzzle',
|
||||
'MCQPuzzle',
|
||||
'RecognitionPuzzle',
|
||||
"BasePuzzle",
|
||||
"ClozePuzzle",
|
||||
"MCQPuzzle",
|
||||
"RecognitionPuzzle",
|
||||
]
|
||||
|
||||
puzzles = {
|
||||
@@ -23,6 +23,7 @@ puzzles = {
|
||||
"base": BasePuzzle,
|
||||
}
|
||||
|
||||
|
||||
@staticmethod
|
||||
def create_by_dict(config_dict: dict) -> BasePuzzle:
|
||||
"""
|
||||
@@ -37,19 +38,19 @@ def create_by_dict(config_dict: dict) -> BasePuzzle:
|
||||
Raises:
|
||||
ValueError: 当配置无效时抛出
|
||||
"""
|
||||
puzzle_type = config_dict.get('type')
|
||||
puzzle_type = config_dict.get("type")
|
||||
|
||||
if puzzle_type == 'cloze':
|
||||
if puzzle_type == "cloze":
|
||||
return puzzles["cloze"](
|
||||
text=config_dict['text'],
|
||||
min_denominator=config_dict.get('min_denominator', 7)
|
||||
text=config_dict["text"],
|
||||
min_denominator=config_dict.get("min_denominator", 7),
|
||||
)
|
||||
elif puzzle_type == 'mcq':
|
||||
elif puzzle_type == "mcq":
|
||||
return puzzles["mcq"](
|
||||
mapping=config_dict['mapping'],
|
||||
jammer=config_dict.get('jammer', []),
|
||||
max_riddles_num=config_dict.get('max_riddles_num', 2),
|
||||
prefix=config_dict.get('prefix', '')
|
||||
mapping=config_dict["mapping"],
|
||||
jammer=config_dict.get("jammer", []),
|
||||
max_riddles_num=config_dict.get("max_riddles_num", 2),
|
||||
prefix=config_dict.get("prefix", ""),
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"未知的谜题类型: {puzzle_type}")
|
||||
raise ValueError(f"未知的谜题类型: {puzzle_type}")
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# base.py
|
||||
class BasePuzzle:
|
||||
"""谜题基类"""
|
||||
|
||||
|
||||
def refresh(self):
|
||||
raise NotImplementedError("谜题对象未实现 refresh 方法")
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return f"谜题: {type(self).__name__}"
|
||||
return f"谜题: {type(self).__name__}"
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from .base import BasePuzzle
|
||||
import random
|
||||
|
||||
|
||||
class ClozePuzzle(BasePuzzle):
|
||||
"""填空题谜题生成器
|
||||
|
||||
|
||||
Args:
|
||||
text: 原始字符串(需要 delimiter 分割句子, 末尾应有 delimiter)
|
||||
min_denominator: 最小概率倒数(如占所有可生成填空数的 1/7 中的 7, 若期望值小于 1, 则取 1)
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
from .base import BasePuzzle
|
||||
import random
|
||||
|
||||
|
||||
class MCQPuzzle(BasePuzzle):
|
||||
"""选择题谜题生成器"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mapping: dict,
|
||||
jammer: list,
|
||||
max_riddles_num: int = 2,
|
||||
prefix: str = ""
|
||||
self, mapping: dict, jammer: list, max_riddles_num: int = 2, prefix: str = ""
|
||||
):
|
||||
self.prefix = prefix
|
||||
self.mapping = mapping
|
||||
@@ -29,18 +26,16 @@ class MCQPuzzle(BasePuzzle):
|
||||
self.answer = ["无答案"]
|
||||
self.options = []
|
||||
return
|
||||
|
||||
|
||||
num_questions = min(self.max_riddles_num, len(self.mapping))
|
||||
questions = random.sample(list(self.mapping.items()), num_questions)
|
||||
puzzles = []
|
||||
answers = []
|
||||
all_options = []
|
||||
|
||||
|
||||
for question, correct_answer in questions:
|
||||
options = [correct_answer]
|
||||
available_jammers = [
|
||||
j for j in self.jammer if j != correct_answer
|
||||
]
|
||||
available_jammers = [j for j in self.jammer if j != correct_answer]
|
||||
if len(available_jammers) >= 3:
|
||||
selected_jammers = random.sample(available_jammers, 3)
|
||||
else:
|
||||
@@ -50,14 +45,14 @@ class MCQPuzzle(BasePuzzle):
|
||||
puzzles.append(question)
|
||||
answers.append(correct_answer)
|
||||
all_options.append(options)
|
||||
|
||||
|
||||
question_texts = []
|
||||
for i, puzzle in enumerate(puzzles):
|
||||
question_texts.append(f"{self.prefix}:\n {i+1}. {puzzle}")
|
||||
|
||||
|
||||
self.wording = question_texts
|
||||
self.answer = answers
|
||||
self.options = all_options
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.wording}\n正确答案: {', '.join(self.answer)}"
|
||||
return f"{self.wording}\n正确答案: {', '.join(self.answer)}"
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
from .base import BasePuzzle
|
||||
import random
|
||||
|
||||
|
||||
class RecognitionPuzzle(BasePuzzle):
|
||||
"""识别占位符"""
|
||||
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
|
||||
def refresh(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -3,10 +3,4 @@ from .procession import Procession
|
||||
from .fission import Fission
|
||||
from .phaser import Phaser
|
||||
|
||||
__all__ = [
|
||||
"PhaserState",
|
||||
"ProcessionState",
|
||||
"Procession",
|
||||
"Fission",
|
||||
"Phaser"
|
||||
]
|
||||
__all__ = ["PhaserState", "ProcessionState", "Procession", "Fission", "Phaser"]
|
||||
|
||||
@@ -3,27 +3,34 @@ import heurams.kernel.puzzles as puz
|
||||
import random
|
||||
from .states import PhaserState
|
||||
|
||||
class Fission():
|
||||
|
||||
class Fission:
|
||||
"""裂变器: 单原子调度展开器"""
|
||||
def __init__(self, atom: pt.Atom, phase = PhaserState.RECOGNITION):
|
||||
|
||||
def __init__(self, atom: pt.Atom, phase=PhaserState.RECOGNITION):
|
||||
self.atom = atom
|
||||
self.orbital_schedule = atom.registry["orbital"]["schedule"][phase.value] # type: ignore
|
||||
self.orbital_puzzles = atom.registry["orbital"]["puzzles"]
|
||||
#print(self.orbital_schedule)
|
||||
self.orbital_schedule = atom.registry["orbital"]["schedule"][phase.value] # type: ignore
|
||||
self.orbital_puzzles = atom.registry["orbital"]["puzzles"]
|
||||
# print(self.orbital_schedule)
|
||||
self.puzzles = list()
|
||||
for item, possibility in self.orbital_schedule: # type: ignore
|
||||
for item, possibility in self.orbital_schedule: # type: ignore
|
||||
if not isinstance(possibility, float):
|
||||
possibility = float(possibility)
|
||||
while possibility > 1:
|
||||
self.puzzles.append({
|
||||
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||
"alia": item
|
||||
})
|
||||
self.puzzles.append(
|
||||
{
|
||||
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||
"alia": item,
|
||||
}
|
||||
)
|
||||
possibility -= 1
|
||||
if random.random() <= possibility:
|
||||
self.puzzles.append({
|
||||
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||
"alia": item
|
||||
})
|
||||
self.puzzles.append(
|
||||
{
|
||||
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||
"alia": item,
|
||||
}
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
yield from self.puzzles
|
||||
|
||||
@@ -4,8 +4,10 @@ import heurams.kernel.particles as pt
|
||||
from .states import PhaserState, ProcessionState
|
||||
from .procession import Procession
|
||||
|
||||
class Phaser():
|
||||
|
||||
class Phaser:
|
||||
"""移相器: 全局调度阶段管理器"""
|
||||
|
||||
def __init__(self, atoms: list[pt.Atom]) -> None:
|
||||
new_atoms = list()
|
||||
old_atoms = list()
|
||||
@@ -17,10 +19,14 @@ class Phaser():
|
||||
old_atoms.append(i)
|
||||
self.processions = list()
|
||||
if len(old_atoms):
|
||||
self.processions.append(Procession(old_atoms, PhaserState.QUICK_REVIEW, "初始复习"))
|
||||
self.processions.append(
|
||||
Procession(old_atoms, PhaserState.QUICK_REVIEW, "初始复习")
|
||||
)
|
||||
if len(new_atoms):
|
||||
self.processions.append(Procession(new_atoms,PhaserState.RECOGNITION, "新记忆"))
|
||||
self.processions.append(Procession(atoms,PhaserState.FINAL_REVIEW, "总体复习"))
|
||||
self.processions.append(
|
||||
Procession(new_atoms, PhaserState.RECOGNITION, "新记忆")
|
||||
)
|
||||
self.processions.append(Procession(atoms, PhaserState.FINAL_REVIEW, "总体复习"))
|
||||
|
||||
def current_procession(self):
|
||||
for i in self.processions:
|
||||
@@ -29,4 +35,4 @@ class Phaser():
|
||||
self.state = i.phase
|
||||
return i
|
||||
self.state = PhaserState.FINISHED
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import heurams.kernel.particles as pt
|
||||
from .states import PhaserState, ProcessionState
|
||||
|
||||
class Procession():
|
||||
|
||||
class Procession:
|
||||
"""队列: 标识单次记忆流程"""
|
||||
|
||||
def __init__(self, atoms: list, phase: PhaserState, name: str = ""):
|
||||
self.atoms = atoms
|
||||
self.queue = atoms.copy()
|
||||
@@ -12,7 +14,7 @@ class Procession():
|
||||
self.phase = phase
|
||||
self.state: ProcessionState = ProcessionState.RUNNING
|
||||
|
||||
def forward(self, step = 1):
|
||||
def forward(self, step=1):
|
||||
self.cursor += step
|
||||
if self.cursor == len(self.queue):
|
||||
self.state = ProcessionState.FINISHED
|
||||
@@ -20,22 +22,22 @@ class Procession():
|
||||
self.state = ProcessionState.RUNNING
|
||||
try:
|
||||
self.current_atom = self.queue[self.cursor]
|
||||
return 1 # 成功
|
||||
return 1 # 成功
|
||||
except IndexError as e:
|
||||
print(f"{e}")
|
||||
return 0
|
||||
|
||||
def append(self, atom = None):
|
||||
def append(self, atom=None):
|
||||
if atom == None:
|
||||
atom = self.current_atom
|
||||
if self.queue[len(self.queue) - 1] != atom or len(self) <= 1:
|
||||
self.queue.append(atom)
|
||||
self.queue.append(atom)
|
||||
|
||||
def __len__(self):
|
||||
return (len(self.queue) - self.cursor)
|
||||
return len(self.queue) - self.cursor
|
||||
|
||||
def process(self):
|
||||
return (self.cursor)
|
||||
return self.cursor
|
||||
|
||||
def total_length(self):
|
||||
return len(self.queue)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
|
||||
class PhaserState(Enum):
|
||||
UNSURE = "unsure"
|
||||
QUICK_REVIEW = "quick_review"
|
||||
@@ -7,6 +8,7 @@ class PhaserState(Enum):
|
||||
FINAL_REVIEW = "final_review"
|
||||
FINISHED = "finished"
|
||||
|
||||
|
||||
class ProcessionState(Enum):
|
||||
RUNNING = auto()
|
||||
FINISHED = auto()
|
||||
FINISHED = auto()
|
||||
|
||||
Reference in New Issue
Block a user