NCHUD-数字电路模拟程序

  • 前言
    这次数字电路模拟程序的迭代开发(基础版→V2 版),是一场兼顾编程实战与逻辑思维的锤炼。从五种基础逻辑门到新增三态门、译码器等复杂元件,从单一输入输出到控制引脚的多维管理,过程虽充满挑战,但也让我在技术能力与系统设计思维上实现了快速成长

    初期阶段:基础逻辑门的抽象与落地
    版本 1 的核心是实现与、或、非等五种基础逻辑门。看似简单的功能,关键在于将物理元件抽象为可编程模型:如何定义元件属性、解析输入格式、实现信号传递与计算。最初因忽略输入引脚数量校验,频繁出现数组越界错误;信号传递的先后依赖也让单次遍历无法完成计算。
    为此,我采用面向对象思想设计Component类,封装元件类型、编号、引脚等核心信息;通过循环传递信号(直到无新值更新)解决依赖问题;用正则表达式精准匹配引脚命名规则,简化输入解析。这个过程让我深刻体会到 “抽象” 与 “严谨” 的重要性 —— 基础逻辑的扎实实现,是后续复杂功能扩展的关键。

    中期阶段:复杂元件的攻坚与逻辑突破
    版本 2 新增的三态门、译码器等元件,是本次作业的核心挑战。这些元件不仅增加了控制引脚,还存在引脚分类复杂、输出规则差异化大的问题:
    一是引脚分类难题。需严格遵循 “控制 - 输入 - 输出” 的编号规则,不同元件的引脚范围截然不同(如译码器控制引脚 0-2、输入引脚 3-5)。初期因理解偏差导致分类错误,后续通过梳理每种元件的引脚分配规则,结合正则分组匹配,才实现精准分类。
    二是逻辑实现难点。复杂元件的输出依赖控制与输入引脚的协同(如译码器需先验证控制条件,再转换输入编码)。我曾因混淆输入编码位权、忽略控制引脚排序要求,多次出现计算错误,最终通过对照真值表逐点验证,才攻克这些逻辑难关。

    后期阶段:模块化优化与输出适配
    随着元件增多、输出规则差异化(普通门输出 0/1、译码器输出引脚编号、数据分配器输出序列),代码维护性面临挑战。我将计算逻辑拆分为独立方法,按元件类型分类处理输出,强化异常处理(忽略输入不全、控制无效的元件),通过模块化设计提升代码可读性与稳定性。这让我明白,好的代码结构不仅能降低调试难度,更能支撑功能的灵活扩展。

    未来展望:持续迭代,探索更深层次的电路模拟
    这次作业只是数字电路模拟的起点,题目规划的版本 3(时序电路,如 D 触发器、JK 触发器)和版本 4(子电路、异常输入检测)还等待着我去探索。未来,我希望能在以下方面继续提升:
    学习并应用设计模式(如工厂模式创建不同类型的元件、观察者模式处理信号更新),进一步优化代码结构;
    针对时序电路的 “反馈” 特性,研究状态存储与时钟同步机制,解决基础版中无法处理的循环依赖问题;
    完善异常输入检测功能,比如校验输入引脚是否连接多个输出引脚、元件编号是否重复等,让程序更具实用性;
    优化性能,针对复杂电路的信号传递效率进行优化,避免不必要的循环迭代。

  • 第一次作业

  • 需求分析
    一、核心目标
    模拟与门、或门、非门、异或门、同或门五种基础逻辑门的电路运行逻辑,根据输入的引脚信号和连接关系,精准计算并输出有效元件的输出电平,为后续复杂电路模拟奠定基础。
    二、功能需求
    (一)输入解析功能
    支持顶层输入解析:识别INPUT:开头的输入行,提取输入引脚名称及对应电平(0/1),格式为 “输入引脚 - 信号值”,多个输入以空格分隔。
    支持连接关系解析:识别以[]包裹的连接行,提取输出引脚与关联输入引脚的映射关系,一个输出引脚可连接多个输入引脚。
    输入结束识别:以 “end” 作为输入终止标志,忽略后续内容。
    (二)元件建模功能
    元件类型与命名:
    与门(A)、或门(O):命名格式为 “标识符 (输入引脚数)+ 编号”(如 A (8) 1、O (4) 2),支持两个及以上输入引脚。
    非门(N)、异或门(X)、同或门(Y):命名格式为 “标识符 + 编号”(如 N1、X8、Y4),非门固定 1 个输入引脚,异或 / 同或门固定 2 个输入引脚。
    约束:同种元件编号不可重复,不同元件编号可重复。
    引脚规则:
    引脚命名格式为 “元件名 - 引脚号”(如 A (8) 1-2、X5-2)。
    输入引脚连续编号(如 n 个输入引脚对应编号 1~n),输出引脚固定为 0 号。
    (三)信号计算功能
    逻辑门计算规则:
    与门:所有输入为 1 时输出 1,否则输出 0。
    或门:所有输入为 0 时输出 0,否则输出 1。
    非门:输入与输出电平相反(0→1,1→0)。
    异或门:输入电平不同时输出 1,否则输出 0。
    同或门:输入电平相同时输出 1,否则输出 0。
    信号传递:输出引脚的信号需传递至所有连接的输入引脚,支持多元件级联(前级输出作为后级输入)。
    有效输入判断:仅当元件所有输入引脚均获得有效信号时,才计算输出;输入不全则视为无效,忽略该元件。
    (四)输出展示功能
    排序规则:按 “与门→或门→非门→异或门→同或门” 的顺序输出,同类元件按编号从小到大排序。
    输出格式:有效元件输出格式为 “元件输出引脚:电平值”(如 A (2) 1-0:1),忽略无效元件。
    三、非功能需求
    正确性:计算结果需严格遵循逻辑门物理特性,输入输出映射符合真值表。
    健壮性:面对输入不全、元件引脚未连接等情况,程序不崩溃,仅忽略无效元件。
    兼容性:支持题目规定的所有输入格式,准确解析不同命名规则的元件与引脚。
    四、约束条件
    连接约束:一个输入引脚仅能连接一个输出引脚,输出引脚不可短接。
    引脚约束:元件输入引脚编号连续且不重复,输出引脚固定为 0 号。
    输入约束:测试输入保证引脚编号合法、元件命名规范,无需处理异常输入格式。

  • 代码分析
    看一下我的代码在PLantUML编辑器的UML图

plantuml (1)

1.输入读取与分类:在 main 方法中,逐行读取输入内容,将 “INPUT:” 开头的行归类为输入行、“[]” 包裹的行归类为连接行,其余行忽略,直到输入 “end” 终止读取流程。
2.初始化核心数据结构:创建 pinValues(存储引脚名与对应电平值 0/1)、sourceToDests(存储输出引脚到输入引脚的连接映射)、components(存储元件对象)三个核心集合,完成初始状态初始化。
3.解析顶层输入引脚:调用输入解析逻辑,解析 INPUT 行内容,按 “引脚名 - 电平值” 格式提取顶层输入引脚(如 A、B)及其对应的 0/1 电平值,存入 pinValues。
4.解析引脚连接关系:解析所有连接行,去除首尾 [] 后,提取输出引脚和关联的输入引脚列表(如 A 对应 A (2) 1-1、X1-1),构建 sourceToDests 的映射关系。
5.提取元件信息:收集所有涉及的引脚,通过正则表达式匹配 A/O/N/X/Y 类型元件引脚规则,提取元件类型、编号、输入引脚数等信息,创建 Component 对象并填充输入 / 输出引脚信息,存入 components。
6.循环传递信号:调用信号传递逻辑,遍历 sourceToDests 集合,将输出引脚的电平值传递至所有关联的输入引脚,若有新值更新则重复此过程,直到无新信号可传递。
7.计算元件输出电平:遍历 components 中的所有元件,按元件类型(与 / 或 / 非 / 异或 / 同或)调用对应计算逻辑,仅当元件所有输入引脚均有有效电平值时,计算输出引脚电平并标记元件为有效;输入不全则标记为无效。
8.结果排序与输出:将有效元件按 “与门→或门→非门→异或门→同或门” 顺序分组,同类元件按编号升序排序,遍历输出有效元件的 “输出引脚:电平值” 信息。
9.程序终止:完成所有有效元件输出后,程序结束运行。
我们可以看看第一次代码的情况根据SourceMonitor:

屏幕截图 2025-12-13 131511

  • 第二次作业
  • 需求与分析
    在基础版五种逻辑门(与 / 或 / 非 / 异或 / 同或)的基础上,扩展支持三态门、译码器、数据选择器、数据分配器四种复杂组合元件,新增控制引脚的识别与处理,适配差异化输出规则,实现更贴近实际场景的数字电路模拟,同时保证程序的扩展性与健壮性。
  • 代码分析
    看一下我的代码在PLantUML编辑器的UML图

plantuml2

  • 代码运行步骤
    1.输入读取与分类:在 main 方法中,逐行读取输入内容,将 “INPUT:” 开头的行归类为输入行、“[]” 包裹的行归类为连接行,其余行忽略,直到输入 “end” 终止读取流程。
    2.初始化核心数据结构:创建 pinValues(存储引脚名与电平值 0/1)、sourceToDests(输出引脚→输入 / 控制引脚映射)、components(元件名→元件对象)三个核心集合,完成初始状态初始化。
    3.解析顶层输入引脚:调用输入解析逻辑,解析 INPUT 行内容,按 “引脚名 - 电平值” 格式提取顶层输入引脚及其电平值,存入 pinValues。
    4.解析引脚连接关系:解析所有连接行,去除首尾 [] 后,提取输出引脚和关联的输入 / 控制引脚列表,构建 sourceToDests 的映射关系。
    5.提取元件信息:收集所有涉及的引脚,通过正则匹配 A/O/N/X/Y/S/M/Z/F 九种元件的命名规则,提取元件类型、编号、核心参数(输入数 / 控制数),创建 Component 对象并按 “控制 - 输入 - 输出” 规则分类填充引脚,存入 components。
    6.循环传递信号:调用信号传递逻辑,遍历 sourceToDests 集合,将输出引脚的电平值传递至所有关联的控制 / 输入引脚,若有新值更新则重复此过程,直到无新信号可传递。
    7.计算元件输出结果:遍历 components 中的所有元件,按类型调用对应计算逻辑:
    基础门(A/O/N/X/Y):验证输入引脚数量与有效性,计算输出电平;
    三态门(S):验证控制 / 输入引脚有效性,判断控制电平后计算有效输出或标记无效;
    译码器(M):验证控制 / 输入引脚有效性与控制条件,计算有效输出引脚编号或标记无效;
    数据选择器(Z):验证控制 / 输入引脚有效性,计算输出电平或标记无效;
    数据分配器(F):验证控制 / 输入引脚有效性,生成输出序列或标记无效。
    8.结果分组排序:将有效元件按 “与门→或门→非门→异或门→同或门→三态门→译码器→数据选择器→数据分配器” 顺序分组,同类元件按编号升序排序。
    9.差异化输出结果:调用对应输出方法,按元件类型输出结果:
    基础门 / 三态门 / 数据选择器:输出 “输出引脚:电平值”;
    译码器:输出 “元件名:有效输出引脚编号”;
    数据分配器:输出 “元件名:输出序列(无效引脚用 - 表示)”。
    10.程序终止:完成所有有效元件输出后,程序结束运行。
  • 第二次代码的升级地方
    1.从 “单一维度” 到 “多维控制”:基础版仅处理 “输入→输出” 的单一逻辑,进阶版新增 “控制引脚” 维度,需兼顾控制条件与输入值的协同计算,更贴近实际数字电路的运行逻辑;
    2.从 “统一输出” 到 “差异化输出”:基础版输出格式、结果类型完全统一,进阶版需适配译码器(有效引脚编号)、数据分配器(输出序列)等特殊输出形式;
    3.从 “简单封装” 到 “模块化设计”:基础版代码聚焦功能实现,进阶版通过引脚分类、计算逻辑拆分、输出方法解耦,提升了代码的扩展性与可维护性,为后续时序电路、子电路等功能扩展奠定基础;
    4.从 “基础校验” 到 “全维度校验”:基础版仅校验输入引脚数量与有效性,进阶版需同时校验控制引脚数量、控制条件、输入引脚有效性,逻辑严谨性要求更高。
    我们可以看看第一次代码的情况根据SourceMonitor:

屏幕截图 2025-12-13 131312

  • 总结
    两次数字电路模拟程序的开发,让我系统掌握了模块化设计、面向对象精准建模、策略模式简化应用、防御性编程等核心设计方式,更深刻理解了 “高内聚、低耦合、可扩展、可维护” 的工程化设计原则。这些设计方式不仅解决了本次作业的复杂需求,更形成了可复用的开发思维 —— 未来面对时序电路、子电路等更复杂的需求时,我将先通过抽象共性、拆分模块、预留扩展点搭建架构,再逐步实现细节,用工程化的设计思路替代 “粗放式编码”,开发出更优质、更具扩展性的程序。
posted @ 2025-12-13 14:18  Shirley_0914  阅读(4)  评论(0)    收藏  举报