羽球搭子 HarmonyOS 实战(16):实时计分页的状态机设计
一、计分页最怕状态由按钮文字暗示实时计分看起来只是两个“1”按钮实际同时约束比赛是否进行、采用哪种赛制、比分能否修改、是否达到结束条件、是否已经落盘以及结束后是否允许重复提交。如果这些规则散落在多个点击回调中21:20、30:29、抢 21 和普通 21 分制会出现互相矛盾的结果。稳妥的实现是把比赛建模为显式状态机。playing状态接受加分、减分、直接录入和撤销每次变化后统一执行赛制判定命中结束条件后进入finished冻结按钮并触发保存。ArkUI 页面只根据状态渲染不自行推断比赛是否结束。HarmonyOS 状态管理的基础概念可参考ArkUI 状态管理概述。二、领域状态要比 UI 状态更精确计分卡片至少需要比赛标识、关联对局标识、计分制、双方名称与比分、比赛状态、胜方、开始时间和结束时间。弹窗是否展开、快捷比分面板是否显示属于 UI 状态不应进入比赛实体。这样即使换成平板双栏或语音计分入口领域模型仍保持一致。字段约束参与的状态转换status只能是 playing/finished决定所有计分按钮可用性scoringSystem创建比赛后固定决定结束阈值与领先分scoreA/scoreB非负整数每次变化后触发结束判定winnerplaying 时为空finished 时必须是 A 或 BendedAtplaying 时为 0finished 时写入时间戳linkedSessionId可为空非空时结束后回写正式对局状态字段不能互相打架。例如statusfinished但winner统计页就无法判断胜方playing却带有endedAt恢复后可能被误当作已完成。创建副本时应一次写全相关字段而不是分多次更新。三、所有比分变化走同一个入口按钮回调只传递队伍和变化量统一入口负责查找比赛、检查状态、收敛非负数、记录可撤销动作、替换数组元素并触发结束判定。这样“加一分”“减一分”和未来的蓝牙遥控器都复用相同规则。updateScore(matchId: string, team: A | B, delta: number): void { const next this.matches.slice() const index next.findIndex((item: ScoreMatch) item.id matchId) if (index 0 || next[index].status ! playing) return const current next[index] const scoreA team A ? Math.max(0, current.playerA.score delta) : current.playerA.score const scoreB team B ? Math.max(0, current.playerB.score delta) : current.playerB.score this.recordHistory(matchId, team, delta, current, scoreA, scoreB) next[index] this.copyWithScore(current, scoreA, scoreB) this.matches next this.checkAutoFinish(matchId) }这里先复制数组再替换元素确保 ArkUI 能观察到引用变化。Math.max(0, ...)只是一层底线更重要的是playing门禁它阻止已结束比赛继续被减分“复活”。四、赛制判定必须是纯函数结束规则不应该直接操作页面。纯函数接收赛制和比分返回胜方或空值便于覆盖边界测试。普通 21 分制要求至少 21 分且领先 2 分抢 21 到点且不平分即可结束15 分制同理一分到底等特殊玩法也可以作为独立策略扩展。function resolveWinner(system: ScoringSystem, a: number, b: number): Team | { const lead Math.abs(a - b) if (system 21-point Math.max(a, b) 21 lead 2) { return a b ? A : B } if (system 21-point-rush Math.max(a, b) 21 a ! b) { return a b ? A : B } if (system 15-point Math.max(a, b) 15 lead 2) { return a b ? A : B } if (system 100-point-rush Math.max(a, b) 100 a ! b) { return a b ? A : B } return }场景普通 21 分制抢 21预期20:20未结束未结束平分继续21:20未结束A 胜普通制还差领先 2 分22:20A 胜A 胜状态进入 finished30:29未设置封顶时继续A 胜规则必须与产品定义一致20:22B 胜B 胜胜方与结束时间同时写入五、结束转换要保证只执行一次快速双击可能让两次1几乎同时进入回调。结束函数再次检查当前状态只有仍为playing才创建结束副本。随后清空撤销栈、持久化比分并根据是否关联正式对局决定同步路径。重复调用直接返回避免一场比赛生成两条保存记录。finishMatch(matchId: string, winner: Team): void { const next this.matches.slice() const index next.findIndex((item: ScoreMatch) item.id matchId) if (index 0 || next[index].status finished) return const current next[index] next[index] { ...current, status: finished, winner, endedAt: Date.now() } this.matches next this.scoreHistory.delete(matchId) this.persistFinishedMatch(next[index]) }保存失败也不应把比赛退回playing。本地结果先保存并给出明确提示云端失败进入待同步状态否则用户已经看到结束画面却因为网络错误突然回到可计分状态会造成更严重的数据不一致。六、直接录入是一条新的比分基线裁判可能从纸面记录补录 18:16或者修正误操作后的整段比分。直接录入与连续点击不同它不知道每一分由哪一队获得因此不能保留旧撤销栈。输入需要校验为有限、非负整数并按赛制设置合理上限写入后清空历史再执行统一结束判定。applyDirectScore(matchId: string, rawA: string, rawB: string): boolean { const a Number(rawA) const b Number(rawB) if (!Number.isFinite(a) || !Number.isFinite(b) || a 0 || b 0) { return false } const max this.scoringSystemOf(matchId) 100-point-rush ? 200 : 50 const scoreA Math.min(max, Math.floor(a)) const scoreB Math.min(max, Math.floor(b)) this.replaceScore(matchId, scoreA, scoreB) this.scoreHistory.delete(matchId) this.checkAutoFinish(matchId) return true }直接录入达到结束条件时同样进入finished不能绕过保存链路。若比分超过产品上限应在输入框旁提示收敛结果避免用户以为录入的 999 分被完整保存。七、语音和动画是状态的副作用比分播报、局点动画和振动反馈都应该在状态更新成功之后触发。播报函数需要知道旧比分和新比分才能避免减分或无效点击重复朗读自动结束发生后则优先播报比赛结果不再播报普通比分。副作用失败不能影响比分本身。private afterScoreChanged(matchId: string, before: Score, after: Score): void { const current this.findMatch(matchId) if (current undefined) return if (current.status finished) { this.speakResult(current) return } if (before.a ! after.a || before.b ! after.b) { this.speakScore(after) } }把副作用和状态转换分开后即使设备没有可用语音引擎计分仍然可靠平板布局只需要订阅相同比赛模型不需要复制一套结束判断。八、围绕边界比分做验收计分状态机的测试重点不是 0:0 到 1:0而是临界状态和重复操作。每一种赛制至少验证一组未结束、刚好结束和结束后继续点击的场景。1. 普通 21 分制输入 20:20双方各加 1 分确认 21:21 仍在进行。 2. 再连续形成 23:21确认只结束一次胜方为 A按钮全部禁用。 3. 抢 21 输入 21:20确认立即结束普通制下同比分不得结束。 4. 在 0:0 连续减分确认比分不低于 0也不产生撤销记录。 5. 对已结束比赛再次点击加分、重置和直接录入确认状态不变化。 6. 结束时关闭网络确认本地结果保留并出现可理解的同步提示。九、总结实时计分页的核心是一组受控状态转换而不是一排按钮。领域模型明确playing与finished比分变化统一进入一个函数赛制判定保持纯净结束转换具备幂等保护直接录入重建撤销基线语音等副作用不干扰主状态。这样才能让手机、平板、语音和云同步共用一套比赛规则。

相关新闻

多步骤智能体任务断层?Kimi-K3 前沿推理专用模型,DMXAPI对接300多款API,AIAgent 开发必备

多步骤智能体任务断层?Kimi-K3 前沿推理专用模型,DMXAPI对接300多款API,AIAgent 开发必备

AI 智能体开发过程中,多步骤链式任务极易出现逻辑断层、步骤缺失、任务中断问题,严重影响智能体落地效果。Kimi-K3 是前沿推理专用模型,长程链式任务推理连贯稳定,彻底解决智能体任务断层难题。DMXAPI 平台入账快速、流程高效&…

2026/8/13 12:32:19 阅读更多 →
计算机毕业设计之智慧篮球馆预约

计算机毕业设计之智慧篮球馆预约

近些年来,随着科技的飞速发展,互联网的普及逐渐延伸到各行各业中,给人们生活带来了十分的便利,智慧篮球馆预约利用计算机网络实现信息化管理,使整个智慧篮球馆预约的发展和服务水平有显著提升。本文拟采用Eclipse开发工…

2026/8/13 12:31:42 阅读更多 →
Go 入门到精通-29-测试与基准

Go 入门到精通-29-测试与基准

目录 🟠 Go 入门到精通:测试与基准开篇:测试不是可选项1. testing 包快速入门1.1 第一个测试1.2 运行测试1.3 测试命名约定 2. 表驱动测试 Table-Driven Tests3. 子测试 t.Run4. 测试辅助函数与 t.Helper5. TestMain:全局 Setup 与…

2026/8/10 3:40:50 阅读更多 →

最新新闻

网易云、QQ音乐歌词免费批量下载:163MusicLyrics 云音乐歌词提取工具完整攻略

网易云、QQ音乐歌词免费批量下载:163MusicLyrics 云音乐歌词提取工具完整攻略

网易云、QQ音乐歌词免费批量下载:163MusicLyrics 云音乐歌词提取工具完整攻略 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 前阵子我把三百多首老歌拷进车载…

2026/8/13 12:31:52 阅读更多 →
信号处理进阶:从实信号到复信号,解锁通信与雷达核心技术

信号处理进阶:从实信号到复信号,解锁通信与雷达核心技术

1. 信号世界的“虚实”之辨:从一根导线到整个宇宙搞了这么多年信号处理,从最开始的单片机采集几个模拟量,到后来玩软件无线电,再到研究通信算法,我越来越觉得,信号处理这行当,入门容易&#xff…

2026/8/13 12:31:52 阅读更多 →
B站视频下载工具新手教程:3步搞定大会员4K与充电专属视频

B站视频下载工具新手教程:3步搞定大会员4K与充电专属视频

B站视频下载工具新手教程:3步搞定大会员4K与充电专属视频 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 你有没有过这样的…

2026/8/13 12:31:52 阅读更多 →
开发五子棋小游戏3.0

开发五子棋小游戏3.0

效果展示功能改进1、窗体画面不丢失在ChessTools类中编写drawChessBoard、drawAllChess方法,并在MyFrame类中重写的paint里调用,这样窗体每刷新一次,棋盘、棋子就重绘一次。2、结合一维数组和二维数组实现功能创建一维数组记录落子顺序&#…

2026/8/13 12:31:52 阅读更多 →
Python零基础入门:从环境搭建到实战项目,手把手带你系统学习

Python零基础入门:从环境搭建到实战项目,手把手带你系统学习

很多朋友在刚开始学习Python时,都会遇到一个共同的问题:网上资料太多太杂,东一榔头西一棒子,学了半天感觉还是云里雾里,不知道如何把知识点串联起来应用到实际项目中。本文旨在为你提供一份系统、完整、可实践的Python…

2026/8/13 12:31:52 阅读更多 →
RDMA与AI优化在KVStore数据同步中的实践

RDMA与AI优化在KVStore数据同步中的实践

1. 项目背景与核心挑战 在分布式存储系统中,KVStore作为基础组件,其数据同步效率直接影响整个系统的吞吐量和延迟表现。传统TCP/IP协议栈的多次内存拷贝和内核态-用户态切换已成为性能瓶颈,特别是在跨节点同步场景下。我们团队近期尝试将RDMA…

2026/8/13 12:30:52 阅读更多 →

日新闻

Visual Studio新建项目解决方案为空:系统性排查与修复指南

Visual Studio新建项目解决方案为空:系统性排查与修复指南

1. 问题现象与本质剖析如果你是一位.NET开发者,或者正准备踏入这个领域,那么Visual Studio(后面简称VS)绝对是你绕不开的伙伴。但有时候,这个伙伴会跟你开一个不大不小的玩笑:你满怀期待地点击“创建新项目…

2026/8/13 0:00:09 阅读更多 →
长春建设厅网站:普通人买房办事必看的真实指南与避坑攻略

长春建设厅网站:普通人买房办事必看的真实指南与避坑攻略

说实话,每次提起“长春建设厅网站”这几个字,我心里都挺有感触的。不是因为它有多高大上,也不是因为那里藏着什么不可告人的秘密,恰恰相反,是因为它太“接地气”了,或者说,它是咱们普通人想要在这个城市好好生活、安稳买房时,必须得翻过的一座“数据山”。很多新朋友第…

2026/8/13 0:00:09 阅读更多 →
Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案

Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案

Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini 你是否曾为Windows家庭版无法支持多用户远程桌面…

2026/8/13 0:00:09 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/13 2:38:34 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/13 10:41:52 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/13 10:41:51 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/13 10:41:50 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/13 10:41:49 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/13 10:41:49 阅读更多 →