基于Black Box Component Builder求解Advent of Code的方法与思路咨询
使用Black Box Component Builder解决Advent of Code 2023第1天问题
解题思路与BBCB环境适配
BBCB基于Component Pascal,核心特点是强类型、模块化结构,文本处理依赖内置标准模块,思维方式和你熟悉的Lisp、Forth、C有明显差异:
- 无动态类型或栈式操作,需用静态变量、循环、条件判断处理逻辑
- 所有代码需封装在
MODULE中,依赖的系统模块必须显式导入 - 字符串、文件操作依赖
Strings、Files等内置模块,过程式风格更突出
第一部分:提取数字字符求和
核心逻辑
读取每行文本,分别找到第一个和最后一个数字字符,组合成两位数后累加总和。
BBCB代码实现
MODULE AoC2023Day1Part1; IMPORT Files, Strings, Chars, Out; PROCEDURE ComputeSum*(inputPath: ARRAY OF CHAR): INTEGER; VAR f: Files.File; line: Strings.String; first, last: CHAR; sum, num: INTEGER; i: INTEGER; BEGIN sum := 0; IF Files.Open(f, inputPath, Files.Read) THEN WHILE Files.ReadLn(f, line) DO first := #0; last := #0; (* 查找第一个数字字符 *) FOR i := 0 TO Strings.Length(line)-1 DO IF Chars.IsDigit(Strings.Get(line, i)) THEN first := Strings.Get(line, i); EXIT; END; END; (* 查找最后一个数字字符 *) FOR i := Strings.Length(line)-1 DOWNTO 0 DO IF Chars.IsDigit(Strings.Get(line, i)) THEN last := Strings.Get(line, i); EXIT; END; END; (* 计算当前行数值并累加 *) IF first # #0 THEN num := (ORD(first) - ORD('0')) * 10 + (ORD(last) - ORD('0')); sum := sum + num; END; END; Files.Close(f); END; RETURN sum; END ComputeSum; PROCEDURE Run*; VAR total: INTEGER; BEGIN total := ComputeSum("input.txt"); Out.String("第一部分总和:"); Out.Int(total, 0); Out.Ln; END Run; END AoC2023Day1Part1.
代码说明
- 导入
Files处理文件读写,Strings操作字符串,Chars判断字符类型,Out实现控制台输出 - 两次遍历每行文本分别定位首尾数字,逻辑直观符合BBCB的过程式风格
- 通过
ORD函数将字符转换为对应数值,这是Component Pascal处理字符转数字的标准方式
第二部分:识别数字单词
核心调整
新增数字单词(one-nine)的识别逻辑,遍历文本时需同时检查单个字符和子串是否匹配数字单词。
BBCB代码实现
MODULE AoC2023Day1Part2; IMPORT Files, Strings, Chars, Out; CONST numWords: ARRAY 9 OF ARRAY OF CHAR = ("one", "two", "three", "four", "five", "six", "seven", "eight", "nine"); numVals: ARRAY 9 OF INTEGER = (1, 2, 3, 4, 5, 6, 7, 8, 9); PROCEDURE GetNumAtPos(line: Strings.String; pos: INTEGER): INTEGER; VAR i: INTEGER; sub: Strings.String; BEGIN (* 检查单个数字字符 *) IF Chars.IsDigit(Strings.Get(line, pos)) THEN RETURN ORD(Strings.Get(line, pos)) - ORD('0'); END; (* 检查是否匹配数字单词 *) FOR i := 0 TO 8 DO IF pos + Strings.Length(numWords[i]) <= Strings.Length(line) THEN Strings.Sub(line, pos, Strings.Length(numWords[i]), sub); IF Strings.Equal(sub, numWords[i]) THEN RETURN numVals[i]; END; END; END; RETURN -1; (* 未找到有效数字 *) END GetNumAtPos; PROCEDURE ComputeSum*(inputPath: ARRAY OF CHAR): INTEGER; VAR f: Files.File; line: Strings.String; first, last, current: INTEGER; sum, i: INTEGER; BEGIN sum := 0; IF Files.Open(f, inputPath, Files.Read) THEN WHILE Files.ReadLn(f, line) DO first := -1; last := -1; (* 单次遍历定位首尾有效数字 *) FOR i := 0 TO Strings.Length(line)-1 DO current := GetNumAtPos(line, i); IF current <> -1 THEN IF first = -1 THEN first := current; END; last := current; (* 持续更新最后一个数字 *) END; END; IF first <> -1 THEN sum := sum + first * 10 + last; END; END; Files.Close(f); END; RETURN sum; END ComputeSum; PROCEDURE Run*; VAR total: INTEGER; BEGIN total := ComputeSum("input.txt"); Out.String("第二部分总和:"); Out.Int(total, 0); Out.Ln; END Run; END AoC2023Day1Part2.
代码说明
- 用常量数组存储数字单词与对应数值,符合BBCB静态类型的设计思路
GetNumAtPos封装位置数字识别逻辑,职责单一,便于维护- 单次遍历即可完成首尾数字的定位,优化了第一部分的重复遍历逻辑
BBCB解题思维总结
- 模块化封装:所有功能拆分为独立过程,放在
MODULE中,便于复用和调试 - 依赖标准模块:优先使用内置的
Strings、Files等模块,避免自定义基础操作 - 静态类型约束:提前明确变量类型,减少运行时错误,这和C的思路类似,但模块化边界更清晰
- 过程式逻辑:用循环、条件判断处理字符流,无函数式高阶操作,逻辑直观易读
内容的提问来源于stack exchange,提问作者Ala'a Mohammad
相关产品推荐
相关产品推荐

