体育

游戏

综合

自定义游戏 - 可验证公平

如何在自定义游戏中使用

YEET 原创游戏的每一次投注都始于一个回合种子(round seed)。回合种子由您的客户端种子(client seed)和投注随机数(nonce)经 HMAC-SHA256 算法生成,并以 YEET 选择的服务器种子(server seed)作为密钥。游戏随后从该回合种子中提取投注所需的所有随机值。在您投注前,我们会向您展示哈希处理后的服务器种子,并在您轮换种子对时揭晓原始值,以便您重新计算过去任何投注的回合种子,验证其结果在投注后未被篡改。

其他验证器可能不匹配

为其他赌场制作的验证网站生成随机数的方式可能不同,因此在那里检查 YEET 投注可能会得出不同结果。请在游戏“公平性”窗口的“验证”选项卡中,或使用本页面上的代码来验证 YEET 投注。

转换

转换逻辑将轮次种子的熵转化为游戏结果。所有原创游戏的核心构件是一样的:unbiasedUint 在 n 个等概率位置中选取一个,游戏随之检查该位置是否获胜。一个在 n 个位置中有 s 个获胜点位的步骤,其获胜概率为 s / n。

本页面未列出每款游戏的转换逻辑。下方的示例展示了其中一款游戏的模式。

示例:Lamb Chop

Lamb Chop 有 16 次跳跃,每次跳跃都是从同一轮种子中进行的一次抽取。在第 h 次跳跃时,赛道上有 totalStart − h 个位置,其中 safeStart − h 个是安全的。掷出的点数小于安全位置数量即视为存活。第一个未能存活的掷点标志着该轮结束,乘数则根据已通过的跳跃次数从赔率表中读取。

const LAMB_CHOP_TOTAL_HOPS = 16;

const LAMB_CHOP_LANES = {
  easy: [19, 21],
  medium: [19, 23],
  hard: [19, 25],
  very_hard: [19, 27],
  death_wish: [20, 32],
};

const LAMB_CHOP_PAYTABLE = {
  easy: [
    1.0721, 1.1912, 1.3313, 1.4977, 1.6975, 1.94, 2.2384, 2.6115,
    3.0863, 3.7036, 4.5266, 5.6583, 7.275, 9.7, 13.58, 20.37,
  ],
  medium: [
    1.1742, 1.4351, 1.7728, 2.216, 2.8069, 3.6089, 4.7194, 6.2925,
    8.5807, 12.013, 17.3522, 26.0283, 40.9016, 68.1694, 122.705, 245.41,
  ],
  hard: [
    1.2763, 1.7017, 2.3023, 3.1657, 4.432, 6.3315, 9.2537, 13.8806,
    21.4519, 34.323, 57.2051, 100.1089, 185.9166, 371.8333, 818.0333, 2045.0833,
  ],
  very_hard: [
    1.3784, 1.991, 2.928, 4.392, 6.7344, 10.5826, 17.0951, 28.4918,
    49.2132, 88.5838, 167.325, 334.65, 717.1071, 1673.25, 4350.45, 13051.35,
  ],
  death_wish: [
    1.552, 2.5322, 4.2203, 7.1994, 12.5989, 22.6781, 42.1166, 80.9934,
    161.9869, 338.7, 745.1401, 1738.6604, 4346.651, 11798.0529, 35394.1588, 120340.14,
  ],
};

async function verifyLambChopBet(serverSeed, clientSeed, nonce, volatility) {
  const seed = await deriveGameSeed(serverSeed, clientSeed, nonce);
  const result = await verifyLambChopFromSeed(seed, volatility);
  return { serverSeed, clientSeed, nonce, ...result };
}

async function verifyLambChopFromSeed(seed, volatility) {
  const lane = LAMB_CHOP_LANES[volatility];
  if (!lane) throw new Error(`No lamb-chop lane geometry for risk profile '${volatility}'.`);

  const [safeStart, totalStart] = lane;
  const entropy = new GameEntropy(hexToBytes(seed));
  const hops = [];
  let bustIndex = LAMB_CHOP_TOTAL_HOPS;

  for (let hop = 0; hop < LAMB_CHOP_TOTAL_HOPS; hop++) {
    const safePositions = safeStart - hop;
    const totalPositions = totalStart - hop;
    const roll = await unbiasedUint(entropy, totalPositions);
    const survived = roll < safePositions;

    hops.push({
      hop,
      safePositions,
      totalPositions,
      chance: safePositions / totalPositions,
      roll,
      survived,
    });

    if (!survived) {
      bustIndex = hop;
      break;
    }
  }

  return {
    seed,
    entropyCursor: entropy.cursor,
    volatility,
    hops,
    bustIndex,
    clearedAllHops: bustIndex >= LAMB_CHOP_TOTAL_HOPS,
    maxReachableMultiplier: lambChopMultiplierFor(volatility, bustIndex),
    paytable: LAMB_CHOP_PAYTABLE[volatility],
  };
}

function lambChopMultiplierFor(volatility, hopCount) {
  if (hopCount < 1) return 0;

  const row = LAMB_CHOP_PAYTABLE[volatility];
  if (!row) throw new Error(`No lamb-chop paytable for risk profile '${volatility}'.`);

  const multiplier = row[hopCount - 1];
  if (multiplier === undefined) {
    throw new Error(`No lamb-chop paytable row for ${volatility} at ${hopCount} hop(s).`);
  }

  return multiplier;
}

// Use the revealed server seed (64 hex characters) and the client seed and nonce shown on the bet.
console.log(await verifyLambChopBet(
  'REVEALED_SERVER_SEED',
  'yeetdemo-7f3a91',
  '1842',
  'easy'
));