diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b793654..b77726e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,23 +1,22 @@ # 贡献指南 -欢迎为潜进 (HeurAMS) 项目做出贡献!本项目是一个开源项目,我们鼓励社区成员参与改进。 +欢迎为此项目做出贡献! +本项目是一个开源项目, 我们鼓励社区成员参与改进. ## 开发流程 -1. **讨论功能**:在开始编写代码之前,建议先通过 Issue 讨论新功能或修复。 -2. **分支策略**: +1. **分支划分**: - `main` 分支:稳定版本 - `develop` 分支:开发版本 - 功能分支:从 `develop` 分支创建,命名格式为 `feature/描述` 或 `fix/描述` -3. **代码风格**: - - 使用 Black 格式化代码(如果配置) +2. **代码风格**: + - 请使用 Black 格式化代码 - 遵循 PEP 8 规范 - - 使用类型注解 - - 添加适当的文档字符串(中英文均可) -4. **提交消息**: + - 添加适当的文档字符串 +3. **提交消息**: - 使用中文或英文撰写清晰的提交消息 - 格式:`类型: 描述`,例如 `fix: 修复登录错误` 或 `feat: 添加新算法` -5. **测试**: +4. **测试**: - 为新功能添加单元测试 - 确保所有测试通过 - 运行 `pytest` 检查 @@ -40,29 +39,6 @@ pip install -r requirements.txt pip install -e . ``` -## 提交更改 - -1. 确保代码通过测试: - ```bash - python -m pytest tests/ - ``` - -2. 提交更改: - ```bash - git add . - git commit -m "类型: 描述" - git push origin 分支名 - ``` - -3. 创建 Pull Request: - - 在 GitHub 上创建 Pull Request,将你的分支合并到 `develop` - - 描述更改内容和动机 - - 链接相关 Issue(如果有) - -## 行为准则 - -请保持友好、尊重的交流氛围。我们遵循 [贡献者公约](https://www.contributor-covenant.org/)。 - ## 许可证 贡献者同意其贡献将在 AGPL-3.0 许可证下发布。 diff --git a/README.md b/README.md index ee24988..9c23f4b 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ ### 启动应用 ```bash -# 从项目根目录运行 +# 在任一目录(建议是空目录或者包根目录, 将被用作存放数据)下运行 python -m heurams.interface ``` diff --git a/src/heurams/interface/screens/memorizor.py b/src/heurams/interface/screens/memorizor.py index d51ab9c..fdee57b 100644 --- a/src/heurams/interface/screens/memorizor.py +++ b/src/heurams/interface/screens/memorizor.py @@ -23,7 +23,7 @@ logger = get_logger(__name__) class MemScreen(Screen): BINDINGS = [ ("q", "pop_screen", "返回"), - ("p", "prev", "复习上一个"), + #("p", "prev", "复习上一个"), ("d", "toggle_dark", "改变色调"), ("v", "play_voice", "朗读"), ] @@ -46,6 +46,8 @@ class MemScreen(Screen): self.procession: Procession = self.phaser.current_procession() # type: ignore # logger.debug(self.phaser.state) # self.procession.forward(1) + for i in atoms: + i.do_eval() def on_mount(self): self.load_puzzle() @@ -53,11 +55,10 @@ class MemScreen(Screen): def puzzle_widget(self): try: - # logger.debug(self.phaser.state) - #logger.debug(self.procession.cursor) - #logger.debug(self.procession.current_atom) + logger.debug(self.phaser.state) + logger.debug(self.procession.cursor) + logger.debug(self.procession.current_atom) self.fission = Fission(self.procession.current_atom, self.phaser.state) - # logger.debug(1) puzzle_debug = next(self.fission.generate()) #logger.debug(puzzle_debug) return shim.puzzle2widget[puzzle_debug["puzzle"]]( @@ -71,21 +72,33 @@ class MemScreen(Screen): def compose(self) -> ComposeResult: yield Header(show_clock=True) with ScrollableContainer(): - with Center(): - yield Static( - f"当前进度: {self.procession.process()}/{self.procession.total_length()}" - ) + yield Label(self._get_progress_text(), id="progress") + # self.mount(self.current_widget()) # type: ignore yield ScrollableContainer(id="puzzle-container") # yield Button("重新学习此单元", id="re-recognize", variant="warning") yield Footer() + def _get_progress_text(self): + return f"当前进度: {self.procession.process() + 1}/{self.procession.total_length()}" + + def update_display(self): + progress_widget = self.query_one("#progress") + progress_widget.update(self._get_progress_text()) # type: ignore + def load_puzzle(self): container = self.query_one("#puzzle-container") for i in container.children: i.remove() container.mount(self.puzzle_widget()) + def load_finished_widget(self): + container = self.query_one("#puzzle-container") + for i in container.children: + i.remove() + from heurams.interface.widgets.finished import Finished + container.mount(Finished()) + def on_button_pressed(self, event): event.stop() @@ -98,7 +111,13 @@ class MemScreen(Screen): ret = self.procession.forward(1) if ret == 0: self.procession = self.phaser.current_procession() # type: ignore - logger.debug(f"建立新队列 {self.procession.phase}") + if self.procession == 0: + logger.debug(f"记忆进程结束") + self.load_finished_widget() + return + else: + logger.debug(f"建立新队列 {self.procession.phase}") + self.update_display() self.load_puzzle() def action_play_voice(self): diff --git a/src/heurams/interface/widgets/mcq_puzzle.py b/src/heurams/interface/widgets/mcq_puzzle.py index ebdcffa..ba3098a 100644 --- a/src/heurams/interface/widgets/mcq_puzzle.py +++ b/src/heurams/interface/widgets/mcq_puzzle.py @@ -3,15 +3,16 @@ from textual.widgets import ( Label, Button, ) -from textual.containers import ScrollableContainer +from textual.containers import ScrollableContainer, Container from textual.widget import Widget import heurams.kernel.particles as pt import heurams.kernel.puzzles as pz from .base_puzzle_widget import BasePuzzleWidget from typing import TypedDict -from bidict import bidict from heurams.services.hasher import hash +from heurams.services.logger import get_logger +logger = get_logger(__name__) class Setting(TypedDict): __origin__: str @@ -46,7 +47,8 @@ class MCQPuzzle(BasePuzzleWidget): ) self.inputlist = [] self.alia = alia - self.hashmap = bidict() + self.hashmap = dict() + self.cursor = 0 self._load() def _load(self): @@ -57,18 +59,23 @@ class MCQPuzzle(BasePuzzleWidget): self.puzzle.refresh() def compose(self): + self.atom.registry["nucleon"].do_eval() setting: Setting = self.atom.registry["nucleon"].metadata["orbital"]["puzzles"][ self.alia ] + logger.debug(f"Puzzle Setting: {setting}") yield Label(setting["primary"], id="sentence") yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle") yield Label(f"当前输入: {self.inputlist}", id="inputpreview") # 渲染当前问题的选项 current_options = self.puzzle.options[len(self.inputlist)] - for i in current_options: - self.hashmap[str(hash(i))] = i - yield Button(i, id=f"select-{hash(i)}") + with Container(id="btn-container"): + for i in current_options: + self.hashmap[str(hash(i))] = i + btnid = f"sel{str(self.cursor).zfill(3)}-{hash(i)}" + logger.debug(f"建立按钮 {btnid}") + yield Button(i, id=f"{btnid}") yield Button("退格", id="delete") @@ -76,7 +83,7 @@ class MCQPuzzle(BasePuzzleWidget): # 更新预览标签 preview = self.query_one("#inputpreview") preview.update(f"当前输入: {self.inputlist}") # type: ignore - + logger.debug("已经更新预览标签") # 更新问题标签 puzzle_label = self.query_one("#puzzle") current_question_index = len(self.inputlist) @@ -95,11 +102,11 @@ class MCQPuzzle(BasePuzzleWidget): self.refresh_buttons() self.update_display() - elif button_id.startswith("select"): # type: ignore + elif button_id.startswith("sel"): # type: ignore # 选项选择处理 answer_text = self.hashmap[button_id[7:]] # type: ignore self.inputlist.append(answer_text) - + logger.debug(f"{self.inputlist}") # 检查是否完成所有题目 if len(self.inputlist) >= len(self.puzzle.answer): is_correct = self.inputlist == self.puzzle.answer @@ -120,22 +127,26 @@ class MCQPuzzle(BasePuzzleWidget): def refresh_buttons(self): """刷新按钮显示(用于题目切换)""" # 移除所有选项按钮 + logger.debug("刷新按钮") + self.cursor += 1 + container = self.query_one("#btn-container") buttons_to_remove = [ child - for child in self.children - if hasattr(child, "id") and child.id and child.id.startswith("select") + for child in container.children + if hasattr(child, "id") and child.id and child.id.startswith("sel") ] for button in buttons_to_remove: - self.remove_child(button) # type: ignore + logger.info(button) + container.remove_children("#"+button.id) # type: ignore # 添加当前题目的选项按钮 current_question_index = len(self.inputlist) if current_question_index < len(self.puzzle.options): current_options = self.puzzle.options[current_question_index] for option in current_options: - button_id = f"select-{hash(option)}" + button_id = f"sel{str(self.cursor).zfill(3)}-{hash(option)}" if button_id not in self.hashmap: self.hashmap[button_id] = option new_button = Button(option, id=button_id) - self.mount(new_button) + container.mount(new_button) diff --git a/src/heurams/kernel/puzzles/mcq.py b/src/heurams/kernel/puzzles/mcq.py index ab11d26..3f2245d 100644 --- a/src/heurams/kernel/puzzles/mcq.py +++ b/src/heurams/kernel/puzzles/mcq.py @@ -64,7 +64,9 @@ class MCQPuzzle(BasePuzzle): # 确保至少有4个干扰项 while len(self.jammer) < 4: - self.jammer.append(" ") + self.jammer.append(" " * (4 - len(self.jammer))) + + unique_jammers = set(jammer + list(self.mapping.values())) def _reset_puzzle_state(self) -> None: """重置谜题状态为初始值 @@ -84,7 +86,7 @@ class MCQPuzzle(BasePuzzle): Raises: ValueError: 当mapping为空时不会抛出异常, 但会设置空谜题状态 """ - logger.debug("MCQPuzzle.refresh 开始,mapping size=%d", len(self.mapping)) + logger.debug("MCQPuzzle.refresh 开始, mapping size=%d", len(self.mapping)) if not self.mapping: self._set_empty_puzzle() return diff --git a/src/heurams/services/hasher.py b/src/heurams/services/hasher.py index 7f90800..2bac237 100644 --- a/src/heurams/services/hasher.py +++ b/src/heurams/services/hasher.py @@ -6,14 +6,14 @@ logger = get_logger(__name__) def get_md5(text): - logger.debug("计算MD5哈希,输入长度: %d", len(text)) + logger.debug(f"计算哈希, 输入`{text}`") result = hashlib.md5(text.encode("utf-8")).hexdigest() - logger.debug("MD5哈希结果: %s...", result[:8]) + logger.debug("哈希结果: %s...", result[:8]) return result def hash(text): - logger.debug("计算哈希,输入长度: %d", len(text)) + logger.debug(f"计算哈希, 输入`{text}`") result = hashlib.md5(text.encode("utf-8")).hexdigest() logger.debug("哈希结果: %s...", result[:8]) return result