ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

在Besiege中搭建三进制全加器:物理机械与逻辑设计

在Besiege中搭建三进制全加器:物理机械与逻辑设计 前几天我在整理“Besiege 里造计算机”这堆存档时又点开了那个调了一半的三进制全加器。很多人看到“Besiege”第一反应是这不是那个拼攻城车、扔石头砸城堡的游戏吗对但它的底层其实是一个完整的物理沙盒——齿轮、活塞、铰链、传感器、木头和铁块理论上什么都能拼出来。有人拿它拼高达有人拿它复刻歼星舰也有人像我一样试图用中世纪风格的机械零件造一台三进制计算机。先说判断在 Besiege 里做三进制计算机真正难的从来不是“三进制怎么算”而是“怎么把一个抽象的加法规则变成一组能在物理引擎里稳定工作的齿轮、推杆和触发机构”。全加器是所有计算单元的起点二进制计算机绕不开它三进制计算机同样绕不开。这篇文章会把 Besiege 机械三进制全加器的开发过程拆开来讲先确立三进制全加器的逻辑模型再把它映射到 Besiege 的机械零件上最后给出分步搭建、验证和排错的完整思路方便你想自己复刻或者做进一步扩展。如果你正在玩 Besiege或者对计算机组成原理、非二进制计算感兴趣这篇文章应该能给你一个不太一样的视角三进制全加器不只是一个游戏里的花活它会把你对“信息编码”和“物理逻辑”的理解一起推翻重建。1. 这篇文章真正要解决的问题先说一个现实问题在 Besiege 里造二进制加法器的玩家已经很多了但做三进制的非常少。原因不只是三进制冷门更在于“三态信号”在机械里很难表示。二进制只需要区分“有”和“无”在机械里可以用“推到左边/推到右边”来实现三进制需要区分三种状态要么用三个位置要么用两路二值信号组合每一种都要面对更复杂的机构设计和物理误差。为什么从全加器开始因为无论二进制、三进制还是十进制算术运算的核心单元都是全加器。全加器处理的是三个输入两个加数位和一个低位进位输出本位和与高位进位。一个加法器阵列本质上就是一个一个全加器串联起来。你要在 Besiege 里造出一台能算加减乘除的三进制计算机第一步就是把全加器做得稳定可靠。这篇文章会解决四个问题三进制全加器的逻辑到底怎么描述和二进制全加器差在哪。如何在 Besiege 的零件体系里编码三态信号以及不同编码方案的优劣。如何把“求和”和“进位”这两个逻辑动作用机械结构实现出来。在实际搭建中容易遇到哪些坑怎么排查。需要说明的是这篇博客偏设计思路和验证方法不是一张“照着摆零件就能复刻”的建筑图纸。Besiege 的版本更新会影响零件参数和物理表现但底层思路是通用的。2. 三进制与二进制先搞清楚全加器要算什么2.1 二进制全加器回顾二进制全加器的逻辑大家都很熟输入 A、B、C_in都是 0 或 1输出 S 和 C_outS 是本位和C_out 是进位。用布尔表达式写就是S A XOR B XOR C_inC_out (A AND B) OR (C_in AND (A XOR B))从算术角度理解更简单S (A B C_in) % 2C_out (A B C_in) / 2 取整数部分。二进制之所以在电子计算机里一统天下核心原因是电子元件最容易区分“高电平”和“低电平”两个状态。三态电平不是做不到而是代价高、抗干扰差所以现实中三进制计算机非常罕见。2.2 三进制的两种定义三进制并不只有一种定义。常见的有两种常规三进制数字位取 0、1、2。平衡三进制数字位取 -1、0、1。平衡三进制历史上很有名因为它在表示负数时浑然天成不需要单独的正负号位。苏联的 Сетунь 计算机用的就是平衡三进制。在 Besiege 机械层面平衡三进制有一个天然的优势对称性。机械结构里一个零件可以停在“左边 / 中间 / 右边”对应 -1 / 0 / 1左右对称视觉和调试都很直观。而常规三进制 0/1/2 的三个位置是非对称的机构设计会更别扭。下面我们同时考虑两种三进制但重点放在平衡三进制上。2.3 三进制全加器的真值表三进制全加器同样有三个输入A、B、C_in但每个输入可能取三种值。输出也有两个本位和 S进位 C_out。如果按常规三进制来定义直接套十进制算术规则S (A B C_in) % 3C_out floor((A B C_in) / 3)A、B、C_in 每个最大都是 2所以 A B C_in 最大是 6。C_out 的取值可能是 0、1、2。如果是平衡三进制情况稍微复杂一点因为加法运算的结果要先转换回平衡三进制表示。举一个关键例子1 1 0 2十进制2十进制 1 × 3 (-1) × 1所以在平衡三进制中表示为“1T”T 表示 -1于是本位 S -1进位 C_out 1这看起来反直觉但这正是平衡三进制的特征本位可以“借”给进位使每一位的取值范围始终保持在 -1、0、1。下表是几个代表性输入组合的常规三进制和平衡三进制输出对比ABC_inABC_in常规三进制 S常规三进制 C_out平衡三进制 S平衡三进制 C_out00000000110220-112204111122260202?最后一个例子需要小心十进制的 6 在平衡三进制中等于 1 × 9 (-1) × 3 0 × 1即“1T0”是一个两位以上的数。一个全加器只有本位和进位两个输出无法表示完整的 6。所以从工程上全加器只负责“本位 S 和向高一位的进位 C_out”更复杂的表示会由多个全加器级联来完成。这意味着在机械实现时我们不必纠结“某个组合的完整数学表示”只需要保证S 等于“所有输入之和模 3 之后的平衡三进制本位值”C_out 等于“需要向高一位传递的量”用一句话概括三进制全加器不是查一张 27 行的真值表而是执行“相加 → 拆成商和余数 → 把余数留在本位、把商传给进位”的过程。这个认知对后续机械搭建至关重要。3. 先用 Python 模拟三进制全加器逻辑在动手拼 Besiege 之前强烈建议先用代码把全加器逻辑跑通。逻辑不对机械结构再精巧也没用。下面给出一份 Python 模拟代码实现常规三进制和平衡三进制的全加器。文件可以命名为ternary_adder.py。def ternary_full_adder_regular(a, b, c_in): 常规三进制全加器 输入 a, b, c_in 取值 0, 1, 2 返回 (s, c_out) total a b c_in s total % 3 c_out total // 3 return s, c_out def to_balanced(value): 将十进制整数 value 转换为平衡三进制数字列表 列表低位在前元素取值为 -1, 0, 1 if value 0: return [0] digits [] n value while n ! 0: r n % 3 n n // 3 if r 2: digits.append(-1) n 1 elif r 1: digits.append(1) else: digits.append(0) return digits def ternary_full_adder_balanced(a, b, c_in): 平衡三进制全加器 输入 a, b, c_in 取值 -1, 0, 1 返回 (s, c_out) 其中本位 s 取 -1, 0, 1进位 c_out 取 -1, 0, 1 total a b c_in digits to_balanced(total) # 因为 abc_in 的范围是 -3 到 3转换后最多两位 # 第一位是本位第二位是进位如果有 s digits[0] if len(digits) 1 else 0 c_out digits[1] if len(digits) 2 else 0 return s, c_out if __name__ __main__: print( 常规三进制全加器 ) for a in range(3): for b in range(3): for c in range(3): s, c ternary_full_adder_regular(a, b, c) print(fA{a}, B{b}, C_in{c} S{s}, C_out{c}) print(\n 平衡三进制全加器 ) for a in [-1, 0, 1]: for b in [-1, 0, 1]: for c in [-1, 0, 1]: s, c_out ternary_full_adder_balanced(a, b, c) print(fA{a:2d}, B{b:2d}, C_in{c:2d} S{s:2d}, C_out{c_out:2d})运行方式python3 ternary_adder.py运行后你会看到所有 27 种输入组合的输出。拿几个关键用例人工核对A1, B1, C_in0 S-1, C_out1 A2, B2, C_in0 S1, C_out1这就是机械实现的目标表。代码跑通后我们在 Besiege 里要做的事情就变得非常明确机械结构只是一个物理计算器输入 A、B、C_in输出 S、C_out。如果你使用的是 0/1/2 常规三进制逻辑会更简单先算 total ABC_in再分离出商和余数。机械上可以用“位置叠加 挡块分档”来完成。如果是平衡三进制就需要多考虑“欠位”问题——表达式里可能出现负的剩余量处理时对机构要求更高。4. Besiege 里为什么能搭全加器零件与信号编码4.1 可用的核心零件Besiege 的零件体系一直在扩充做机械逻辑时最常用的是这几类零件作用在逻辑电路中的角色旋转铰链 (Rotation)提供旋转自由度可受控转动信号源、角度编码、时钟活塞 (Piston)直线伸缩产生推力信号输入、状态切换弹射器/弹簧 (Spring)存储弹性势能提供回弹力复位机构、能量输出齿轮 (Gear)传递旋转运动角度迭加、减速/加速传感器/触发器 (Sensor)检测物体是否进入区域状态检测、触发判断碰撞块 (Collision Block)提供物理碰撞挡块、限位器绳索 (Rope)柔性连接远程拉伸、信号远程传递木块/铁块 (Block)搭建主体结构结构基础铰链 (Hinge)单一方向旋转连接模拟开关、杠杆在实际搭建中很多“逻辑门”不是用电信号实现的而是用“推杆 挡块 传感器”的组合。例如一个二值信号可以用活塞是否推出到位来表示检测这个信号可以用传感器去感应活塞头部是否到达某个区域。4.2 三态信号怎么编码这是三进制全加器和二进制全加器最大的差异点。二进制里一根杆只有两个稳定位置代表 0 和 1三进制里一根杆需要有三个稳定位置代表 -1、0、1或 0、1、2。三种常见编码方案编码方案表示方法优点缺点单通道角度编码铰链停在 -90°/0°/90°零件少直观角度精度受物理影响大需要限位单通道位置编码滑块停在三个卡槽位置稳定容易加挡块需要额外增加定位机构双轨二值编码两路信号组合表示三态如 000, 011, 102每个通道只有两个状态可靠性高零件数量翻倍失去三进制“少零件”优势我的建议是在 Besiege 里优先使用“单通道位置编码”。原因很现实——物理引擎对角度误差很敏感一个铰链理论上停在 -90°、0°、90°实际运行时会因为重力、摩擦、碰撞而出现几度偏差传感器检测区域也需要留余量。而位置编码可以加物理挡块让滑块稳定地停在三个精确位置可靠性高得多。如果你坚持用平衡三进制的对称思维方式那么“左中右三档”和 -1/0/1 的对应关系天然成立。4.3 机械逻辑的最小原则搭建时记住一条原则物理引擎不是数电仿真。它会累积误差会抖动会延迟。所以任何一个逻辑模块都要设计成“一旦状态确定就能稳定保持”不能依赖刚好停在某个位置。实现手段就是加限位器、挡块、回位弹簧。一个模块不够稳级联两个模块后误差会放大。二进制加法器已经很容易因为齿轮滑齿而出错三进制由于位置档位更多对结构刚性的要求更高。5. 三进制全加器的机械结构拆解下面进入核心部分把三进制全加器拆成三个功能区。5.1 输入编码区把操作转化为三态位置输入区解决的是“人怎么告诉机器 A、B、C_in 是什么值”的问题。最简单的做法是用三个旋转铰链作为手动输入旋钮每个旋钮转动一个角度通过一根连杆推动一个滑块让滑块停在三个位置之一。例如旋钮转到左挡位 → 滑块位置 -1旋钮转到中挡位 → 滑块位置 0旋钮转到右挡位 → 滑块位置 1一个滑块代表一路输入所以一共有三个滑块分别对应 A、B、C_in。这里有一个很常见的坑手动旋钮的“停止位置”不好精确控制。解决办法是在旋钮末端加“棘爪”结构——用一个小弹簧柱塞让它卡进预设的三个凹槽里。这样每次旋转都能明确落位不会停在半路。5.2 求和区用位移叠加实现加法加法的本质是“三个数加起来”。在机械上最直接的加法是位移叠加。假设三根输入杆分别连接到一根公共杆上输入滑块移动时都会推动公共杆向同一个方向移动一段距离。那么公共杆的总位移就等于三个输入位移之和的线性叠加。理想情况下X A B C_in公共杆的位移 X 的范围是 -3 到 3平衡三进制。这个 X 就是全加器的“中间结果”。这个方案的优点是逻辑极其直观加法就是物理上的位移相加。缺点也很明显三个输入同时推动公共杆会造成受力耦合需要足够的结构刚度。位移叠加时滑块自身的摩擦会消耗一部分力可能导致公共杆停在比理论值偏小的位置。X 范围大公共杆行程长占用空间多。另一种方案是“真值表查询式”求和把三根输入杆布置成三组不同位置的拨杆每一种输入组合对应唯一一组拨杆落位再通过拨杆触发对应的输出机构。这种方式相当于把加法表做成了一个机械 ROM稳定但零件爆炸。从工程难度和观赏性考虑位移叠加更符合 Besiege 的“机械感”但真值表查询式的稳定性更好。实际开发中我更推荐先用位移叠加跑通逻辑再根据出现的问题决定是否换用查询式。5.3 取模与进位分离全加器真正的灵魂全加器不是只做加法还要把加法结果拆成“本位和”和“进位”。以平衡三进制为例公共杆位移 X 可能取 -3、-2、-1、0、1、2、3。我们需要根据 X 的值产生两个输出X 值S本位C_out进位-30-1-21-1-1-100001102-11301这张表就是全加器进位分离机构的真值表。机械上是这样实现的公共杆行程经过一组“筛选挡块”。每个挡块对应一个 X 的特殊值比如 X2 时一个凸起会推一下进位杆让进位杆拨到 1X3 时另一个凸起让进位杆拨到 1同时本位杆归零。这个过程很像老式机械计算器里的“十位跳表”机构不同的是这里做的是三进制跳表。调试时最容易出问题的地方就是这些凸起的触发时机——早一点或晚一点都会把进位送到错误的位置从而让下一位加法算错。5.4 进位传递把 C_out 送到下一个全加器单个全加器的 C_out 只是一个输出信号。当我们需要把多位全加器串起来组成一个多位数加法器时C_out 必须能作为下一个全加器的 C_in 输入。在 Besiege 中这个传递可以用推杆或绳索实现。推杆传递刚性好但需要保证方向不变绳索传递灵活但存在弹性可能造成位置回弹。进位传递还有一层时序问题如果下一位的加法已经开始了进位才慢悠悠到位结果就是整体计算错误。解决方法是引入“计算时钟”——用一个公共的时序机构先让所有位的输入稳定再释放全加器执行求和最后才取样进位。这一步在多个全加器级联时几乎是必须的。6. 分步组装与验证方法Besiege 的机械项目最忌“一口气拼完再调试”。建议按下面的顺序分模块搭建和验证。6.1 第一步搭输入编码器先只做三路输入滑块不接任何加法逻辑。每路滑块手动推到三个挡位观察滑块位置是否稳定。通过标准三路滑块都能准确停在 -1、0、1 三个位置。切换任意输入滑块没有半途卡住。手动反复切换 20 次以上没有出现位置漂移。如果这里都不稳定后面全加器一定出错。优先调限位和回位弹簧。6.2 第二步搭公共杆位移叠加把三路滑块用连杆连接到公共杆先不接取模机构直接观察公共杆位移。通过标准输入组合 (A1, B1, C_in0) 时公共杆位移应该等于 2。输入组合 (A1, B1, C_in1) 时公共杆位移应该等于 3。无需精确到小数只要位移档位能明显区分 0、1、2、3 即可。6.3 第三步实现本位 S 输出在公共杆上安装“取余挡块”让公共杆位移 X 经过取余机构后本位杆停留在 S 对应的位置。测试用例ABC_in期望 S期望 C_out0000010010110-111110122011通过标准拉动 A、B、C_in 到上表组合本位杆 S 能停在正确档位。6.4 第四步实现进位输出 C_out加入进位检测机构让公共杆位移达到 2 或 3 时触发进位杆输出 C_out。通过标准只需验证 2 和 3 两个位移值能分别触发 C_out 为 1。注意 X-3、-2 等负值也要能触发负进位。6.5 第五步级联两个全加器做两位数加法把两个全加器串起来低位的 C_out 接高位的 C_in再输入高位数据验证整体结果。通过标准低位的 2 高位的 1加上进位能得到正确三进制结果。连续跑多组用例没有出现进位漏传或误传。如果使用平衡三进制建议用以下手算用例做验证低位 A B C_in 1 1 0 期望输出S -1C_out 1 高位 A B C_in 0 0 1进位 期望输出S 1C_out 0 总体结果 1 * 3 (-1) 2十进制这个用例验证了“低位产生进位后高位能正确吃进”的整条链路。7. 常见问题与排查思路机械逻辑的调试和软件调试最大的不同是Bug 不一定有日志你得靠眼睛看。下面是我整理的 Besiege 三进制全加器常见问题排查表。问题现象可能原因排查方式解决方案滑块停不到中间位置缺少限位挡块观察滑块是否被卡在摩擦点上加三点定位挡块确保三个位置都有硬限位公共杆位移不准结构受力变形暂停时按住公共杆看是否有明显柔性变形改用铁块缩短跨度增加斜撑进位信号触发过早/过晚触发凸起位置不对逐帧推进观察凸起与检测杆接触时刻微调凸起在公共杆上的位置或升高触发块进位杆不回落回位弹簧力量不足手动拨动进位杆看是否自动归位增加弹簧数量或换用更强回位装置级联后进位抖动低位的 C_out 还没稳定就被传给高位在进位传递路径上加缓冲机构或时钟门控用统一的“计算时钟”控制各模块动作顺序传感器误触发检测区域过大或重叠用高亮模式检查传感器覆盖范围缩小检测区域给不同信号使用不同高度平面启动瞬间机构乱跑零件初始位置互相碰撞把机器从起始状态开始逐帧观察重启测试前把所有输入拨回零位或加锁定机构零件数太多导致卡顿物理引擎同时处理大量碰撞关闭无用装饰分模块测试把已稳定的模块合并成 Block 组减少实时碰撞计算调试时的核心技巧是把每个“信号杆”都用不同颜色来标记。例如 A 用红色、B 用绿色、C_in 用蓝色、S 用黄色、C_out 用橙色。这样当计算错误时一眼就能看出是哪一路信号没到位。另外一定要在暂停模式下搭结构但在运行模式下调试逻辑。Besiege 的暂停模式会冻结物理模拟方便调整位置运行模式才能看到真实的重力和碰撞效果。如果某个模块在暂停时看着挺好一运行就错位八成是重力负载或零件间初始碰撞的问题。8. 最佳实践与进一步扩展8.1 工程建议从这次开发中总结几条适合 Besiege 机械计算机的工程经验先定编码再画机构。三态信号用哪种位置方案要在搭建前确定不然后期改编码等于整体重做。任何一个模块都要能单独测试。输入编码区、求和区、进位区必须分开不能一上来就全部连在一起。多用硬限位少依赖摩擦力。摩擦会随零件磨损和受力变化波动而硬限位能提供确定性的停止位置。预留调试观察窗。在关键机构旁边留出视野不要用装饰块把逻辑部分完全包裹住。把“计算时钟”当作一等公民。单个全加器可以不考虑时序三个以上级联时必须考虑。最简单的时钟可以用一个旋转铰链周期性地触发行程开关控制“输入→计算→输出→复位”四个阶段。善用“爆炸后修复”的存档习惯。Besiege 物理引擎有时会因为加载顺序产生随机抖动养成“复制一个稳定版本再继续改”的习惯。8.2 从全加器到三进制计算机全加器只是起点。后面的扩展方向也很清晰多位加法器把多个全加器按位串联低位进位接高位 C_in。这是最容易做的一步。三态锁存器用带卡口的滑块结构记忆一个三态值。这就是机械存储单元。译码显示把三态杆位置转换为数字显示可以用旋转刻度盘或不同高度标记。乘法器三进制乘法可以用移位加实现本质上就是一组加法器阵列加一个状态控制时序。实际硬件参考历史上苏联的 Сетунь 计算机验证了平衡三进制的可行性现代数字设计里也有研究者尝试用三态逻辑降低互连复杂度。Besiege 里的三进制全加器某种意义上就是这些思想的小比例物理复现。从学习角度这个项目最大的收获是让你真正理解“二进制”只是众多编码方式之一。当你不把 0 和 1 视为天经地义时你会开始思考信息表示的本质任意 K 个可区分状态都可以用来编码而计算就是一组定义在这些状态上的规则。9. 总结三进制全加器是一个“看着小、折腾大”的项目。它只有三个输入、两个输出但要把这五路三态信号在 Besiege 的物理引擎里做得稳定确实需要花不少时间。这篇文章梳理了我认为最重要的几个环节三进制全加器用算术规则而不是真值表来理解平衡三进制和常规三进制的差异以及机械实现时的“输入编码区 / 位移求和区 / 取模进位区”三段式结构。如果你也想复刻建议先从 4.2 节的编码方案选型开始然后按第 6 节的五个步骤逐模块搭建和验证不要越过任何一步。全加器之后的路还很长加法和寄存器是计算机的地基但要想变成真正的计算机还需要时钟、控制器和更复杂的指令系统。至少把三进制全加器做出来之后你在 Besiege 里已经比大多数二进制玩家多了一个问题要思考当进位不是“逢二进一”而是“逢三进一”整个世界会有什么不同。
返回列表