纯端侧数独 App 的三个工程问题:声明式棋盘、确定性题库、文件持久化
先看它到底要解决什么
鸿蒙开发实践中心里这个「数独小游戏」案例,是一个很少见的、完全不碰网络的题目。它不登录、不联网、不要云数据库,做完就是一个能装在模拟器里玩的离线小游戏。但正因为它「简单」,反而把三个纯端侧的工程问题暴露得很清楚:棋盘怎么用声明式 UI 渲染并实时高亮冲突、题库怎么在没网的情况下确定性地生成、进度怎么可靠地存下来。
问题一:9×9 棋盘的状态该放在哪
棋盘是 81 个格子,每个格子都有值、是否固定、是否冲突三种属性。如果每个格子都自己管状态,父组件想统一重置或者判胜负就会很别扭。案例里的做法是:用 @State 在页面级持有棋盘数据,用 @Prop 把单元格数据单向传给子组件,子组件只负责渲染。这样填数时只需要改父级数组里的一项,界面自动刷新,冲突校验也能在一处统一算出结果再回填高亮标记,不用让 81 个格子互相打听。
另外它把重复 UI 结构抽成了 @Builder 构建函数,棋盘格和数字面板都复用了同一套构建逻辑,避免了大量重复的模板代码。
问题二:没网怎么出题
这是我觉得最有意思的一点。题库不是随机乱填,而是「基准解 + 置换 + 盲挖空格」:先拿一个确定的合法解,通过行、列、数字的对称置换生成等价解,再按难度挖掉不同数量的格子。配合确定性 PRNG,同一难度同一序号每次生成的题完全一样,结果可复现。简单、中等、困难各 18 题,一共 54 题,每题都有解。
确定性这三个字很关键:出了问题能复现,写测试也能写断言,不用面对「这次和上次出的题不一样」这种没法收场的局面。
问题三:进度为什么不用 dataPreferences
案例里有一个很实在的取舍说明:进度用 @ohos.file.fs 直接读写 JSON 文件,而不是用 dataPreferences。原因是 dataPreferences 是单例缓存,跨页面容易出现读到旧值的情况——首页读完进度进游戏页,通关回来首页还是老数字。直接读文件虽然多一次 IO,但语义清楚,读完即是最新。这是个典型的「用简单方案避开隐性坑」的例子。
一点体会
纯端侧应用最容易被低估,因为它没有云端那一堆资源编排,看起来步骤少。但真正决定体验的恰恰是状态管理、数据一致性和可复现性这些基本功。这个案例把逻辑和 UI 严格拆开(校验、判定都是 TypeScript 纯函数),再配一条「构建 → 运行 → 固定样例复核」的验收链路,很适合当作 ArkUI 的入门练手题。
下一步我想试试它列出的拓展方向里最简单的一条:给棋盘加笔记模式,在单元格里叠加候选数字的小字布局,顺便看看 CellData 结构扩展之后状态刷新会不会有新问题。
- 点赞
- 收藏
- 关注作者
评论(0)