カスタムゲーム - プロバブリーフェア
カスタムゲームでの使用方法
YEET Originalのすべてのベットは、ラウンドシードから始まります。ラウンドシードは、プレイヤーのクライアントシードとベットのナンス(nonce)をHMAC-SHA256でハッシュ化したもので、YEETが選択したサーバーシードが鍵として使用されます。ゲームはそのベットに必要なすべての乱数値をこのラウンドシードから生成します。サーバーシードはプレイ前にハッシュ化された状態で表示され、シードペアを更新すると公開されるため、過去のすべてのベットのラウンドシードを再計算し、結果がベット後に改ざんされていないことを確認できます。
他の検証ツールでは一致しない場合があります
他カジノ向けに作られた検証サイトでは乱数の生成方法が異なるため、そこでYEETのベットを確認しても異なる結果が出る可能性があります。YEETのベットは、ゲームの公平性ウィンドウの「検証」タブ、またはこのページのコードを使用して確認してください。
変換
変換とは、ラウンドシードのエントロピーをゲームの結果に変換する仕組みです。すべてのオリジナルゲームにおいて、構成要素は同じです。unbiasedUint がn個の等確率な位置から1つを選び、ゲームがその位置で勝利かどうかを判定します。s個の勝利ポジションを持つステップの勝率は s / n となります。
このページには、すべてのゲームの変換が記載されているわけではありません。以下の例は、1つのゲームにおけるパターンを示しています。
例:Lamb Chop
Lamb Chopには16回のホップがあり、各ホップは同じラウンドシードからの1回の抽選です。ホップ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'
));