Learn-mindustry-logic-A4-Advanced:修订间差异

来自Mindustry中文wiki
(创建页面,内容为“__NOTOC__ <div class="mdtLogicTutorial"><span id="引言"></span> == 引言 == 这是《逻辑教学》的超完整版 (进阶篇), 适用于已经掌握基础语句的玩家. 本教程不是语句词典, 而是偏工程与实战的写法总结. 基线版本: * Mindustry 155 ---- <span id="执行模型与调试"></span> == 执行模型与调试 == <span id="执行四步"></span> === 执行四步 === 逻辑运行可抽象为四步<sup>2</sup>:…”)
 
(清空全部内容)
标签清空
 
(未显示同一用户的1个中间版本)
第1行: 第1行:
__NOTOC__
<div class="mdtLogicTutorial"><span id="引言"></span>
== 引言 ==


这是《逻辑教学》的超完整版 (进阶篇), 适用于已经掌握基础语句的玩家.
本教程不是语句词典, 而是偏工程与实战的写法总结.
基线版本:
* Mindustry 155
----
<span id="执行模型与调试"></span>
== 执行模型与调试 ==
<span id="执行四步"></span>
=== 执行四步 ===
逻辑运行可抽象为四步<sup>[[#fn-2|2]]</sup>:
# 读取 <code>@counter</code> 指向语句
# <code>@counter += 1</code>
# 执行被读取语句
# 回到 1
这条规则解释了:
* <code>jump</code> 的本质是改写下一条语句位置
* <code>wait/stop</code> 的“卡住”是通过 <code>counter-- + yield</code> 实现
* 所有函数/跳表都能用 <code>@counter</code> 手工实现
<span id="变量表调试法"></span>
=== 变量表调试法 ===
建议你固定三层调试变量:
* 控制层: <code>state phase step</code>
* 数据层: <code>in out tmp err</code>
* 时序层: <code>tick heartbeat watchdog</code>
典型调试输出模板:
<pre>
print "s="; print state
print " p="; print phase
print " t="; print tick
printflush message1
</pre>
<div class="mdtMarkdownAlert mdtMarkdownAlert-note">
变量表刷新频率低于逻辑执行频率, 快速跳转下会误读 @counter.
</div>
<span id="最小监控框架"></span>
=== 最小监控框架 ===
'''心跳''' 是什么: 持续变化的计数值。作用: 判断逻辑是否仍在运行。<br />
'''卡死''' 是什么: 逻辑未崩溃但长期不推进。作用: 作为触发恢复的判据。<br />
'''看门狗''' 是什么: 监控“是否长期无进展”的计数器。作用: 超时后触发重置或降级。
<pre>
# 监控心跳和卡死
op add heartbeat heartbeat 1
op mod heartbeat heartbeat 1000000
op add watchdog watchdog 1
jump wd_ok lessThan watchdog 600
    print "watchdog trip"
    printflush message1
    set watchdog 0
wd_ok:
end
</pre>
----
----
<span id="进阶控制流-基础"></span>
== 进阶控制流-基础 ==
这一章只做“衔接”, 不再重复基础控制流定义。
以下基础结构已移动到基础教程《逻辑教学.wiki》中的“控制流基础补充”章节:
* skip
* if-else
* do-while
* while
* gwhile
进阶篇只保留工程侧规则:
* 多层循环必须用唯一标签前缀, 防止跳错行
* break/continue 跳转必须显式写“目标层级”
* 所有循环都要能从外部条件中断
多层循环命名模板:
<pre>
# outer loop
O_LOOP:
    # inner loop
I_LOOP:
        jump I_CONT lessThan x 0
        jump I_BREAK equal innerStop true
        # inner body...
    I_CONT:
        # inner tail...
    jump I_LOOP lessThan i 10
I_BREAK:
    jump O_BREAK equal outerStop true
    # outer tail...
jump O_LOOP lessThan o 5
O_BREAK:
</pre>
----
----
<span id="进阶控制流-选择"></span>
== 进阶控制流-选择 ==
<span id="跳表基础"></span>
=== 跳表基础 ===
'''跳表''' 是什么: 用 @counter 偏移把输入映射到分支入口。作用: 用常数时间做多分支分派。
<pre>
# sel in [0,2]
op add @counter @counter sel
jump C0 always 0 0
jump C1 always 0 0
jump C2 always 0 0
C0:
    print "0"
    jump END always 0 0
C1:
    print "1"
    jump END always 0 0
C2:
    print "2"
END:
printflush message1
</pre>
<span id="跳表防越界"></span>
=== 跳表防越界 ===
<pre>
# clamp sel to [0,2]
op max sel sel 0
op min sel sel 2
op add @counter @counter sel
jump C0 always 0 0
jump C1 always 0 0
jump C2 always 0 0
</pre>
<span id="等长块分派"></span>
=== 等长块分派 ===
每块长度固定时, 可减少子表行数:
<pre>
# len=4
op mul off idx 4
op add @counter @counter off
    print "A"
    jump END always 0 0
    noop
    noop
    print "B"
    jump END always 0 0
    noop
    noop
END:
printflush message1
</pre>
<span id="匹配守卫"></span>
=== 匹配守卫 ===
'''匹配守卫''' 是什么: case 之前的额外条件跳转。作用: 在不增加主分派复杂度的前提下细化命中条件。
<pre>
# case 0 if a<b
op mul k n 2
op add @counter @counter k
    jump C0_G lessThan a b
    jump C0 always 0 0
    jump C1 always 0 0
C0_G:
    print "0 guard"
    jump END always 0 0
C0:
    print "0"
    jump END always 0 0
C1:
    print "1"
END:
printflush message1
</pre>
----
----
<span id="复杂条件"></span>
== 复杂条件 ==
<span id="逻辑代数定义"></span>
=== 逻辑代数定义 ===
{| class="wikitable"
|-
! 形式
! 名称
! 说明
|-
| !A
| 非
| 反转条件
|-
| A && B
| 短路与
| A假时不看B
|-
| A || B
| 短路或
| A真时不看B
|}
<span id="基本反转表"></span>
=== 基本反转表 ===
{| class="wikitable"
|-
! 原
! 反
|-
| lessThan
| greaterThanEq
|-
| lessThanEq
| greaterThan
|-
| greaterThan
| lessThanEq
|-
| greaterThanEq
| lessThan
|-
| equal
| notEqual
|-
| notEqual
| equal
|}
<span id="德摩根定律"></span>
=== 德摩根定律 ===
* <code>!(A && B) = (!A) || (!B)</code>
* <code>!(A || B) = (!A) && (!B)</code>
<span id="构建算法"></span>
=== 构建算法 ===
<pre>
def build(cond, target):
    if cond.type == AND:
        tmp = newTag()
        build(not cond.left, tmp)
        build(cond.right, target)
        add(tmp)
    elif cond.type == OR:
        build(cond.left, target)
        build(cond.right, target)
    else:
        add(jump target cond)
</pre>
<span id="实战示例-复杂条件"></span>
=== 实战示例-复杂条件 ===
目标: <code>(a&lt;b && c&lt;d) || e&lt;f</code>
<pre>
jump T1 greaterThanEq a b
jump TARGET lessThan c d
T1:
jump TARGET lessThan e f
print "false"
TARGET:
print "true"
printflush message1
</pre>
----
----
<span id="函数系统-非递归"></span>
== 函数系统-非递归 ==
<span id="函数组成"></span>
=== 函数组成 ===
# 入口跳过
# 函数体
# 返回语句 <code>set @counter ret</code>
<pre>
jump DEF_END always 0 0
fn_print:
    print msg
    set @counter ret
DEF_END:
set msg "Hello"
op add ret @counter 1
jump fn_print always 0 0
set msg "World"
op add ret @counter 1
jump fn_print always 0 0
printflush message1
</pre>
<span id="函数参数约定"></span>
=== 函数参数约定 ===
推荐约定:
* 入参: <code>arg1 arg2 ...</code>
* 出参: <code>retv</code>
* 返回地址: <code>ret</code>
<span id="函数复用案例"></span>
=== 函数复用案例 ===
平方函数:
<pre>
jump D_END always 0 0
fn_sqr:
    op mul retv arg1 arg1
    set @counter ret
D_END:
set arg1 12
op add ret @counter 1
jump fn_sqr always 0 0
print retv
printflush message1
</pre>
----
----
<span id="函数系统-递归与栈"></span>
== 函数系统-递归与栈 ==
递归函数必须解决两个问题:
# 返回地址会多层嵌套
# 中间变量会被后续递归覆盖
所以要用内存做调用栈<sup>[[#fn-3|3]]</sup>.
<span id="栈模型"></span>
=== 栈模型 ===
建议每帧栈帧结构:
{| class="wikitable"
|-
! 偏移
! 含义
|-
| +0
| 返回地址
|-
| +1
| 参数n
|-
| +2
| 临时值tmp
|}
<span id="递归框架"></span>
=== 递归框架 ===
<pre>
# 仅示意骨架
set sp -1
jump DEF_END always 0 0
fib:
    # push ret
    # push n
    # recurse
    # pop
    set @counter ret
DEF_END:
</pre>
<span id="尾递归优化"></span>
=== 尾递归优化 ===
尾递归可改循环, 大幅降复杂度和 bug 风险.
<pre>
# tail recursion -> loop
LOOP:
    # body
jump LOOP lessThan i n
</pre>
----
----
<span id="多处理器协作协议"></span>
== 多处理器协作协议 ==
超大逻辑应拆分为多个处理器协作.
<span id="协议字段"></span>
=== 协议字段 ===
'''协议''' 是什么: 多处理器共享内存字段和时序规则的约定。作用: 避免协作时读写歧义与乱序。<br />
'''消费者心跳''' 是什么: 由消费者更新的心跳字段。作用: 让生产者判断消费者是否卡住。<br />
'''ACK''' 是什么: 命令处理完成回执值。作用: 让发送方安全进入下一步。
{| class="wikitable"
|-
! 地址
! 字段
|-
| 0
| 协议版本
|-
| 1
| 生产者心跳
|-
| 2
| 消费者心跳
|-
| 3
| 命令码
|-
| 4
| 参数A
|-
| 5
| 参数B
|-
| 6
| ACK
|-
| 7
| 错误码
|}
<span id="握手流程"></span>
=== 握手流程 ===
# Producer 写 cmd + args
# Consumer 读取并执行
# Consumer 写 ack=cmd
# Producer 校验 ack
<span id="协作模板"></span>
=== 协作模板 ===
生产者:
<pre>
write 1 bank1 0
op add hb hb 1
write hb bank1 1
write 200 bank1 3
write x bank1 4
write y bank1 5
read ack bank1 6
jump 0 notEqual ack 200
</pre>
消费者:
<pre>
read ver bank1 0
jump 0 notEqual ver 1
read cmd bank1 3
jump 0 notEqual cmd 200
read x bank1 4
read y bank1 5
# do work...
write 200 bank1 6
</pre>
----
----
<span id="单位控制进阶"></span>
== 单位控制进阶 ==
<span id="抢控保护"></span>
=== 抢控保护 ===
'''抢控''' 是什么: 当前单位被其他逻辑或玩家接管。作用: 提醒当前控制逻辑立即重绑或回退。
<pre>
find:
    ubind @flare
    sensor c @unit @controlled
jump find notEqual c 0
ctrl:
    ucontrol move tx ty 0 0 0
    sensor dead @unit @dead
jump find notEqual dead false
    sensor owner @unit @controller
jump ctrl equal owner @this
jump find always 0 0
</pre>
<span id="控制最小化"></span>
=== 控制最小化 ===
不用控制语句时不要发控制信号<sup>[[#fn-4|4]]</sup>:
<pre>
# 用 op len 判定距离, 替代 ucontrol within
sensor ux @unit @x
sensor uy @unit @y
op sub dx ux tx
op sub dy uy ty
op len dist dx dy
op lessThan near dist 10
</pre>
<span id="可靠解绑"></span>
=== 可靠解绑 ===
<pre>
# 确认当前确实在控制时再 unbind
sensor owner @unit @controller
jump skip notEqual owner @this
ucontrol unbind 0 0 0 0 0
skip:
</pre>
----
----
<span id="单位批处理与调度"></span>
== 单位批处理与调度 ==
目标: 降低单帧峰值, 提升稳定性.
<span id="时间片调度"></span>
=== 时间片调度 ===
<pre>
# task 0..2
op add @counter @counter task
jump T0 always 0 0
jump T1 always 0 0
jump T2 always 0 0
T0:
    # bind / select
    jump NEXT always 0 0
T1:
    # sense
    jump NEXT always 0 0
T2:
    # control
    jump NEXT always 0 0
NEXT:
op add task task 1
op mod task task 3
end
</pre>
<span id="轮询类型"></span>
=== 轮询类型 ===
<pre>
lookup unit utype slot
ubind utype
# ... process one ...
op add slot slot 1
op mod slot slot @unitCount
</pre>
<span id="负载退避"></span>
=== 负载退避 ===
<pre>
# backlog高时减少控制频率
jump light lessThan backlog 20
    wait 0.05
    jump done always 0 0
light:
    wait 0.01
done:
</pre>
----
----
<span id="世界处理器-安全框架"></span>
== 世界处理器-安全框架 ==
<span id="双开关安全门"></span>
=== 双开关安全门 ===
建议两个按钮:
* <code>switch1</code>: 总开关
* <code>switch2</code>: 危险操作开关
<pre>
sensor en1 switch1 @enabled
sensor en2 switch2 @enabled
jump END equal en1 false
jump END equal en2 false
# privileged dangerous ops...
END:
end
</pre>
<span id="回滚点"></span>
=== 回滚点 ===
任何会改地图状态的逻辑建议保留回滚参数:
<pre>
# 写入前先存旧值
getblock block oldB x y
write oldB bank1 20
# ... setblock ...
</pre>
<span id="速率保险丝"></span>
=== 速率保险丝 ===
'''速率保险丝''' 是什么: 先短时提速再自动回落的控制策略(本教程命名)。作用: 避免 setrate 长期高负载导致全局卡顿。
<pre>
# 防止 setrate 长时间高负载
setrate 20
wait 0.2
setrate 1
</pre>
----
----
<span id="世界处理器-高级语句"></span>
== 世界处理器-高级语句 ==
<span id="fetch"></span>
=== fetch ===
<pre>
fetch unit u @sharded i 0
fetch build b @sharded i @conveyor
fetch unitCount uc @sharded 0 0
</pre>
<span id="message"></span>
=== message ===
<pre>
print "系统广播"
message announce 1 @wait
</pre>
<span id="setprop"></span>
=== setprop ===
<pre>
# 高风险示例
setprop @health @this 0
</pre>
<span id="setrule"></span>
=== setrule ===
<pre>
setrule lighting 1 0 0 0 0
</pre>
<span id="status"></span>
=== status ===
<pre>
status false wet unit 10
status true boss unit 0
</pre>
<div class="mdtMarkdownAlert mdtMarkdownAlert-warning">
世界处理器语句破坏性极强, 建议默认禁用, 仅在维护窗口开启.
</div>
----
----
<span id="性能优化与资源预算"></span>
== 性能优化与资源预算 ==
<span id="资源预算模型"></span>
=== 资源预算模型 ===
建议给每帧设置预算变量:
* <code>budgetOps</code>
* <code>budgetIO</code>
* <code>budgetDraw</code>
<span id="高频热点"></span>
=== 高频热点 ===
* 高频 <code>printflush/drawflush</code>
* 全量遍历单位/链接
* 重复 sensor 同一属性
* 大量字符串拼接
<span id="优化手段"></span>
=== 优化手段 ===
{| class="wikitable"
|-
! 问题
! 手段
|-
| 全量扫描卡顿
| 分帧批处理
|-
| 输出过于频繁
| 合并输出/降低 flush 频率
|-
| 逻辑难维护
| 状态机 + 协议层
|-
| 控制抖动
| 降频 + 持续控制窗口
|}
<span id="实战-分帧遍历链接"></span>
=== 实战: 分帧遍历链接 ===
<pre>
# 每帧只处理一个链接
getlink b idx
# ... do something ...
op add idx idx 1
op mod idx idx @links
end
</pre>
----
----
<span id="可维护性规范"></span>
== 可维护性规范 ==
<span id="命名规范"></span>
=== 命名规范 ===
推荐前缀:
* <code>s_</code> 状态变量
* <code>t_</code> 临时变量
* <code>io_</code> 协议变量
* <code>cfg_</code> 配置变量
<span id="模块边界"></span>
=== 模块边界 ===
建议一个处理器只负责一个职责:
* 采集
* 决策
* 执行
* 可视化
<span id="注释规范"></span>
=== 注释规范 ===
注释写“为什么”, 不写“做了什么”.
<pre>
# bad: op add i i 1  # i加1
# good: # 轮询链接索引, 防止固定打同一建筑
op add i i 1
</pre>
<span id="发布规范"></span>
=== 发布规范 ===
建议维护:
* 版本号
* 协议版本
* 变更记录
----
----
<span id="编译器与工程化"></span>
== 编译器与工程化 ==
<span id="什么时候上编译器"></span>
=== 什么时候上编译器 ===
满足任一条件就建议上:
* 代码 > 300 行
* 需要函数与复用
* 需要自动构建复杂条件
* 需要多人协作
<span id="编译器对比"></span>
=== 编译器对比 ===
{| class="wikitable"
|-
! 名称
! 特点
! 适配人群
|-
| mindcode
| 优化强、成熟
| 重性能
|-
| mlogjs
| JS/TS生态好
| 前端/脚本开发者
|-
| bang-lang
| 贴近 mlog、元编程强
| 深度控制流玩家
|}
<span id="工程化流水线"></span>
=== 工程化流水线 ===
推荐流程:
# 源码仓库
# 编译脚本
# 自动导出 mlog
# 回归测试图
# 版本发布
<span id="bang最小用法"></span>
=== bang 最小用法 ===
<pre>
mindustry_logic_bang_lang cl <<< 'print "Hello, World!";'
</pre>
----
----
<span id="155与146差异对照"></span>
== 155与146差异对照 ==
本章整理“旧教程常见说法”与 155 行为的关键差异.
{| class="wikitable"
|-
! 项目
! 146常见说法
! 155/当前基线
|-
| print缓冲上限
| 常被写成约220
| 源码上限为400<sup>[[#fn-5|5]]</sup>
|-
| 二/十六进制负号
| 多写作 0b-101, 0x-80
| 也支持 +0b/-0b/+0x/-0x
|-
| read/write对象范围
| 常仅讲内存
| 可扩展到字符串/信息板/画板/逻辑变量等
|-
| select语句
| 旧版本无
| 新版本可直接用
|-
| ucontrol细节
| 文档较少
| 选项与行为更丰富
|-
| control范围
| 严格依赖链接
| 某些版本行为有变化, 以当版实测为准
|}
<div class="mdtMarkdownAlert mdtMarkdownAlert-important">
若遇到“教程说法”和游戏行为冲突, 以当前版本实测 + 源码为准.
</div>
----
----
<span id="附录01-op方法进阶"></span>
== 附录01-op方法进阶 ==
{| class="wikitable"
|-
! 类别
! 操作
|-
| 算术
| add sub mul div idiv mod emod pow
|-
| 比较
| equal notEqual lessThan lessThanEq greaterThan greaterThanEq strictEqual
|-
| 位运算
| shl shr ushr and or xor not
|-
| 数学
| abs sign floor ceil round sqrt log log10 logn max min rand
|-
| 几何/三角
| len angle angleDiff sin cos tan asin acos atan noise
|}
要点:
* <code>mod</code> 与 <code>emod</code> 在负数时行为不同
* 位运算前会转整数
* 三角函数是角度制
----
<span id="附录02-传感器速查"></span>
== 附录02-传感器速查 ==
{| class="wikitable"
|-
! 分类
! 属性
|-
| 坐标
| x y shootX shootY mineX mineY
|-
| 生存
| health maxHealth dead shield armor
|-
| 资源
| totalItems totalLiquids totalPower itemCapacity liquidCapacity powerCapacity
|-
| 行为
| enabled shooting boosting mining speed range
|-
| 标识
| team type id name controlled controller flag
|-
| 载荷
| payloadType payloadCount totalPayload payloadCapacity
|-
| 文本/显示
| size bufferSize displayWidth displayHeight
|}
----
<span id="附录03-环境变量速查"></span>
== 附录03-环境变量速查 ==
<span id="逻辑信息"></span>
=== 逻辑信息 ===
* <code>@this</code> / <code>@thisx</code> / <code>@thisy</code>
* <code>@links</code>
* <code>@unit</code>
* <code>@ipt</code>
* <code>@counter</code>
<span id="常量与数学"></span>
=== 常量与数学 ===
* <code>true</code> <code>false</code> <code>null</code>
* <code>@pi</code> <code>@e</code>
* <code>@degToRad</code> <code>@radToDeg</code>
<span id="世界变量"></span>
=== 世界变量 ===
* <code>@time</code> <code>@tick</code> <code>@second</code> <code>@minute</code>
* <code>@waveNumber</code> <code>@waveTime</code>
* <code>@mapw</code> <code>@maph</code>
<span id="lookup计数"></span>
=== lookup计数 ===
* <code>@itemCount</code>
* <code>@unitCount</code>
* <code>@blockCount</code>
* <code>@liquidCount</code>
----
<span id="附录04-术语表"></span>
== 附录04-术语表 ==
{| class="wikitable"
|-
! 术语
! 解释
|-
| 跳表
| 是什么: 用 @counter 偏移把输入值映射到不同代码块。作用: 用常数时间完成多分支分派。
|-
| 匹配守卫
| 是什么: 在进入某个分支前额外检查一次条件的跳转。作用: 让同一个 case 支持更细粒度筛选。
|-
| 穿透
| 是什么: 分支执行后没有跳出, 继续执行后续分支。作用: 可用于刻意复用后续逻辑, 也可能引发误执行。
|-
| 阻塞
| 是什么: 在一行或几行上反复循环等待条件。作用: 保证条件满足后再继续, 但会牺牲推进速度。
|-
| 协议
| 是什么: 多处理器共享内存字段和时序规则的约定。作用: 避免协作时读写歧义和乱序。
|-
| 抢控
| 是什么: 单位控制权被其他逻辑或玩家接管。作用: 提醒当前控制逻辑需要重绑或回退。
|-
| 心跳
| 是什么: 持续递增并回写的计数值。作用: 用来判断某个处理器是否仍在运行。
|-
| 消费者心跳
| 是什么: 由消费者处理器维护的心跳值。作用: 让生产者检测消费者是否卡住或停机。
|-
| ACK
| 是什么: Acknowledgement, 命令已处理完成的回执值。作用: 让发送方确认可进入下一步。
|-
| 卡死
| 是什么: 逻辑没有崩溃, 但长期停在同一等待或循环。作用: 作为故障信号触发恢复流程。
|-
| 速率保险丝
| 是什么: 短时提速后自动回落的保护策略(本教程命名)。作用: 防止 setrate 长期高负载导致全局卡顿。
|-
| 看门狗
| 是什么: 监控流程是否长期无进展的保护计数器。作用: 超时后触发重置或降级恢复。
|}
<span id="术语-人话例子"></span>
=== 高频术语(一句人话 + 最小例子) ===
<span id="术语-心跳"></span>
'''心跳''': 一句话人话: 一个持续变化的数字, 用来证明“这个逻辑还活着”.
最小例子:
<pre>
op add hb hb 1
op mod hb hb 1000000
write hb bank1 1
</pre>
<span id="术语-消费者心跳"></span>
'''消费者心跳''': 一句话人话: 消费者处理器每轮报平安, 让生产者知道它没停机.
最小例子:
<pre>
# consumer side
op add hb_c hb_c 1
op mod hb_c hb_c 1000000
write hb_c bank1 2
</pre>
<span id="术语-ack"></span>
'''ACK''': 一句话人话: “我这条命令做完了”的回执信号.
最小例子:
<pre>
# producer
write 200 bank1 3
read ack bank1 6
jump 0 notEqual ack 200
# consumer
read cmd bank1 3
# ...do work...
write cmd bank1 6
</pre>
<span id="术语-卡死"></span>
'''卡死''': 一句话人话: 逻辑没崩, 但一直卡在某个等待/循环里, 业务不前进.
最小例子:
<pre>
wait_btn:
sensor on switch1 @enabled
jump wait_btn equal on false
# 按钮不变真就会一直卡在这里
</pre>
<span id="术语-速率保险丝"></span>
'''速率保险丝(本教程命名)''': 一句话人话: 短时提速, 自动回落, 防止 setrate 长期高负载.
最小例子:
<pre>
setrate 20
# heavy work ...
wait 0.2
setrate 1
</pre>
<span id="术语-看门狗"></span>
'''看门狗''': 一句话人话: 发现流程长期没进展就触发恢复动作.
最小例子:
<pre>
jump progressed notEqual step lastStep
op add stuck stuck 1
jump chk always 0 0
progressed:
set stuck 0
set lastStep step
chk:
jump ok lessThan stuck 600
    # recovery
    set state 0
ok:
</pre>
----
<span id="附录05-排错清单"></span>
== 附录05-排错清单 ==
请按顺序检查:
# 变量是否初始化
# 链接名是否存在且正确
# 是否同队伍且有权限
# @counter 是否跳飞
# 是否被 wait/stop 阻塞
# 单位是否被抢控
# 协议版本是否一致
# ACK 是否回写
# flush 频率是否过高
# 是否触发了安全门
最小排错模板:
<pre>
print "state="; print state
print " err="; print err
print " ack="; print ack
printflush message1
</pre>
----
<span id="注释"></span>
== 注释 ==
* <span id="fn-2"></span> [2] @counter 四步模型是理解所有高级控制流的基础.
* <span id="fn-3"></span> [3] 递归调用必须隔离返回地址和跨调用变量.
* <span id="fn-4"></span> [4] 单位控制语句会发控制信号, 非必要不要滥用.
* <span id="fn-5"></span> [5] 当前基线中 textBuffer 上限为 400.
* <span id="fn-6"></span> [6] 跳表前务必约束输入范围.
* <span id="fn-7"></span> [7] 复杂条件转换时优先做逻辑代数化简.
* <span id="fn-8"></span> [8] guard 优先处理“高概率失败”分支可减少执行成本.
* <span id="fn-9"></span> [9] while 和 gwhile 选型取决于条件反转成本.
* <span id="fn-10"></span> [10] 函数建议统一入参/出参/返回地址变量命名.
* <span id="fn-11"></span> [11] 非递归函数的返回地址常用 @counter+1.
* <span id="fn-12"></span> [12] 递归函数要保证栈平衡, 否则会读错返回地址.
* <span id="fn-13"></span> [13] 多处理器协作应先定协议再写代码.
* <span id="fn-14"></span> [14] 心跳变量建议做取模防止无限增长.
* <span id="fn-15"></span> [15] ACK 建议回写命令码本身, 便于无状态校验.
* <span id="fn-16"></span> [16] 单位控制需持续刷新, 否则控制会过期.
* <span id="fn-17"></span> [17] owner 校验可快速检测抢控.
* <span id="fn-18"></span> [18] 批处理策略是性能优化的第一手段.
* <span id="fn-19"></span> [19] 世界处理器高风险操作必须有硬开关.
* <span id="fn-20"></span> [20] 任何 setblock 类操作建议保留回滚信息.
* <span id="fn-21"></span> [21] setrate 只应短时升高, 长时高频会压垮整体.
* <span id="fn-22"></span> [22] flush 过频是常见卡顿源.
* <span id="fn-23"></span> [23] 输出日志尽量结构化, 便于排错脚本解析.
* <span id="fn-24"></span> [24] 命名规范是多人协作里性价比最高的质量手段.
* <span id="fn-25"></span> [25] 注释写“原因”优先于“动作”.
* <span id="fn-26"></span> [26] 编译器能显著降低复杂控制流的人肉错误率.
* <span id="fn-27"></span> [27] 版本迁移先做差异表再做迁移计划.
* <span id="fn-28"></span> [28] mod/emod 的负数行为不同, 算法里要明确选型.
* <span id="fn-29"></span> [29] 位运算要注意数值转换与范围精度.
* <span id="fn-30"></span> [30] strictEqual 与 equal 的语义差别在类型一致性.
* <span id="fn-31"></span> [31] 逻辑代数化简可减少 jump 数量和维护成本.
* <span id="fn-32"></span> [32] 先保证正确性再做局部性能优化.
* <span id="fn-33"></span> [33] 协议字段建议保留错误码便于远程诊断.
* <span id="fn-34"></span> [34] 调试逻辑与业务逻辑建议分离处理器.
* <span id="fn-35"></span> [35] 对外交互 (message/marker) 建议加频率限制.
* <span id="fn-36"></span> [36] 内存地址使用建议维护单独映射表.
* <span id="fn-37"></span> [37] 每次大改应维护 migration 日志.
* <span id="fn-38"></span> [38] 逻辑蓝图发布建议附最小测试图.
* <span id="fn-39"></span> [39] 复杂项目推荐 CI 自动导出并做语法检查.
* <span id="fn-40"></span> [40] 本教程若与将来版本冲突, 以新版本实测为准.
----
</div>

2026年3月5日 (四) 18:40的最新版本