Fur Trader 的 ANSI C 移植指南从 1978 年 BASIC 经典到 C99 的忠实转换【免费下载链接】basic-computer-gamesAn 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/项目地址: https://gitcode.com/gh_mirrors/ba/basic-computer-games导读Fur Trader毛皮商人是《Basic Computer Games》1978中的经典文字冒险游戏玩家扮演 1776 年法国毛皮贸易远征队的首领在三个要塞间选择贸易路线、买卖四种毛皮。本文以本仓库中 C 语言移植版的核心文档与完整源码为骨架讲解该游戏从 Vintage BASIC 到 ANSI CC99的移植思路、源码结构、编译运行方法、定价与随机事件机制并重点剖析翻译者在文档中披露的狐狸皮价格未初始化历史 Bug 及其处理策略。游戏背景1776 年的毛皮贸易远征在开始阅读移植代码之前先理解游戏本身的设定。根据 38_Fur_Trader/README.md 的介绍你是一支 1776 年法国毛皮贸易远征队的首领即将离开安大略湖区去出售毛皮并为来年采购补给。你可以在三个要塞中任选其一进行交易补给价格与毛皮售价取决于你选择的要塞同时你需要说明手中持有哪些种类的毛皮。游戏的原始作者是加拿大卡尔加里大学的 Dan Bachor原版以 Microsoft 8K BASIC 编写收录于 David Ahl 的《Basic Computer Games》一书。游戏会一直持续直到你主动选择不再交易。本仓库中该游戏拥有多种语言移植C#、Java、JavaScript、Python 等而C 语言版本被归类在00_Alternate_Languages备用语言目录下——依据 README.md 的说明该目录收录不属于项目约定 10 种官方语言C#、Java、JavaScript、Kotlin、Lua、Perl、Python、Ruby、Rust、VB.NET的移植仅用于教学目的。移植文档核心内容从 Vintage Basic 到 ANSI C本次关联文档 00_Alternate_Languages/38_Fur_Trader/c/README.md 虽然篇幅简短却完整交代了移植的出处、目标与关键技术决策原始出处源码下载自 Vintage Basic 网站游戏仓库中所有 BASIC 源码均来自 vintage-basic.net/games.html。目标语言转换为 ANSI-C源码注释中进一步明确为 C99 标准见 furtrader.c。翻译者署名krtkrt.com.au2020-10-10。翻译者注释的四大设计原则原文档中翻译者krt明确记录了自己的移植策略这直接决定了整个源码的风格尽可能保留原始布局与流程不重构游戏逻辑让 C 代码的执行顺序与原始 BASIC 的GOTO跳转结构一一对应使用枚举类型为 Fort要塞编号和 Fur毛皮类型引入枚举/符号常量这是对原代码的明显改进使代码更易读尽量减少指针的使用坚持老式 C 格式化风格——原因是你永远不知道编译器有多老强调兼容性与可移植性保留并修复 Fox Fur 价格 Bug这是文档中最有价值的技术细节下文专节剖析。源码结构总览常量、辅助函数与状态机C 版本实现于 furtrader.c共 474 行整体结构清晰按职责分为三大部分。常量与枚举虽然文档提到使用枚举类型实际源码采用了宏常量 常量数组的组合方式见 furtrader.c以兼容最老式的 C 编译器#define FUR_TYPE_COUNT 4 #define FUR_MINK 0 #define FUR_BEAVER 1 #define FUR_ERMINE 2 #define FUR_FOX 3 #define MAX_FURS 190 const char *FUR_NAMES[FUR_TYPE_COUNT] { MINK, BEAVER, ERMINE, FOX }; #define FORT_TYPE_COUNT 3 #define FORT_MONTREAL 1 #define FORT_QUEBEC 2 #define FORT_NEWYORK 3 const char *FORT_NAMES[FORT_TYPE_COUNT] { HOCHELAGA (MONTREAL), STADACONA (QUEBEC), NEW YORK };关键约束一目了然玩家最多持有190 张毛皮只有 4 种毛皮类型、3 个要塞可选。辅助函数源码按单一职责拆分了 12 个辅助函数替代了原 BASIC 中大量GOSUB子程序函数职责printAtColumn(int, const char*)在指定列打印文本对应 BASIC 的TAB()print(const char*)带换行输出一行文本getNumericInput()循环读取用户输入并转换为整数非法输入重新提示strtol 指针校验getYesOrNo()循环读取 YES/NO 输入只校验首字母Y/N兼容大小写getFortChoice()展示三要塞选择提示循环直到输入 1/2/3showFortComment(int)打印所选路线的难度说明getFursPurchase(int*)依次询问四种毛皮的持有数量zeroInventory(int*)/sumInventory(int*)清零 / 求和毛皮库存randomAB(float, float)/randFloat()生成[a,b]区间与[0,1]区间的随机浮点数其中getNumericInput通过strtol的endptr判断转换是否成功见 furtrader.cgetYesOrNo则通过首字母判断允许y、Y、n、N等任意变体——这正是项目指南要求的支持大小写输入。状态机驱动的主循环与原始 BASIC 依靠GOTO/GOSUB线形流转不同C 版本用一个显式的状态机组织游戏流程见 furtrader.c#define STATE_STARTING 1 #define STATE_CHOOSING_FORT 2 #define STATE_TRAVELLING 3 #define STATE_TRADING 4main()中while(1)无限循环根据game_state分发四个状态依次构成完整游戏周期STATE_STARTING打印引言重置资金为 600 美元、清空库存询问是否交易STATE_TRADING显示当前资金与 190 张毛皮让玩家输入四种毛皮数量若总数超过 190输出 YOU MAY NOT HAVE THAT MANY FURS. DO NOT TRY TO CHEAT. I CAN ADD. 并回到 STARTING 重来STATE_CHOOSING_FORT选择要塞并显示路线评价询问是否更换要塞STATE_TRAVELLING按所选要塞生成价格、扣减补给与旅行费用、触发随机事件、计算销售收入然后询问是否来年继续交易。编译与运行源码头部注释直接给出了编译命令见 furtrader.cgcc -g -Wall -Werror furtrader.c -o furtrader-g保留调试符号便于在 gdb 中跟踪游戏状态-Wall -Werror将警告升级为错误强制代码零警告——这既是移植者自律的体现也保证了代码在老旧编译器上也能顺利通过。编译后直接运行./furtrader即可开始游戏全程为命令行交互输入均为键盘应答。核心机制一要塞选择、价格生成与成本三条路线的风险-收益设计选择要塞后showFortComment会打印该路线的难度说明见 furtrader.cFort 1 Hochelaga蒙特利尔最容易的路线但离海港远毛皮售价低、补给价高Fort 2 Stadacona魁北克中等难度路线毛皮价值与补给价格均居中但需要搬运货物并穿越 Lachine 急流Fort 3 New York纽约最难路线穿越易洛魁人领地毛皮售价最高、补给最低。价格生成公式每种毛皮的价格由随机区间 取整公式生成与原始 BASIC 中的INT((.2*RND(1).7)*10^2.5)/10^2完全对应即( (幅度 * rand 基数) * 100 0.5 ) / 100得到两位小数的价格。各要塞、各毛皮的价格区间整理如下数据取自 furtrader.c 的实际公式毛皮HochelagaStadaconaNew YorkMINK 貂0.70 – 0.900.85 – 1.151.05 – 1.20BEAVER 河狸0.75 – 0.950.90 – 1.101.00 – 1.25ERMINE 白鼬0.65 – 0.850.80 – 0.950.95 – 1.10FOX 狐狸0.80 – 1.001.10 – 1.35见下节 Bug 分析可见越危险收益越高的平衡纽约路线整体价格水平最高而蒙特利尔最低。补给与旅行成本前往每个要塞都会一次性扣减补给费与旅行费源码中与 BASIC 一致注意 C 版纽约补给价为 $85.00要塞补给费旅行费合计扣减Hochelaga$150.00$10.00$160Stadacona$125.00$15.00$140New York$85.00$25.00$105核心机制二随机事件表魁北克路线Stadaconaevent_picker (10 * randFloat()) 1按 1~10 整数分布触发事件见 furtrader.c取值概率事件效果1–220%河狸太重搬运中丢失并被偷走player_furs[BEAVER] 03–640%安全到达 Stadacona无损失7–820%独木舟在 Lachine 急流倾覆全部毛皮清零9–1020%狐狸皮未妥善腌制无人购买player_furs[FOX] 0纽约路线New York取值概率事件效果1–220%遭易洛魁人袭击全员遇难exit(0)游戏直接结束3–640%幸运安全抵达无损失7–820%侥幸逃脱袭击但丢下全部毛皮全部毛皮清零9–1020%貂皮与河狸皮途中受损相关毛皮售价减半其中受损减半分支值得注意屏幕提示文本写的是 YOUR MINK AND BEAVER WERE DAMAGED但 C 源码实际执行的是mink_price / 2; fox_price / 2;见 furtrader.c而原始 BASICfurtrader.bas减半的是B1河狸与M1貂。也就是说提示文本与实际减半的毛皮种类在 C 版中并不完全一致——这是阅读源码时可留意的一处细节。销售结算到达要塞后统一结算见 furtrader.cbeaver_value beaver_price * player_furs[ FUR_BEAVER ]; fox_value fox_price * player_furs[ FUR_FOX ]; ermine_value ermine_price * player_furs[ FUR_ERMINE ]; mink_value mink_price * player_furs[ FUR_MINK ]; player_funds beaver_value fox_value ermine_value mink_value;随后打印四种毛皮的销售收入与累计资金询问 DO YOU WANT TO TRADE FURS NEXT YEAR?回答 NO 即结束游戏。核心机制三Fox Fur 价格 Bug 深度剖析这是翻译者文档中着墨最多、也是移植最有价值的部分。翻译者写道有意思的是代码似乎在 Fox Furs狐狸皮的价格上存在一个 Bug。该商品的价格存储在变量D1中但某些代码路径不会设置这个价格因此存在使用未初始化值或上一轮循环残留值的可能。我认为这不是原作者的本意。所以我保留了原始代码流程沿用之前的D1值同时捕获未初始化的路径为其赋一个最佳猜测值。原始 BASIC 中的问题对照 furtrader.bas 可以看到蒙特利尔分支第 1177 行与魁北克分支都设置了D1狐狸皮价格纽约分支第 1250 行起只设置了M1、E1、B1唯独没有设置D1如果玩家第一年就直接选择纽约销售结算时第 1414 行PRINT YOUR FOX SOLD FOR $;D1*F(4)使用的D1将是未初始化变量如果此前去过其他要塞则会沿用上一轮的价格。这直接导致了 38_Fur_Trader/README.md 中Known Bugs记录的玩家可见现象某些毛皮的价格不会随要塞变化——所有毛皮价格都在访问 Fort 1 时被设置当你选择 Fort 2 或 Fort 3 时部分价格仍沿用 Fort 1 的值导致同样的毛皮在去没去过其他要塞时得到不同售价。C 移植的修复策略C 版本在保留原始行为的同时修复了未初始化路径见 furtrader.c 与 furtrader.cfloat fox_price -1; /* sometimes this takes the last price (probably this was a bug) */ ... if ( fox_price 0 ) { /* Original Bug? There is no Fox price generated for New York, it will use any previous D1 price. So if there was no previous value, make one up */ fox_price ( ( 0.25 * randFloat() 1.05 ) * 100 0.5 ) / 100; /* not in orginal code */ }具体策略分两步初始化防御fox_price初始化为-1一个不可能是合法价格的哨兵值避免真正的未定义行为保留原始语义 兜底如果玩家此前去过其他要塞fox_price已有值则沿用上一轮价格忠实保留原版行为只有从未设置过 0时才用与蒙特利尔狐狸价格类似的公式0.25*rand 1.05区间 1.05–1.30生成一个最佳猜测值并明确注释/* not in orginal code */标注这是移植新增代码。这种既忠实又安全的处理方式值得学习它没有擅自改变原版游戏逻辑而是用注释与哨兵值把历史 Bug 的边界条件显式化。跨语言一致性验证这一 Bug 修复策略并非 C 版独有——对照 38_Fur_Trader/python/furtrader.py 可以看到Python 版同样声明fox_price None并在纽约分支中判断if fox_price is None:才生成兜底价格注释几乎一字不差。这说明多个移植版本对同一历史 Bug 采取了相同的保留 兜底共识可交叉印证该分析的准确性。移植风格观察与源码细节结合翻译者文档与源码可以总结 C 版移植的几个风格特征指针最小化指针仅出现在必须修改调用方变量的地方如getFursPurchase(int *furs)、zeroInventory(int*)其余数据传递全部使用值语义老式 C 风格使用printf、fgets、strtol等经典 API无任何平台相关扩展符合不知道编译器有多老的兼容性考量明确的错误哨兵源码内置Internal error #1/#2/#3/#4防御分支分别覆盖非法要塞编号与越界事件值见 furtrader.c 等在输入不可能触达的路径上仍做了兜底随机数种子srand(time(NULL))以当前时间初始化随机序列保证每局价格与事件不同见 furtrader.c。另有一处可留意的源码细节Internal Error #4分支的printf调用缺少对应的event_picker实参见 furtrader.c由于该分支逻辑上不可达并未造成实际影响但若以-Wformat严格编译可能产生警告。总结Fur Trader的 ANSI C 移植是忠实转换 现代工程化的典型案例它用符号常量、辅助函数和状态机把 1978 年 BASIC 的GOTO迷宫重构成可读的 C99 代码却完整保留了原版的定价公式、事件概率、文本输出与游戏节奏面对原始代码中的狐狸皮价格 Bug翻译者没有武断地修掉而是通过文档披露、哨兵值初始化、保留历史语义、注释标注新增代码的方式把历史真相与修复意图同时留给了后来者。对想学习经典游戏移植、或研究如何在兼容性与正确性之间取舍的开发者这份文档与源码是一份小而完整的范本。如需进一步探索可继续阅读C 移植说明、C 源码、游戏原始说明与已知 Bug、原始 BASIC 源码、Python 移植对照。【免费下载链接】basic-computer-gamesAn 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/项目地址: https://gitcode.com/gh_mirrors/ba/basic-computer-games创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
智能工具提升内容创作效率与原创性 1. 选题与降重的双重挑战在内容创作领域,选题精准度和内容原创性一直是困扰创作者的难题。我见过太多同行花费数小时确定选题方向,结果产出内容却无人问津;也遇到过辛苦创作的内容因为重复率过高而被平台限流的情况。过去三年里,我… · 2026/9/23 11:31:03
飞书 CLI 从入门到自动化:安装、认证与多维表格操作实战 1. 飞书 CLI 到底是什么,为什么值得花时间学第一次听到“飞书 CLI”这个词,大概率是在某个技术群里看到有人发了一张终端截图,里面几行命令跑完,多维表格的数据就批量更新了,或者一条消息就推到了群里。当时我的反应是… · 2026/9/23 11:30:57
易语言开发电商订单自动化管理工具实战 1. 项目背景与核心功能解析"夏目Xiamu转单插件"是一款基于易语言开发的电商订单管理工具,主要解决多平台订单流转与自动化处理需求。其核心价值在于:实现电商平台(如淘宝、拼多多)与仓储管理系统(ZCJ&#x… · 2026/9/23 11:30:57
DeepSeek V4.1 Flash生产部署指南:vLLM与SGLang选型实战 1. 项目概述:这不是“跑个模型”那么简单,而是面向生产级推理的系统工程DeepSeek V4.1 Flash 这个名字一出来,很多人第一反应是“又一个新版本大模型”,但如果你真把它当成普通模型去部署,十有八九会在显存报错、CUDA … · 2026/9/23 13:02:08
GFPGAN人脸修复原理与工程实践指南 简介:这是一套基于Python实现的GFPGAN人脸美颜与清晰度增强开源项目,面向图像/视频处理开发者、AI视觉初学者及内容创作者,解决人脸图像与短视频的自动化美化与画质提升需求。资源共60个文件,包含29个核心Python脚本(如… · 2026/9/23 13:02:01
高光谱数据预处理方法详解:从DN值到可用的光谱矩阵 简介:面向高光谱数据预处理任务的Python实现合集,系统整合了标准正态变换、多元散射校正、Savitzky-Golay平滑滤波、滑动平均、一阶差分、二阶差分、小波变换、均值中心化、标准化、最大最小归一化和矢量归一化等常用预处理算法,每个算法均提… · 2026/9/23 13:02:01
FPGA时序分析:读懂XST综合报告与布局布线后的TRACE 简介:ISE静态时序分析是一份面向FPGA开发者和数字电路设计人员的实操型学习文档,围绕Xilinx ISE综合后生成的Timing Report进行系统性解读,帮助读者评估设计时序性能、发现潜在时序瓶颈,并为后续电路优化提供明确切入点。资源包内… · 2026/9/23 13:02:01
企业级智能体效能管理:从能跑到管得住的落地指南 1. 企业级智能体从“能跑”到“管得住”的转折点过去一年,我经手过不下十个企业级智能体项目,从销售获客智能体到内部知识问答智能体,几乎每个项目在POC阶段都跑得挺漂亮,但一到规模化推广就出问题。最常见的情况是:某… · 2026/9/23 13:02:01
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29