☰
Besiege机械三进制计算机实战:全加器逻辑设计与搭建指南
2026/10/20 7:59:54 网站建设 项目流程

如果你在 Besiege 里用轮子、活塞和逻辑门搭建过一些能“动起来”的装置,那么“在三进制计算机里做一块全加器”这个目标会是一个非常有趣的进阶挑战。今天这篇文章,我从三进制全加器的逻辑设计讲起,再落到 Besiege 机械结构的具体拆分思路,完整记录机械三进制计算机开发中最关键的这个环节。内容偏工程向,适合对 Besiege 机械感兴趣、或想了解非二进制逻辑电路设计的玩家与开发者;读完你不仅能理解三进制全加器难在哪里、怎么设计,还能照着搭建思路在自己游戏存档里从零拼出一个可以验证的全加器模块。

1. 机械三进制计算机与全加器:为什么值得做

1.1 Besiege 里也能造“计算机”?

Besiege 是一款以物理沙盒建造为主的游戏,看似目标只是造攻城机器,但它提供了足够丰富的机械模块:梁、轮子、活塞、弹簧、铰链、旋转关节、逻辑门、传感器,甚至炸弹。这些模块组合起来,可以做成复杂的机械传动系统,也可以做成类似早期机械计算机的逻辑装置。

普通玩家在 Besiege 里搭投石机、坦克、飞机,而计算机制作者在 Besiege 里搭的是“能计算的机器”。你可能见过用二进制逻辑门搭出的内存、加法器、甚至简单 CPU;这类作品的核心思路就是用逻辑门与机械结构表示“0 / 1”两个状态,再用这些状态完成运算。

三进制机械计算机则是更小众、更偏门的方向。它不依赖“通 / 断”二进制,而是用三种状态表达一位数字。在 Besiege 这种物理引擎下,三进制的实现方式反而有可能比二进制更自然,因为一个转轴可以用三个角度位置表达三个状态,不需要额外组合多路信号。

1.2 为什么选择三进制?

经典数字电路中二进制占了绝对统治地位,因为电子器件最容易区分“低电平 / 高电平”。但三进制在数学上并非没有优势,尤其平衡三进制,使用-1 / 0 / 1三个数字,可以直接表达负数,某些运算规则比二进制更对称、更直观。

在 Besiege 机械环境中,三进制更加诱人。原因有两点:

  • 二进制信号必须用“有没有位移”“有没有电压”来表达,需要一个明确的阈值;但机械零件受物理引擎影响,很难精确卡在“有 / 无”两个边界。
  • 三进制可以用一个旋转关节或多个挡块的位置直接表示,比如:
状态 0:旋转关节角度为 0° 状态 1:旋转关节角度为 45° 状态 2:旋转关节角度为 90°

这种“连续位置表达多值状态”的方式,比纯逻辑门组合更接近机械本质,也更容易让新材料玩家理解。

1.3 全加器:机械计算机的起点

全加器是数字电路里最基础、也最重要的运算模块之一。它能把两个一位数字相加,并接受来自低位的进位,输出本位和以及向高位的进位。有了全加器,就能并联成多位加法器;有了多位加法器,就能继续扩展减法、乘法、除法等更多运算。

因此,在做机械三进制计算机时,全加器往往是整个运算器开发的第一块里程碑。把三进制全加器在 Besiege 里跑通,后面很多模块就有了稳定的复用单元。

2. 从二进制全加器到三进制全加器

2.1 先复习二进制全加器

二进制全加器有三个输入:本位加数A、加数B、低位进位Cin;两个输出:和位S、进位Cout。

二进制一位加法的规则是:

A + B + Cin = 2 * Cout + S

其中S是除以 2 的余数,Cout是除以 2 的商。

真值表如下:

ABCinCoutS
00000
00101
01001
01110
10001
10110
11010
11111

二进制全加器的逻辑表达式是:

S = A ⊕ B ⊕ Cin Cout = (A AND B) OR (Cin AND (A ⊕ B))

其中的核心思想是:先把两个加数相加,如果溢出,就向高位进位。

2.2 三进制全加器的定义

三进制全加器的输入从两个“0 / 1”变成了三个可能的数字:0 / 1 / 2。它的输入仍然有三个:一位三进制加数A、一位三进制加数B、以及来自低位的三进制进位Cin。

三进制一位加法的规则是:

A + B + Cin = 3 * Cout + S

也就是说,A + B + Cin的和值除以 3,商就是进位Cout,余数就是本位和S。

为什么进位也用三进制而不是只有 0 / 1?因为两个三进制位相加,最大值是:

2 + 2 + 2 = 6

而 6 用三进制表示是:

6 = 2 * 3 + 0

也就是说进位可以是 2,而不只是 0 或 1。这是三进制全加器和二进制全加器非常关键的区别。

2.3 三进制全加器的统一真值表

因为加法结果只取决于A + B + Cin的总和total,我们可以用一张非常紧凑的表来描述三进制全加器:

totalCoutSum
000
101
202
310
411
512
620

从这张表可以看出:

  • total < 3时,不产生进位,Sum = total。
  • 3 <= total <= 5时,产生 1 次进位,Sum = total - 3。
  • total = 6时,产生 2 次进位,Sum = 0。

这个“查表式”的设计思路比推导布尔表达式更适合 Besiege 机械实现。因为机械结构很难表达复杂的逻辑门网络,但可以用“位置”“角度”“凸轮”等物理方式把不同的total值映射到不同输出位置。

2.4 关于平衡三进制的扩展说明

三进制还有一种更优雅的编码方式:平衡三进制,也叫对称三进制,使用-1 / 0 / 1三个数字。它的优势是负数可以直接表示,不用单独引入符号位;进位规则也更加对称。

但在机械计算机的实际开发中,平衡三进制需要一个额外的问题:如何处理负角、负位移?比如用转轴角度表示-90° / 0° / 90°,那么在加法模块中,两个负角相加就可能超出机械限位。因此本文第一版全加器采用0 / 1 / 2编码,等主逻辑跑通后再扩展平衡三进制版本,会更稳妥。

3. Besiege 中表达三态信号的几种方案

在开始动手搭建之前,先确定“三态信号”在游戏里到底用哪种物理形态表达。这个选择直接决定了后面所有模块的设计复杂度。

3.1 方案一:旋转关节角度

用一个旋转关节(Rotation Joint)或铰链,通过限位块限制它在三个固定角度之间切换,例如:

数字 0:0° 数字 1:45° 数字 2:90°

好处是状态直观、便于观察,配合齿轮或连杆可以和其他模块联动。缺点是传动过程中存在间隙(Backlash),角度可能漂移;高负载下容易滑齿,需要加锁定结构。

3.2 方案二:多路二进制信号组合

用两根活塞或两个逻辑门分别表示几个布尔信号,然后组合出三态。例如:

状态 0:信号 X = 0,信号 Y = 0 状态 1:信号 X = 1,信号 Y = 0 状态 2:信号 X = 1,信号 Y = 1

本质上是用“二进制的多根线”编码一个三进制位。这样做的好处是逻辑门、传感器等现有模块可以直接复用;坏处是占空间、布线复杂,而且失去了“三进制直观”的意义。

3.3 方案三:滑块位移

使用活塞或滑块的长短位置来表示三态:

数字 0:活塞收回 数字 1:活塞半伸出 数字 2:活塞完全伸出

滑块位移的好处是方便通过碰撞体触发逻辑,坏处是高精度定位比较困难,物理引擎的碰撞抖动会影响位移稳定性。

3.4 三种方案对比与选择

方案空间占用精度逻辑门依赖推荐度
旋转关节角度小中低高
多路二进制组合大高高中
滑块位移中低中低

在实际搭建中,我更推荐以“旋转关节角度”作为主编码方案。它最贴合机械三进制的概念,而且能够用较少的零件表达三个状态。后文中的核心模块设计,也默认采用角度编码。

4. 三进制全加器总体架构设计

4.1 输入与输出约定

先约定输入输出接口:

输入 A:0 / 1 / 2 输入 B:0 / 1 / 2 输入 Cin:0 / 1 / 2 输出 Sum:0 / 1 / 2 输出 Cout:0 / 1 / 2

在机械上,每个信号都对应一个“三态角度轴”。

4.2 模块划分

三进制全加器可以拆成四个模块:

  1. 输入编码模块:把玩家操作或前级模块带来的状态,转换成统一的三态角度信号。
  2. 求和判定模块:接收三个输入的角度,根据total = A + B + Cin判断总和大类。
  3. 进位生成模块:根据 total 是否大于等于 3,生成Cout的角度输出。
  4. 求余输出模块:根据 total 对 3 取余的结果,生成Sum的角度输出。

4.3 模块之间的信号关系

可以用文字描述整体数据流:

A ──→ 求和判定模块 ──→ 进位生成模块 ──→ Cout B ──→ 求和判定模块 ──→ 求余输出模块 ──→ Sum Cin ──→ 求和判定模块

求和判定模块内部不做复杂逻辑运算,只负责把三个输入位置“叠加”起来,得到一个物理位置或机械结构状态,供后续两个输出模块读取。这种拆法对应了前面的真值表:

total = A + B + Cin Cout = total / 3(整除) Sum = total % 3(取余)

5. 核心模块的机械实现思路

5.1 求和判定模块:角度叠加

Besiege 里要把两个或多个转轴的角度“相加”,最常见的机械结构是差速器(差动齿轮组)。差速器的特性是:两个输入轴的旋转角度之差会体现在输出轴上。理论上,只要把输入 A 和输入 B 接到差速器的两个输入端,输出轴就能得到“A 的角度 - B 的角度”或“A 的角度 + B 的角度”的某种线性组合。

但在实际游戏中,差速器对安装精度和齿轮咬合要求较高,容易出现滑齿和卡死。一个更容易落地的替代方案是使用连杆 + 滑块:

两个输入轴分别推动滑块,滑块位移通过连杆叠加成一个总位移,再用这个总位移去触发后续判定。

这种方案牺牲了一些精度,但调试难度低很多,也更容易理解。

求和判定模块的最终目标是:让机械结构产生七个可区分的位置区域,对应total = 0 到 6。例如给输出轴安装一个有 7 个齿的棘轮,使它能卡在 7 个不同角度位置之一。

5.2 进位生成模块:阈值判定

当total >= 3时,需要产生进位。进位有 0 / 1 / 2 三种状态:

total = 0,1,2 → Cout = 0 total = 3,4,5 → Cout = 1 total = 6 → Cout = 2

机械实现一种方式是“挡块判定”,在total对应的角度轴上安装几个碰撞体,只有当轴转到特定位置时,才触碰进位输出杆:

  • total小于 3:进位杆保持 0 位;
  • total等于 3、4、5:进位杆被推到 1 位;
  • total等于 6:进位杆被推到 2 位。

这种设计类似于机械式凸轮控制,不需要逻辑门,纯靠物理位置完成阈值判定。

5.3 求余输出模块:余数映射

求余输出模块处理Sum = total % 3:

total = 0,3,6 → Sum = 0 total = 1,4 → Sum = 1 total = 2,5 → Sum = 2

注意这里比较特殊:三个不同的total值可能对应同一个Sum。这意味着求余模块不能简单只判断“某个位置”,它需要把不同位置归并到三个输出状态之一。

一种可行做法是使用带凸轮轮廓的转盘:

转盘根据 total 旋转到 0 到 6 的对应位置。 转盘边缘有一个曲线槽,曲线高度按 0,1,2,0,1,2,0 规律变化。 一根随动杆压在曲线槽里,槽的高度决定了 Sum 输出角度。

这种“机械凸轮映射”非常经典,也是三进制机械计算机比二进制机械计算机更有趣的地方之一。

5.4 同步与精度问题

机械计算机与电子计算机最大的不同是:它没有全局时钟。各模块之间的运动速度受物理引擎影响,可能不同步。比如 A 输入已经到位,但 B 输入还在路上,求和判定模块就会短暂处于错误状态。

为了避免这个问题,通常在输入模块加入“锁定结构”:

输入未全部就位前,求和判定模块被一个挡块锁住,不跟随输入变化。 当三个输入都到位后,释放挡块,让求和模块完成一次求值。

这种“先锁定,后释放”的流程,本质上就是机械计算机的门控时钟。

6. 用 Python 验证三进制全加器逻辑

在进入 Besiege 搭建前,强烈建议先用脚本把逻辑验证一遍,避免游戏里机械结构搭好了,最后却发现整个真值表设计错了。下面是一段可以直接运行的 Python 模拟脚本。

# 文件名:ternary_adder.py # 作用:模拟三进制全加器逻辑,验证真值表 def ternary_add(a: int, b: int, cin: int): """三进制一位全加器。 参数: a: 0/1/2 b: 0/1/2 cin: 0/1/2 返回: (sum, cout),sum 为本位和,cout 为进位 """ total = a + b + cin sum_ = total % 3 cout = total // 3 return sum_, cout def run_all_tests(): """遍历所有输入组合,检查输出与真值表是否一致。""" expected = { (0, 0, 0): (0, 0), (0, 0, 1): (1, 0), (0, 0, 2): (2, 0), (0, 1, 0): (1, 0), (0, 1, 1): (2, 0), (0, 1, 2): (0, 1), (0, 2, 0): (2, 0), (0, 2, 1): (0, 1), (0, 2, 2): (1, 1), (1, 0, 0): (1, 0), (1, 0, 1): (2, 0), (1, 0, 2): (0, 1), (1, 1, 0): (2, 0), (1, 1, 1): (0, 1), (1, 1, 2): (1, 1), (1, 2, 0): (0, 1), (1, 2, 1): (1, 1), (1, 2, 2): (2, 1), (2, 0, 0): (2, 0), (2, 0, 1): (0, 1), (2, 0, 2): (1, 1), (2, 1, 0): (0, 1), (2, 1, 1): (1, 1), (2, 1, 2): (2, 1), (2, 2, 0): (1, 1), (2, 2, 1): (2, 1), (2, 2, 2): (0, 2), } for (a, b, cin), exp in expected.items(): sum_, cout = ternary_add(a, b, cin) if (sum_, cout) != exp: print(f"错误: A={a}, B={b}, Cin={cin} => Sum={sum_}, Cout={cout}, 期望={exp}") return False print("全部 27 组测试通过") return True if __name__ == "__main__": run_all_tests()

运行脚本:

python ternary_adder.py

预期输出:

全部 27 组测试通过

有了这个测试脚本,你在 Besiege 里搭出来的机械结构就可以对照真值表逐项验证;后续做多位加法器时,也可以直接复用这个函数。

7. Besiege 内搭建流程实战

下面给出一个从零开始的搭建顺序。每个步骤都尽量给出设计意图,而不是简单贴零件清单。

7.1 第一步:搭建基础机架

全加器至少有三个输入模块、一个核心判定模块、两个输出模块。建议先做一个规整的底座机架,把各模块固定在确定位置,避免后期机械结构移动导致信号错位。

机架要点:

  • 使用大块木质或金属梁做底盘,保证重量稳定;
  • 四个角加轮子或固定块,防止整体位移;
  • 为每个模块预留足够操作空间。

7.2 第二步:制作输入编码模块

输入编码模块的任务是让玩家可以手动切换 0 / 1 / 2 三个状态。这里可以用旋转关节加上两个限位块:

角度 0° 到 45° 对应数字 0 角度 45° 到 90° 对应数字 1 角度 90° 以上对应数字 2

更好的做法是直接用三个固定挡块卡死三个位置,这样玩家每次都能精准停在 0°、45°、90°,不会因为手抖而停在中间状态。

7.3 第三步:搭建求和判定模块

这一步是核心,也是调试时间最长的部分。推荐先用“连杆位移叠加”方案验证逻辑,再优化成齿轮差速器方案。

连杆位移叠加的基本思路是:

  1. 三个输入轴分别连接到三根连杆;
  2. 三根连杆共同推动一个滑动块;
  3. 滑动块的位移等于三个输入位移之和。

这样我们就可以通过滑动块的位置判断total。

接着在滑动块旁边安装一个有 7 个定位槽的棘轮,让滑动块每次只能停在0 到 6的某个槽位。这个槽位就是total。

要注意的是,机械结构在高负载下会变形,如果三个连杆推同一个滑块,摩擦力可能很大,建议给滑块加滚动支撑或使用轻质材料。

7.4 第四步:搭建设进位生成模块

进位生成模块要从求和判定模块取走total位置信号,并输出Cout。

最简单的实现:

  • 当滑块在槽位 0、1、2 时,进位杆保持 0 位;
  • 当滑块在槽位 3、4、5 时,进位杆被推杆推到 1 位;
  • 当滑块在槽位 6 时,进位杆被推到 2 位。

可以用一个带不同高度凸点的“随动板”完成映射。随动板的高度差直接决定进位输出轴的角度。

7.5 第五步:搭建求余输出模块

求余输出模块类似,但需要把槽位映射到三个 Sum 状态:

槽位 0、3、6 → Sum 角度 0° 槽位 1、4 → Sum 角度 45° 槽位 2、5 → Sum 角度 90°

实现方式是做一个“三段高度曲线”的凸轮板,或者用三个逻辑门分别识别三组槽位,再驱动同一根输出轴。

7.6 第六步:加装锁定与校准装置

最后,在所有输入模块上加装“到位锁定”结构。只有当三个输入都处于稳定状态时,才释放求和判定滑块,避免中间状态进入判定模块。

校准方法:

  • 逐个输入组合,观察Sum和Cout是否落在预期槽位;
  • 如果某个槽位偏差,检查联动杆的长度和限位块;
  • 每个状态固定后,在对应位置添加挡块,防止再次漂移。

8. 测试用例与验证方法

8.1 关键测试用例

不建议第一次就把 27 组全部测完,先测代表性组合即可。以下覆盖了total从 0 到 6 的所有情况:

编号ABCin期望 Sum期望 Couttotal
1000000
2001101
3011202
4111013
5121114
6022115
7222026

这 7 组用例覆盖了进位 0 / 1 / 2 三种情况,也覆盖了 Sum 为 0 / 1 / 2 的所有取值,能快速暴露大部分逻辑问题。

8.2 手动测试步骤

  1. 把三个输入模块分别调整到期望角度;
  2. 等待 1 到 2 秒,让物理结构稳定;
  3. 观察Sum输出轴和Cout输出轴所在角度;
  4. 对照期望值表格记录结果。

如果出现错误,不要急着改整个结构,先确认是“输入没有到位”还是“判定模块映射错误”。一个简单的方法是:在求和判定模块的滑动块上看当前total槽位是否正确。如果滑动块位置正确,说明问题出在输出映射模块;如果滑动块位置不对,说明问题出在求和层级。

8.3 自动验证思路

随着模块变大,手动测试会越来越耗时。可以在所有关键轴上安装角度传感器或颜色标记,然后用 Besiege 的录像/截图功能记录每一帧的信号角度,再批量对照真值表。

更好的方式是利用外部工具:

用 Python 读取导出的测试记录文件,逐帧校验角度是否处于合法状态集合。

这样可以把整个验证过程自动化,为后续多位加法器铺路。

9. 常见问题与排查思路

机械结构与纯逻辑脚本不同,容易出现各种物理层面的问题。下面整理几个高频问题与排查建议。

问题现象常见原因排查思路
Sum 输出偶尔跳动齿轮间隙、连杆虚位在关键轴增加限位块,使用轻质高强度材料
进位信号比 Sum 慢进位判定链路过长缩短传动链,将进位判定移到靠近求和模块的位置
输入状态无法稳定停在 0/1/2限位块位置不准确或反冲重新校准限位块,增加阻尼或弹簧锁定
滑块被卡死多个连杆同时推动产生过约束改用差速器或减少推动点,增加滑块润滑
高负载下零件变形结构强度不足加装支撑梁,尽量让受力沿直线传递
求和位置偏移导致进位误触发联动杆长度不一致逐级测量每个输入到滑块的位移比
测试时结果时对时错没有等待物理稳定就读取每次操作后延迟 1 到 2 秒再读取输出

遇到问题时,建议遵循“先定位、再修改”的原则。不要一上来就拆整个结构,而是用标识笔或颜色标记为每个轴标出目标角度,然后分段检查。

10. 最佳实践与工程建议

10.1 模块先独立验证,再组合

在 Besiege 里搭机械计算机,最容易犯的错误是“一步到位”。全加器整体结构复杂,如果一次性拼完再排查,bug 可能散布在多个模块之间,极难定位。

建议的做法是:

  1. 先单独搭好输入模块,验证三个角度稳定可切换;
  2. 再搭求和判定模块,用三个独立的手动输入去推滑块,验证total槽位正确;
  3. 最后才接入进位生成和求余输出模块。

每一步验证通过后再进入下一步,出问题就能缩小范围。

10.2 做好存档版本管理

每完成一个里程碑模块,建议另存一个新存档。机械结构在调试时经常发生“之前还能动,改了两根梁就卡死”的情况。存档版本管理能让你快速回退。

10.3 优先使用机械结构,而不是逻辑门堆砌

Besiege 的性能对零件数量很敏感,逻辑门虽然方便,但数量多了会导致帧率下降、物理模拟不稳定。如果同一功能可以用齿轮或凸轮实现,优先选择机械结构。这既是性能考虑,也是三进制机械计算机的乐趣所在。

10.4 统一信号约定

在搭建前先定好三态角度约定。比如:

0 → 0° 1 → 45° 2 → 90°

所有模块都必须严格遵循这个约定。混用角度范围会导致后续扩展时,进位输出无法前后级联。

10.5 为扩展保留接口

全加器将来可能需要连成多位加法器,所以在设计输入输出轴时,尽量把接口留在模块两侧,不要被装饰零件遮挡。同时给Cout输出轴预留足够的连接空间,方便把它接到下一级的Cin上。

10.6 控制零件规模

一个全加器如果用纯机械方式实现,零件数量可能在几十到上百之间。如果零件太多,可以考虑以下几个优化方向:

  • 用更少的支撑梁,减少冗余结构;
  • 用逻辑门替代传动链过长的纯机械判定;
  • 使用对称布局,用同一套结构同时处理多路信号。

11. 下一步:向多位加法器与平衡三进制扩展

全加器跑通后,机械三进制计算机的运算核心就具备雏形了。下一步可以沿着两个方向深入。

11.1 级联多位三进制加法器

把多个全加器的Cout依次接到下一级的Cin,就能构成 ripple carry 多位加法器:

bit0 全加器 (A0, B0, 0) → Cout0 bit1 全加器 (A1, B1, Cout0) → Cout1 bit2 全加器 (A2, B2, Cout1) → Cout2 ...

这种结构简单、容易理解,但存在进位传播延迟。在 Besiege 里,机械传动的延迟更大,所以多位加法器必须考虑同步问题。一种改进方案是“进位旁路”或“进位前瞻”,但机械实现难度较高,可以作为进阶挑战。

11.2 尝试平衡三进制

如果你已经熟悉了0 / 1 / 2编码,可以挑战平衡三进制-1 / 0 / 1。

平衡三进制的优点在于:

  • 负数可以直接表示;
  • 加法的进位规则更对称;
  • 输出可以在结构上复用更多模块。

但它对机械结构的要求更高,因为状态对应角度可能是:

-1 → -90° 0 → 0° 1 → 90°

这需要转轴范围覆盖更大的角度,且要对负角度进行限位。调试时也需要一套不同的映射逻辑。

11.3 从加法器走向完整运算器

有了加法器之后,可以通过补码实现减法;通过“移位 + 加法”实现乘法;通过循环减法实现除法。这些运算最终可以组成一个完整的机械三进制运算器。

如果再搭配机械存储模块,比如用齿轮组状态保存数据,那么一个真正的 Besiege 机械三进制计算机就已经具雏形了。当然,这会是一个非常宏大的工程,需要极强的耐心和结构设计能力。

12. 写在最后的实践建议

三进制全加器只是整台机械三进制计算机开发的第一步,但它完全值得单独作为一次开发记录来总结。逻辑上它比二进制全加器多了一倍以上的状态组合,机械上又要在同一个物理世界里处理三态角度、进位判定和同步问题,每个环节都考验设计与调试能力。

如果你准备在 Besiege 里尝试同样的事情,我的建议是:不要追求一步到位。先从最小的输入编码模块开始实验,把“角度表达三态”这个基础弄扎实,再逐步搭建求和与进位模块。调试时不要嫌麻烦,每一步都对照真值表记录下来,错误会更容易定位。

接下来我计划继续完善三进制全加器的机械结构,再做一个小型的多位加法器原型,并把平衡三进制的引入提上日程。如果你也在做 Besiege 机械计算,欢迎一起交流思路和踩坑经验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询