Mik azok a játékmeneti események?
Korábban a generateFloats és byteGenerator függvényekkel 0 és 1 közötti véletlen lebegőpontos számokat generáltunk. A játékmeneti események ezeket a generált lebegőpontos számokat tényleges játékeredményekké alakítják. Ez játékonként eltérő módon történik. A Plinko esetében a lebegőpontos számok segítenek meghatározni a golyó esésének irányát. A Dice esetében a lebegőpontos számok segítenek meghatározni a dobás eredményét.
Az alábbiakban részletesen bemutatjuk, hogyan alakítjuk át a lebegőpontos számokat tisztességes eseményekké vagy eredményekké a platformunkon elérhető minden saját játékban.
Tower
A Tower célja, hogy a kulcsok megtalálásával és a mérgezett almák elkerülésével feljuss a torony tetejére, és megmentsd a hercegnőt. A torony minden sora az adott nehézségtől függően előre meghatározott számú biztonságos mezőt (kulcsot) és mérgezett almát tartalmaz.
A Tower játékmeneti eseménye az egyes sorokban található biztonságos mezők (vagy kulcsok) helyzetének meghatározása.
A torony összesen 9 sorból áll. Az oszlopok száma, valamint a kulcsok és mérgezett almák eloszlása a kiválasztott nehézségtől függ:
Könnyű: 4 oszlop – soronként 3 kulcs és 1 mérgezett alma
Közepes: 3 oszlop – soronként 2 kulcs és 1 mérgezett alma
Nehéz: 2 oszlop – soronként 1 kulcs és 1 mérgezett alma
Szakértő: 3 oszlop: soronként 1 kulcs és 2 mérgezett alma
Mester: 4 oszlop – soronként 1 kulcs és 3 mérgezett alma
Az egyes sorok eredményét a kulcsok (biztonságos mezők) véletlenszerű pozícióinak generálásával határozzuk meg a rendelkezésre álló oszlopok között, a nehézségi beállítás alapján.
const TOWER_DIFFICULTY_TO_CONFIG: Record<TowerDifficulty, DifficultyConfig> = {
[TowerDifficulty.EASY]: {
count: 3,
columns: 4,
},
[TowerDifficulty.MEDIUM]: {
count: 2,
columns: 3,
},
[TowerDifficulty.HARD]: {
count: 1,
columns: 2,
},
[TowerDifficulty.EXPERT]: {
count: 1,
columns: 3,
},
[TowerDifficulty.MASTER]: {
count: 1,
columns: 4,
},
};
// Generate floats to determine the positions of safe tiles (keys) for each row
const floats = generateFloats({
serverSeed,
clientSeed,
nonce,
cursor,
count,
});
// Get the tower configuration based on the selected difficulty
const towerConfig = TOWER_DIFFICULTY_TO_CONFIG[difficulty];
const results: number[][] = [];
const resultPerRow = towerConfig.count;
// Iterate through each row to determine the positions of safe tiles for that row
for (let i = 0; i < TOWER_TOTAL_ROWS.toNumber(); i++) {
const result: number[] = [];
const values = Array.from(Array(towerConfig.columns).keys());
// Get positions for safe tiles in the current row
for (let j = 0; j < resultPerRow; j++) {
const float = floats[i * resultPerRow + j];
if (float === undefined) {
break;
}
const position = Math.floor(float * (towerConfig.columns - j));
result.push(values.splice(position, 1)[0] ?? 0);
}
results.push(result);
}
return results;
// Example: when clientSeed='abc', serverSeed='def', nonce=1, difficulty='easy'
// results: [
// [0, 1, 2],
// [0, 2, 3],
// [0, 2, 3],
// [0, 1, 2],
// [0, 1, 3],
// [0, 1, 2],
// [1, 2, 3],
// [0, 1, 3],
// [0, 1, 3]
// ]
// Each sub-array represents the column indexes of safe tiles for that row
// (e.g., for the first row, safe tiles are in columns 0, 1, and 2)
Chicken
A Chicken célja, hogy a csirkét minél több sávon átvezesd anélkül, hogy a veszélyes sávra lépnél.
Minden sikeres előrelépés növeli a kifizetési szorzót. A játékos bármikor kifizethet, mielőtt a csirke a veszélyes sávra ugrana. Ha a csirke a játékos kifizetése előtt eléri a veszélyzónát, a tét elveszik.
A Chicken fő játékmeneti eseménye a veszélyes sáv meghatározása – vagyis annak a konkrét sávnak a kijelölése, ahol a csirke veszít.
A Chickenben 4 nehézségi szint van. Az áthaladható sávok száma a kiválasztott nehézségtől függ:
Könnyű: 19 sáv
Közepes: 17 sáv
Nehéz: 15 sáv
Szakértő: 10 sáv
const TOTAL_LANES = 20
// Number of lanes that the chicken can cross for each difficulty
const DIFFICULTY_TO_VALID_LANE_COUNT: Record<ChickenDifficulty, number> = {
[ChickenDifficulty.EASY]: 19,
[ChickenDifficulty.MEDIUM]: 17,
[ChickenDifficulty.HARD]: 15,
[ChickenDifficulty.EXPERT]: 10,
};
// Number of gameResults generated depends on the difficulty
// Example with Hard difficulty, we generate 20 - 15 = 5 numbers
// and the smallest number in the array is the danger lane
const gameResults = generateFloats({
serverSeed,
clientSeed,
nonce,
cursor: 0,
count: TOTAL_LANES - DIFFICULTY_TO_VALID_LANE_COUNT[difficulty] // difficulty selected for the game
}).map((val, index) => Math.floor(val * (TOTAL_LANES - index)));
// Danger lane is determined by the smallest number in the game results array
const dangerLane = Math.min(...gameResults)
// Example: Hard difficulty - gameResults = [10, 4, 6, 15, 8]
// Danger lane will be on 4 (this is zero based index)
// Lane 0 - 3 are safe and lane 4 will be the danger lane
// The chicken will lose upon reaching lane 4 if not cashed out earlier
Plinko
A Plinkóban a játékosok 8 és 16 magasság közötti piramisok közül választhatnak. Amikor a golyót felülről elengedik, a Plinko táblán lévő minden egyes pegnél 8–16 alkalommal balra vagy jobbra esik. A Plinko játékmeneti eseménye annak meghatározása, hogy a golyó az egyes szinteken balra vagy jobbra esik-e, amit a 0 és 1 jelöl.
// Create multiple floats between 0 and 1
// Example: floats = [0.8320531346835196, 0.8531235849950463, 0.18227359023876488, 0.774284637067467, 0.18627392360940576, 0.6012540922965854, 0.608081541955471, 0.46018488449044526] when clientSeed='abc', serverSeed='def', nonce=1, count=8
// count refers to the number of plinko rows
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count });
// Example: [1, 1, 0, 1, 0, 1, 1, 0] Each 1 represents a drop to the right whereas 0 represents a drop to the left
const dropDirections = floats.map(val => Math.floor(val * 2));
// This sums up all the values in the array to get the final position of the ball from the left.
// Example: finalPositionFromLeft = 5 (the ball will land on the 6th slot from the left)
const finalPositionFromLeft = dropDirections.reduce((cur, acc) => cur + acc, 0)
Dice
A Dice játékban a dobás értéke 0.00 és 100.00 között lehet. A Dice játékmeneti eseménye ennek az értéknek a meghatározása. Ezt a (floats * 10,001) / 100) képlettel végezzük. Mivel legfeljebb 2 tizedesjegyű értékeket és a 0 számot is figyelembe vesszük, összesen 10,000 + 1 = 10,001 lehetséges eredmény van (a tizedesjegyeket is beleértve).
// Creates an array of random numbers
// Example: With clientSeed = 'abc', serverSeed = 'def', nonce = 1, floats = [0.43053962965495884]
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 1 });
// Converts the value in the array to a number between 0.00 to 100.00 and return the value
// Example: resultValue = [43.05]
const resultValue = floats.map(val => Math.floor(floats * 10001) / 100);
return resultValue[0];
// Example: 43.05 is returned as the result of the game
Limbo
A Limbóban a játék célja egy >1 szorzó megtippelése. Ha a játék eredménye nagyobb a szorzónál, a felhasználó megnyeri a játékot. A játékmeneti esemény egy 1 feletti lebegőpontos érték generálása, amely hiperbolikus görbe szerinti eloszlást követ.
// Generate float between 0 and 1
// Example: floats = [0.43053962965495884], float = 0.43053962965495884,
// when clientSeed='abc', serverSeed='def', nonce=1
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 1 });
const float = floats[0]
// generate limbo game event results with house edge (1%)
// using a hyperbolic 1/x curve
// multiplying by this and dividing by (MAX_VALUE + 1) prevents division by 0 error
const MAX_VALUE = 2 ** 24;
const rtp = 0.99;
// Example: rawValue = 2.298905
const rawValue = (rtp * MAX_VALUE) / (MAX_VALUE * float + 1)
// resultValue = 2.29
const resultValue = (0.99 * MAX_VALUE / (MAX_VALUE * float +1)).toFixed(2,ROUND_DOWN);
return resultValue;
Keno
A Kenóban a játékmeneti eseményhez 10 egyedi drágakőpozíciót kell meghatározni a kenótáblán. Ennek érdekében 10 különböző lebegőpontos számot generálunk 1 és 40 között, amelyek a kenótábla egyes helyeit jelölik. Ezután egy folyamat kezeli az ismétlődő lebegőpontos számokat, és visszaadja a végleges 10 drágakőpozíciót.
// Generate 10 different floats as there are 10 positions that are selected when the game is played
// Example: floats = [18, 26, 7, 22, 31, 10, 23, 8, 24, 13] when clientSeed='abc', serverSeed='def', nonce=1
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 10 }) .map((val, index) => Math.ceil(val * (40 - index)))
// array used to store the position of the gems const gemLocations: number[] = [];
// this loop helps to prevent duplicate gem positions by skipping positions that already contain a gem
for (const val of floats) { let currentGem = val;
let i = 0;
while (i <= currentGem) {
if (gemLocations.includes(i)) {
currentGem++;
}
i++;
}
gemLocations.push(currentGem);
}
// returns the location of the gem on the board
// Example: [18, 27, 7, 24, 35, 11, 28, 9, 31, 16] return gemLocations;
Mines
A Mines játékban a játékmeneti eseményhez meg kell határozni az aknák elhelyezkedését a 25 mezőből álló aknatáblán. A felhasználó által kiválasztott aknaszám alapján 0 és 24 közötti egész számok listáját generáljuk, hogy a tábla 25 mezőjét ábrázoljuk.
// Generate 10 different floats
// Example: [20, 20, 4] when clientSeed='abc', serverSeed='def', nonce=1, numberOfBombs=3
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: numberOfBombs })
.map((val, index) => Math.floor(val * (25 - index)));
// array used to store the position of the bombs
const mineLocations: number[] = [];
// this loop helps to prevent duplicate bomb positions by skipping positions that already contain a mine
for (const val of floats) {
let currentMine = val;
let i = 0;
while (i <= currentMine) {
if (mineLocations.includes(i)) {
currentMine++;
} i++; } mineLocations.push(currentMine); }
// returns the location of the bombs on the board
// Example: [20, 21, 4]
return mineLocations;
Rulett
Rulettünk az európai típusú, egyetlen ‘0’ nullás keréken alapul, amelyen 37 különböző rekesz található 0 és 36 között. A rulett játékmeneti eseménye annak kiszámítása, hogy a golyó a 37 rekesz közül melyikben áll meg.
// Generate a float between 0 and 1
// Example: floats = [0.43053962965495884]
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor: 0, count: 1 });
// generate an integer from 0 to 37 to represent the pocket to land on
// Example: resultValue = 15
const resultValue = floats.map(val => Math.floor(val * 37))[0];
return resultValue
Wheel
A Wheel játékban a felhasználó kiválasztja, hány szegmense legyen a keréknek. Attól függően, hogy a mutató melyik szegmensen áll meg, a felhasználó az adott szegmenshez tartozó szorzót nyeri meg. A játékmeneti esemény a szegmens meghatározása.
// Generate a float between 0 and 1
// Example: floats = [0.43053962965495884]
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor, count:1 });
// Get an integer representing the number of segments set in the game
// Example: resultSegment = 8
const resultSegment = floats.map(val => Math.floor(val * numberOfSegments))[0];
return resultSegment
Blackjack
A Blackjack játékban korlátlan paklit használunk. Ezért minden körben azonosak az esélyek. A Blackjack játékmeneti eseménye annak meghatározása, hogy melyik lapot húzza a játékos vagy a bankár a pakliból.
// Generate a float between 0 and 1
// Example: floats = [0.43053962965495884, 0.6645898742135614, 0.17454026662744582, 0.5729992990382016, 0.850033157505095] (52 elements are generated but only 5 are shown here for brevity)
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor, count:52 });
const CARDS = [ ♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4, ♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6, ♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9, ♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J, ♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A, ♥A, ♠A, ♣A
];
// Get an integer 0 to 51, representing the index of the cards
// Example: cardFloats = [22, 34, 9, 29, 44]
const cardFloats = floats.map(val => Math.floor(val * 52));
// Example: cards = [♠7, ♠10, ♥4, ♥9, ♦K]
const cards = cardFloats.map(val => CARDS[val])
return cards;
Hilo
A Hilo játékban korlátlan paklit használunk. Ezért minden körben azonosak az esélyek. A játék célja annak megtippelése, hogy a következő lap értéke magasabb vagy alacsonyabb lesz-e a jelenlegi lapénál. A Hilo játékmeneti eseménye annak meghatározása, hogy a felhasználó melyik lapot húzza legközelebb (ha húz lapot).
// Generate a float between 0 and 1
// Example: floats = [0.43053962965495884, 0.6645898742135614, 0.17454026662744582, 0.5729992990382016, 0.850033157505095] (an unlimited number of cards can be drawn but only 5 are shown here for brevity)
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor, count:52 });
const CARDS = [
♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4, ♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6, ♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9, ♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J, ♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A, ♥A, ♠A, ♣A
];
// Get an integer 0 to 51, representing the index of the cards
// Example: cardFloats = [22, 34, 9, 29, 44]
const cardFloats = floats.map(val => Math.floor(val * 52));
// Example: cards = [♠7, ♠10, ♥4, ♥9, ♦K]
const cards = cardFloats.map(val => CARDS[val])
return cards;
Crash
A Crash játék eredményének kiszámítása 2 részből áll
Bitcoin-blokk hash
Seed
Bitcoin hash
A részletek ebben a tweetben találhatók:
A 779588 blokk hash-e a BTC-blokkkeresőben található (https://btcscan.org/block/000000000000000000033ab71b5fa7edcafe388e5f49719f1de8e1f8d0670460), és megegyezik a tweetben szereplő hash-sel.
Seed
A 10 millió Crash játék seedjének generálási folyamata a tisztességesség és az átláthatóság biztosítására szolgál, megakadályozva a Shuffle általi manipuláció bármilyen lehetőségét. Így generáljuk és ellenőrizzük a seedeket:
Kezdeti seedgenerálás: A 10 milliomodik játék seedjét a Shuffle véletlenszerűen választja ki.
Szekvenciális hashelés a seedgeneráláshoz: Az összes többi játék seedjének előállításához visszafelé történő hashelési módszert használunk:
Az egyes játékok seedje a következő játék seedjének hasheléséből származik. Konkrétan a 9,999,999. játék hash-e a 10 milliomodik játék hash-ének SHA256 hash-e.
Ez a láncolat úgy folytatódik, hogy minden játék seedje a következő játék hash-ének hasheléséből származik, míg végül az első játék seedje a második játék hash-éből származik.
A seed integritásának ellenőrzése:
Az első játékban használt hash hashelt értékének közzétételével a játékosok önállóan ellenőrizhetik az összes játék hash-ének integritását a 10 milliomodik játékig.
Ezzel a módszerrel, ha ismered bármely konkrét játék hash-ét, ellenőrizheted az összes korábbi játék seedjét. Például ha ismered a 1323185 játék seedjét, hashelheted ezt a seedet, hogy ellenőrizd, egyezik-e a 1323184 játék seedjével, és így tovább egészen az első játékig.
Például a 1323185 játékban (https://shuffle.com/games/originals/crash?md-id=1323185&modal=crashGame), a hash: 2f824ebb9548a4d24d042ecab390acd1dc931048f696dc03c738937852825ac0
A 1323184 játékban (https://shuffle.com/games/originals/crash?md-id=1323184&modal=crashGame), a hash: 20f42ccc46fed8e005767f85eb4bd5d42d3bd2a72b01ae77dcc7071bec280265
A 1323184 játék hash-e a 1323185 hash-ének SHA256 hash-e. Ennek ellenőrzéséhez használhatsz egy online SHA256 kalkulátort, például a következőt: https://xorbin.com/tools/sha256-hash-calculator .
Átláthatóság és biztonság:
A Shuffle ellenőrzésén kívül eső jövőbeli BTC-blokk hash használatával, valamint az első játék seedjének hashelt változatának közzétételével a felhasználók bizonyíthatják, hogy a Crash játék eredményei tisztességesek voltak, és nem manipulálták őket.
Slide
A Slide ugyanazt a provably fair és seedelési folyamatot használja, mint a Crash. A seedelés nyilvánosan történt a következő oldalon: x.com, a bejegyzés pedig itt.
A 952294 blokk hash-e a BTC-blokkkeresőben található (https://btcscan.org/block/00000000000000000000a382760ff19cdb7f9f22147b9123f3e471fb3c6d129a) és megegyezik a tweetben megjelenített hash-sel.
Baccarat
A Baccarat játékban korlátlan paklit használunk. Ezért minden körben azonosak az esélyek. A Baccarat játékmeneti eseménye a játékos és a bankár kezébe kiosztott lapok meghatározása, a kezdeti osztás és a standard Baccarat húzási szabályok szerinti esetleges további húzások során.
A lapokat a generált lebegőpontos számsorozat alapján a következő sorrendben osztjuk ki:
A játékos első lapja – lebegőpontos szám indexe: 0
A bankár első lapja – lebegőpontos szám indexe: 1
A játékos második lapja – lebegőpontos szám indexe: 2
A bankár második lapja – lebegőpontos szám indexe: 3
A játékos harmadik lapja (ha húz) – lebegőpontos szám indexe: 4
A bankár harmadik lapja (ha húz)
lebegőpontos szám indexe: 4 – ha a játékos nem húzott harmadik lapot
lebegőpontos szám indexe: 5 – ha a játékos harmadik lapot húz
// Generate a float between 0 and 1
// Example: floats = [0.40353962965495884, 0.6645898742135614, 0.17454026662744582, 0.5729992990382016, 0.850033157505095] (an unlimited number of cards can be drawn but only 5 are shown here for brevity)
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor, count:52 });
const CARDS = [
♠2, ♥2, ♦2, ♣2, ♠3, ♥3, ♦3, ♣3, ♠4, ♥4,
♦4, ♣4, ♠5, ♥5, ♦5, ♣5, ♠6, ♥6, ♦6, ♣6,
♠7, ♥7, ♦7, ♣7, ♠8, ♥8, ♦8, ♣8, ♠9, ♥9,
♦9, ♣9, ♠10, ♥10, ♦10, ♣10, ♠J, ♥J, ♦J,
♣J, ♠Q, ♥Q, ♦Q, ♣Q, ♠K, ♥K, ♦K, ♣K, ♠A,
♥A, ♦A, ♣A
];
// Get an integer 0 to 51, representing the index of the cards
// Example: cardFloats = [22, 34, 9, 29, 44]
const cardFloats = floats.map(val => Math.floor(val * 52));
// Example: cards = [♠7, ♠10, ♥4, ♠9, ♦K]
const cards = cardFloats.map(val => CARDS[val])
return cards;
Blitz
A Blitz játékban korlátlan paklit használunk. Ezért minden körben azonosak az esélyek. A Blitz játékmeneti eseménye a játékosnak a kiválasztott húzásszám alapján kiosztott lapok meghatározása, valamint annak értékelése, hogy az összes kihúzott lap egyedi-e.
// Generate a float between 0 and 1
// Example: floats = [0.43053962965495884, 0.6645898742135614, 0.17454026662744582, 0.5729992990382016, 0.850033157505095] (an unlimited number of cards can be drawn but only 5 are shown here for brevity)
const floats = generateFloats({serverSeed, clientSeed, nonce, cursor, count:52 });
const CARDS = [
♠2, ♥2, ♣2, ♦2, ♠3, ♥3, ♣3, ♦3, ♠4, ♥4,
♣4, ♦4, ♠5, ♥5, ♣5, ♦5, ♠6, ♥6, ♣6, ♦6,
♠7, ♥7, ♣7, ♦7, ♠8, ♥8, ♣8, ♦8, ♠9, ♥9,
♣9, ♦9, ♠10, ♥10, ♣10, ♦10, ♠J, ♥J, ♣J, ♦J,
♠Q, ♥Q, ♣Q, ♦Q, ♠K, ♥K, ♣K, ♦K, ♠A,
♥A, ♣A, ♦A
];
// Get an integer 0 to 51, representing the index of the cards
// Example: cardFloats = [22, 34, 9, 29, 44]
const cardFloats = floats.map(val => Math.floor(val * 52));
// Example: cards = [♠7, ♠10, ♥4, ♠9, ♦K]
const cards = cardFloats.map(val => CARDS[val])
return cards;
Coinflip
A Coinflip célja, hogy helyesen tippeld meg, melyik oldalára esik az feldobott érme. A Coinflip játékmeneti eseménye minden érmedobás eredményének (FEJ vagy ÍRÁS) meghatározása. A Coinflipnek három módja van: Classic (egyetlen dobás), Classic Progressive (ismételt dobás, bármikori kifizetési lehetőséggel) és Target (válassz egy dobásszámot és a nyeréshez szükséges helyes tippek minimális számát) –, de mindhárom ugyanúgy határozza meg a dobások eredményét.
Minden dobás egy lebegőpontos szám generálásával, majd annak 0 vagy 1 értékhez rendelésével történik, pontosan úgy, ahogy a Plinko a lebegőpontos számokat balra/jobbra esésekhez rendeli:
// Generate floats to determine each flip outcome
// Example: floats = [0.43053962965495884, 0.6645898742135614, ...] when clientSeed='abc', serverSeed='def', nonce=1
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count });
// Each float maps to 0 or 1, which maps to HEADS or TAILS
// Example: [0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1]
const flipValues = floats.map(val => Math.floor(val * 2));
const flipResults = flipValues.map(val => (val === 0 ? 'HEADS' : 'TAILS'));
// Example: [HEADS, TAILS, HEADS, TAILS, TAILS, HEADS, TAILS, HEADS, TAILS, HEADS,
// TAILS, HEADS, TAILS, HEADS, HEADS, TAILS, HEADS, HEADS, HEADS, TAILS]
return flipResults;
Classic – egy dobás generálódik (count = 1). A játékos akkor nyer, ha a kiválasztott oldala megegyezik a dobás eredményével.
Classic Progressive – a dobások egyenként generálódnak, ahogy a játékos folytatja, de minden dobás eredménye már a kör kezdetétől rögzített: az N-edik dobás mindig az 1–N dobások generálásával és az utolsó kiválasztásával származik. Így a dobások egyenkénti felfedése a játékos előrehaladtával nem változtatja meg egyik dobás eredményét sem. A játékos minden sikeres dobás után kifizethet; a kör az első hibás tippnél véget ér.
Target – a játékos kiválasztja a dobások teljes számát (legfeljebb 20) és a nyeréshez szükséges helyes tippek minimális számát. Az összes dobás egyetlen kötegben generálódik (count = totalFlips), és a kör akkor nyertes, ha a játékos tippjével egyező dobások száma legalább a kiválasztott minimum.
Floor is Lava
Cél: Kelj át egy 7×7 méretű rácson (49 mező) három egymást követő szinten anélkül, hogy olyan mezőre lépnél, amely lávává változik.
Minden szint rögzített méretű „körökből” áll – minden körben egyszerre több mező válik lávává –, és bármely kör túlélése után kifizethetsz.
Tábla generálása
A kör kezdete előtt mindhárom szint mezőelrendezése egyetlen bizonyíthatóan tisztességes shuffle során kerül kisorsolásra: a seedelt generátor visszatevés nélkül kiválasztja a 0..146 egész számok (49 mező × 3 szint) véletlen permutációját, majd szintekre bontja:
// Draw a random permutation of 0..146 without replacement
// Example: raw = [103, 12, 140, 76, 3, ...]
const boards = [[], [], []];
for (const value of raw) {
boards[Math.floor(value / 49)].push(value % 49); // bucket = level, residue = tile index }
// boards[0], boards[1], boards[2] are each a uniformly random ordering of tiles 0..48
Egy 147-értékű permutáció kisorsolása három különálló 49-értékű shuffle helyett csupán hatékonysági megoldás – mivel a 147 érték közül pontosan 49 esik az egyes szintek tartományába, minden szint továbbra is a saját 49 mezőjének független, egyenletesen véletlenszerű sorrendjét kapja.
Körök: hogyan terjed a láva
Minden szint 49 mezőből álló sorrendje egymást követő, egymást nem átfedő részekre van osztva: körönként rögzített számú mező (dropsPerRound), rögzített számú körön keresztül (roundsPerLevel), a végén fennmaradó mezők pedig az egész szintet túlélő mezők:
tilesDroppedInRound(level, dropsPerRound, roundIndex) = levelBoard.slice(roundIndex * dropsPerRound, (roundIndex + 1) * dropsPerRound)
tilesThatSurviveLevel(level, survivingCount) = levelBoard.slice(-survivingCount)
Mivel a shuffle már előre rögzítette a mezők sorrendjét, a kör lávamezői nem a választásodra reagálva kerülnek kiválasztásra – hanem az előre-shuffled lista adott körben esedékes része.
Minden választáskor kijelölsz egy mezőt (selectedTile). Ez a mező nem tartozhat egy korábbi kör lávacsoportjához ezen a szinten. A kör ezután úgy értékelődik ki, hogy az általad kiválasztott egyetlen mezőt a kör teljes lávacsoportjával hasonlítjuk össze (selectedTile):
isLoss = droppedTiles.includes(selectedTile)
Ha a meződ a körben lávává váló mezők egyike, a játék véget ér. Ellenkező esetben túlélted a kört – függetlenül attól, hány másik mező vált még lávává vele együtt.
Nehézség beállítása
A négy nehézségi szint a kör mérete és a körök száma között teremt egyensúlyt. Mindegyik a teljes 49 mezős táblát adja ki (dropsPerRound × roundsPerLevel + survivingTiles = 49):
Nehézség | Lávává váló mezők körönként | Körök szintenként | Túlélő mezők |
Könnyű | 7 | 6 | 7 |
Közepes | 11 | 4 | 5 |
Nehéz | 23 | 2 | 3 |
Mérgező | 48 | 1 | 1 |
Szint- és játékelőrehaladás
Egy játék 3 szintből áll, amelyek mindegyike saját, egymástól függetlenül shuffled 49 mezős táblával rendelkezik. Ha egy szinten minden kört túlélsz, teljesíted azt, és a következő szint táblájának első körére lépsz; a harmadik szint teljesítésével befejezed a játékot.
Kifizetés
Bármely kör túlélése után kifizethetsz – már az első sikeres választásod is feloldja ezt a lehetőséget.
Szorzó
multiplier = edgeMultiplier * 49^(levelsCleared+1) / (tilesRemainingInLevel * survivingTiles^levelsCleared)
levelsCleared az eddig teljesen teljesített szintek száma, tilesRemainingInLevel az aktuális szinten túlélhető körönként a körben lávává váló mezők számával csökken, és survivingTiles a fenti táblázatban szereplő, nehézségi szintenkénti túlélő mezők száma.
Ez tisztességes esélyeken alapuló árképzés: az adott pont elérésének halmozott valószínűsége (teljesített szintek × túlélt körök) reciprokának felel meg egyenletesen véletlenszerű mezőelhelyezés mellett, a házelőnnyel korrigálva.


