3、第一个挑战:猜数字游戏 —— 建立基础的信任循环(出题与验证)
好了,理论聊完了,咱们来点实际的。
第一个挑战,我选了一个经典到不能再经典的东西——猜数字游戏。你别看它简单,这玩意儿是建立「信任循环」最直观的模型。说白了,就是让计算机出题,你来验证它有没有作弊。
3.1 游戏规则:一个极简的信任模型
规则我尽量简化,就三步:
- 出题:程序生成一个 1 到 100 之间的随机整数。
- 猜测:你输入一个数字,程序告诉你「大了」、「小了」或者「猜对了」。
- 验证:游戏结束后,程序公布答案,并允许你检查整个过程的日志。
你可能会问:「这有什么信任不信任的?」
嗯,问题就在这。如果程序生成的随机数不是真正的随机呢?如果它偷偷改了答案呢?我们做这个挑战,就是要亲手搭建一个可审计的系统。每一步都留下痕迹,每一步都能被复查。
核心概念:信任循环
出题 → 交互 → 公布答案 → 验证日志。这个闭环一旦建立,用户就不再是「盲信」,而是「确信」。
3.2 代码实现:从「黑盒」到「白盒」
我先给你看一个最基础的版本。注意,这个版本没有任何验证机制,纯粹是功能演示。
// 基础版猜数字游戏(无验证)
function basicGuessGame() {
const secret = Math.floor(Math.random() * 100) + 1;
let guess;
let attempts = 0;
while (guess !== secret) {
guess = parseInt(prompt("猜一个 1-100 的数字:"), 10);
attempts++;
if (guess > secret) {
console.log("大了");
} else if (guess < secret) {
console.log("小了");
} else {
console.log(`猜对了!答案是 ${secret},你用了 ${attempts} 次。`);
}
}
}
这段代码能跑,但有个致命问题——你没法证明程序没作弊。比如,程序可能在你猜第 5 次的时候,悄悄把答案从 42 改成了 50。你完全不知道。
我在早期做在线考试系统时就踩过类似的坑。那时候我们直接把答案存在前端变量里,结果学生用浏览器调试工具一翻就全看见了。后来我们学乖了,所有敏感数据必须走服务端,而且每一步都要签名。
所以,我们要给这个游戏加上「信任层」。怎么做?核心思路就两条:
- 记录所有操作日志:谁、在什么时间、做了什么操作、结果是什么。
- 提供验证入口:游戏结束后,用户能通过日志重建整个游戏过程,确认答案没有被篡改。
来看改进版:
// 可验证版猜数字游戏
class VerifiableGuessGame {
constructor() {
this.secret = Math.floor(Math.random() * 100) + 1;
this.log = []; // 操作日志
this.attempts = 0;
this.isFinished = false;
// 记录出题事件
this.log.push({
event: 'GAME_START',
timestamp: Date.now(),
secret: this.secret // 游戏结束后才公开
});
}
guess(number) {
if (this.isFinished) {
return { error: '游戏已结束' };
}
this.attempts++;
let result;
if (number > this.secret) {
result = 'HIGH';
} else if (number < this.secret) {
result = 'LOW';
} else {
result = 'CORRECT';
this.isFinished = true;
}
// 记录每次猜测
this.log.push({
event: 'GUESS',
timestamp: Date.now(),
guess: number,
result: result,
attempt: this.attempts
});
return { result, attempts: this.attempts };
}
// 游戏结束后,获取完整日志用于验证
getAuditLog() {
if (!this.isFinished) {
return { error: '游戏尚未结束,无法获取审计日志' };
}
return {
secret: this.secret,
totalAttempts: this.attempts,
log: this.log
};
}
}
设计思路:日志里记录了每次猜测的原始值,包括最终答案。用户拿到这份日志后,可以自己重放一遍,确认程序没有在中间改过答案。这就是「可审计性」的雏形。
3.3 验证流程:亲手检查信任
光有日志还不够,你得知道怎么用它来验证。我建议你按这个步骤来:
- 记录初始状态:游戏开始前,记下当前时间戳和程序版本号。
- 执行游戏:正常玩一遍,程序自动记录所有操作。
- 导出日志:游戏结束后,调用
getAuditLog()获取完整日志。 - 手动重放:按照日志里的
guess值,用同一个规则(大了/小了/正确)重新判断一遍,看结果是否一致。 - 核对答案:确认日志里的
secret和游戏过程中实际生效的答案是否一致。
这个过程听起来繁琐,但做一遍你就会发现——信任不是靠感觉,而是靠可重复的验证。
注意:这个版本的验证还比较初级。真正的生产环境还需要考虑日志防篡改(比如哈希链)、时间同步、身份认证等问题。我们后面会逐步引入。
3.4 知识图谱:猜数字游戏中的信任循环
下面这张图展示了整个信任循环的完整结构。你可以看到,从出题到验证,每个环节都环环相扣。
3.5 常见陷阱与避坑指南
做这个挑战的时候,有几个坑我当年都踩过,分享给你:
| 陷阱 | 表现 | 解决方案 |
|---|---|---|
| 日志不完整 | 只记录了最终结果,没有中间过程 | 每次操作都追加一条日志,包括时间戳 |
| 答案提前泄露 | 日志在游戏结束前就能看到 secret | 游戏结束前,日志中的 secret 字段设为 null |
| 时间戳不可信 | 使用客户端时间,容易被篡改 | 使用服务端时间或区块链时间戳 |
| 日志被覆盖 | 多次游戏共用同一个日志变量 | 每次游戏新建一个日志数组,游戏结束后归档 |
我的经验:我曾经在一个项目中,因为日志数组是全局变量,导致两个用户同时玩游戏时日志互相污染。排查了半天才发现。后来我强制每个游戏实例独立维护自己的日志,问题就解决了。
3.6 小结:信任循环的起点
这个猜数字游戏虽然简单,但它把「信任」从一个抽象概念变成了可操作的技术方案。你想想看,通过日志记录和验证流程,我们让一个原本「黑盒」的程序变得透明可审计。这就是信任循环的起点。
后面我们会在这个基础上,逐步引入更复杂的机制——比如哈希链、数字签名、去中心化验证。但核心思想不会变:信任不是靠承诺,而是靠可验证的证据。
嗯,现在你可以动手试试了。写一个带日志的猜数字游戏,然后自己验证一遍。相信我,亲手走完这个流程,你对「信任」的理解会完全不一样。