3、第一个挑战:猜数字游戏 —— 建立基础的信任循环(出题与验证)

好了,理论聊完了,咱们来点实际的。

第一个挑战,我选了一个经典到不能再经典的东西——猜数字游戏。你别看它简单,这玩意儿是建立「信任循环」最直观的模型。说白了,就是让计算机出题,你来验证它有没有作弊。

3.1 游戏规则:一个极简的信任模型

规则我尽量简化,就三步:

  1. 出题:程序生成一个 1 到 100 之间的随机整数。
  2. 猜测:你输入一个数字,程序告诉你「大了」、「小了」或者「猜对了」。
  3. 验证:游戏结束后,程序公布答案,并允许你检查整个过程的日志。

你可能会问:「这有什么信任不信任的?」

嗯,问题就在这。如果程序生成的随机数不是真正的随机呢?如果它偷偷改了答案呢?我们做这个挑战,就是要亲手搭建一个可审计的系统。每一步都留下痕迹,每一步都能被复查。

核心概念:信任循环

出题 → 交互 → 公布答案 → 验证日志。这个闭环一旦建立,用户就不再是「盲信」,而是「确信」。

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 验证流程:亲手检查信任

光有日志还不够,你得知道怎么用它来验证。我建议你按这个步骤来:

  1. 记录初始状态:游戏开始前,记下当前时间戳和程序版本号。
  2. 执行游戏:正常玩一遍,程序自动记录所有操作。
  3. 导出日志:游戏结束后,调用 getAuditLog() 获取完整日志。
  4. 手动重放:按照日志里的 guess 值,用同一个规则(大了/小了/正确)重新判断一遍,看结果是否一致。
  5. 核对答案:确认日志里的 secret 和游戏过程中实际生效的答案是否一致。

这个过程听起来繁琐,但做一遍你就会发现——信任不是靠感觉,而是靠可重复的验证。

注意:这个版本的验证还比较初级。真正的生产环境还需要考虑日志防篡改(比如哈希链)、时间同步、身份认证等问题。我们后面会逐步引入。

3.4 知识图谱:猜数字游戏中的信任循环

下面这张图展示了整个信任循环的完整结构。你可以看到,从出题到验证,每个环节都环环相扣。

猜数字游戏信任循环结构图 出题 生成随机数 + 记录日志 交互 用户猜测 + 系统反馈 公布答案 展示 secret + 完整日志 验证 重放日志 + 核对结果 信任反馈循环 关键点 • 每一步都记录日志 • 日志包含原始数据 • 验证可手动重放 • 形成闭环信任

3.5 常见陷阱与避坑指南

做这个挑战的时候,有几个坑我当年都踩过,分享给你:

陷阱 表现 解决方案
日志不完整 只记录了最终结果,没有中间过程 每次操作都追加一条日志,包括时间戳
答案提前泄露 日志在游戏结束前就能看到 secret 游戏结束前,日志中的 secret 字段设为 null
时间戳不可信 使用客户端时间,容易被篡改 使用服务端时间或区块链时间戳
日志被覆盖 多次游戏共用同一个日志变量 每次游戏新建一个日志数组,游戏结束后归档

我的经验:我曾经在一个项目中,因为日志数组是全局变量,导致两个用户同时玩游戏时日志互相污染。排查了半天才发现。后来我强制每个游戏实例独立维护自己的日志,问题就解决了。

3.6 小结:信任循环的起点

这个猜数字游戏虽然简单,但它把「信任」从一个抽象概念变成了可操作的技术方案。你想想看,通过日志记录和验证流程,我们让一个原本「黑盒」的程序变得透明可审计。这就是信任循环的起点。

后面我们会在这个基础上,逐步引入更复杂的机制——比如哈希链、数字签名、去中心化验证。但核心思想不会变:信任不是靠承诺,而是靠可验证的证据。

嗯,现在你可以动手试试了。写一个带日志的猜数字游戏,然后自己验证一遍。相信我,亲手走完这个流程,你对「信任」的理解会完全不一样。