- 示例工程
【免费下载链接】basic-computer-games
An updated version of the classic "Basic Computer Games" book, with well-written examples in a variety of common MEMORY SAFE, SCRIPTING programming languages. See https://coding-horror.github.io/basic-computer-games/
本文以 00_Alternate_Languages/45_Hello/README.md 为核心文档,围绕经典《Basic Computer Games》合集中 Hello 游戏的非主流语言移植展开:先阐明 "Alternate Languages" 目录的定位与遴选标准,再逐一解析 ANSI C、C、Go、MiniScript、Swift 五份移植实现的流程结构与关键代码,最后给出各端口的运行方式和新增移植的贡献指引。读完本文,你将理解该项目"10 大语言 + 任意附加语言"的组织策略,并能对照原始 BASIC 程序读懂任意一种端口的移植逻辑。
一、文档背景:Alternate Languages 目录是什么
Hello 游戏所在的 00_Alternate_Languages 目录存放的是各游戏在非约定 10 大语言下的实现。按 00_Alternate_Languages/README.md 的说明,主仓库约定的 10 种语言需要同时满足三项标准:
- 流行(Popular):以 TIOBE 指数衡量;
- 内存安全(Memory safe);
- 通常被视为脚本语言(Generally considered a 'scripting' language)。
而 Alternate Languages 目录中的实现不受这三项标准约束——因此这里允许出现 C、Pascal 这类非脚本语言(本游戏的 hello.c 就是典型例子)。目录还给出了两条移植规范:
- 忠实还原原貌:尽量保持与原版一致的"控制台应用"观感(console applications);
- 保持可移植性:除非无法做到,否则尽量保持代码可移植,并在 README 和文件夹命名中明确说明任何平台限制。
需要特别强调的是,这些附加移植仅供教育目的(for educational purposes only),不计入项目最终的目标移植数量。这也是 00_Alternate_Languages/45_Hello/README.md 要求读者"参考父目录 README"的原因——单看子目录文档只有一段说明,其完整的组织规则都定义在父目录中。
二、游戏本体:Hello 的原始 BASIC 程序结构
Hello 是一个趣味交互程序(心理咨询师模拟),原始实现位于 00_Alternate_Languages/45_Hello/hello.bas。它虽然以"Hello"命名,但核心逻辑是一条完整的对话状态机,主要分为五个阶段:
| 阶段 | BASIC 行号 | 行为 |
|---|---|---|
| 标题输出 | 2–6 | 用TAB定位居中打印 "HELLO" 与 "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" |
| 询问姓名 | 10–20 | 自我介绍后INPUT "WHAT'S YOUR NAME";N$读取用户姓名 |
| 询问心情 | 30–85 | 问"是否玩得开心",非 YES/NO 会循环追问 |
| 四类咨询 | 125–250 | 按 SEX / HEALTH / MONEY / JOB 四类分发不同回复,并支持继续提问 |
| 收费结尾 | 300–390 | 索要 5 美元咨询费,校验是否付款后告别 |
程序的关键设计是三类输入校验循环:第 40–65 行的 YES/NO 校验、第 125–140 行的四分类校验(C$="SEX"等分支,否则输出IS GREEK TO ME并跳转到 250)、以及第 210–217 行的 TOO MUCH/TOO LITTLE 子问题校验。移植时这些循环是忠实度检验的试金石。
三、ANSI C 移植:经典结构化复刻
00_Alternate_Languages/45_Hello/ANSI_C/hello.c 是与 BASIC 结构一一对应的 C 实现,它用三个辅助函数清晰表达了移植思路:
tab(int):循环putchar(' ')复刻 BASIC 的TAB(33)/TAB(15)居中效果;get_input(char*):用fgets读取并用strcspn剔除行尾换行,对应 BASIC 的INPUT;strings_match:基于strncasecmp做大小写不敏感比较,把strings_match(reply, "YES")直接映射到 BASIC 的IF B$="YES"。
主函数以done、paid、maybe_more、sure四个状态变量驱动,while (!strings_match(reply, "YES") && !strings_match(reply, "NO"))正是 BASIC 第 40 行校验循环的翻译。值得注意的是,仓库根目录下的 hello.c 与之几乎一致,唯一实质差异是strings_match使用strncmp(大小写敏感)——同一游戏存在两份 C 实现,可对照观察移植者对输入容错的取舍。
四、Go 移植:类型化状态机的现代改写
00_Alternate_Languages/45_Hello/go/main.go 是五份移植中结构化程度最高的一份,它不再逐行镜像 BASIC,而是用现代语言特性重构:
- 用
type PROBLEM_TYPE int8与iota定义SEX/HEALTH/MONEY/JOB/UKNOWN枚举,替代 BASIC 中 130–136 行的四次IF C$="..."串行比较; promptForProblems内用switch strings.ToUpper(scanner.Text())做分类分发,default分支返回UKNOWN,对应 BASIC 第 138 行的 "IS GREEK TO ME";- 每个咨询分支(
solveSexProblem、solveHealthProblem、solveMoneyProblem、solveJobProblem)被拆成独立函数,askQuestionLoop承担外层"ANY MORE PROBLEMS"循环; - 收费阶段用
time.Sleep(4 * time.Second)模拟原版 BASIC 第 307 行的空转延时循环FOR I=1 TO 2000: NEXT I。
这份实现展示了从"行号 GOTO 结构"到"函数 + 枚举 + 循环"的迁移路径,是学习移植方法论的最佳范本。
五、MiniScript 移植:最贴近原版的脚本化直译
MiniScript/hello.ms 采用字符串拼接式直译,ns = input("What's your name? ")与 BASIC 的INPUT一一对应,print " "*33 + "Hello"用字符串乘法替代TAB。其输入处理值得注意:bs = input.lower直接在读取时统一转小写,随后与"yes"/"no"比较,等效于 ANSI C 版的大小写不敏感策略。
该目录还附有 MiniScript/README.md,明确给出了两种运行方式:
- 命令行版 MiniScript:从 miniscript.org/cmdline 下载安装后执行
miniscript hello.ms; - Mini Micro 环境:下载 Mini Micro,挂载该目录为磁盘文件夹,在命令行输入
load "hello"后run。
这是五份移植中唯一附带运行文档的端口,体现了"保持可移植性并明确说明限制"的目录规范。
六、Swift 移植:默认值兜底与函数式输出
Swift/hello.swift 的移植亮点在于健壮性处理:var name = "STRANGER"为姓名提供默认值,读取输入后判断if (input != nil && input != "")才覆盖默认名,对应 BASIC 中未显式处理的空输入边界情况。tab用字符串拼接spaces += " "配合print(spaces, terminator:"")实现不换行的空格输出;get_Input()对readLine()的 nil 结果返回空串并统一uppercased(),与 ANSI C 的大小写不敏感策略一致。
七、五份移植的实现对照
| 端口 | 文件 | 输入比较策略 | 结构风格 | 状态控制 |
|---|---|---|---|---|
| ANSI C | ANSI_C/hello.c | strncasecmp大小写不敏感 | 函数辅助 + 循环 | 4 个布尔标志 |
| C(根目录) | hello.c | strncmp大小写敏感 | 函数辅助 + 循环 | 4 个布尔标志 |
| Go | go/main.go | strings.ToUpper后比较 | 枚举 + 独立求解函数 | 函数返回 / 循环 |
| MiniScript | MiniScript/hello.ms | input.lower统一小写 | 直译脚本 | while true+break |
| Swift | Swift/hello.swift | uppercased()统一大写 | 函数辅助 + 循环 | 4 个布尔标志 |
从源码结构看,一个共同的移植模式是:把 BASIC 的 GOTO 跳转(如IF B$="YES" THEN 70)转换为循环内的break/状态位,把行号标签(如 145/160/180/200)转换为独立函数或分支。这正是把 1970 年代 BASIC 结构迁移到现代语言的通用方法论。
八、如何贡献新的移植
依据两份 README 的约定,向 Alternate Languages 目录新增端口需要遵守以下规则:
- 任何语言均可:不限于约定的 10 种语言,C、Pascal、MiniScript 等"非内存安全或非脚本"语言同样欢迎;
- 忠实原貌:保持控制台应用观感与原文案(原文案本身是复古风格的一部分);
- 声明平台限制:代码若依赖特定平台,必须在 README 与文件夹命名中明确说明;
- 教育用途定位:附加端口仅供学习,不计入项目移植数量目标,也不参与项目末尾的捐赠统计。
建议新移植以 00_Alternate_Languages/45_Hello/hello.bas 为唯一行为基准,先保证姓名输入、YES/NO 校验、四分类咨询、收费结尾五个阶段完整,再参考 go/main.go 的函数化拆分思路组织代码结构。
九、总结
Hello 游戏的五份附加语言移植,是理解《Basic Computer Games》项目"多语言移植方法论"的绝佳入口:它体量小但状态机完整,从直译(MiniScript)到重构(Go)展示了不同抽象层次的移植风格,而 00_Alternate_Languages/README.md 则从项目层面定义了"10 大语言三标准 + 附加端口教育用途"的组织策略。无论你想学习如何忠实复刻复古终端交互,还是想研究 GOTO 结构如何映射到现代控制流,这份 8KB 的 BASIC 程序及其五个端口都值得精读。
- 示例工程
【免费下载链接】basic-computer-games
An updated version of the classic "Basic Computer Games" book, with well-written examples in a variety of common MEMORY SAFE, SCRIPTING programming languages. See https://coding-horror.github.io/basic-computer-games/
相关推荐
Basic Computer Games 之 Animal:备用语言移植(Go / MiniScript)实现与原理解析
Basic Computer Games 之 Animal:备用语言移植(Go / MiniScript)实现与原理解析 导读 00_Alternate_Lan
示例工程EdgeLM/fairseq 示例实战:基于往返翻译与混合专家模型的文本改写(Paraphrasing)
EdgeLM/fairseq 示例实战:基于往返翻译与混合专家模型的文本改写(Paraphrasing) 本文围绕 fairseq 生态中的 paraphras
示例工程Basic Computer Games 备选语言移植指南:Batnum 的 Go 与 MiniScript 实现深入解析
Basic Computer Games 备选语言移植指南:Batnum 的 Go 与 MiniScript 实现深入解析 BATNUM(Battle of N
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考