Šta su događaji u igri
Prethodno smo generisali nasumične float vrednosti između 0 i 1 koristeći funkcije generateFloats i byteGenerator. Događaji u igri prevode ove generisane float vrednosti u stvarne ishode igre. To se odvija na različite načine u različitim igrama. U igri Plinko, float vrednosti pomažu u određivanju smera pada loptice. U igri Dice, float vrednosti pomažu u određivanju ishoda bacanja kockice.
U nastavku se nalazi detaljno objašnjenje kako float vrednosti prevodimo u fer događaje ili ishode za svaku originalnu igru na našoj platformi.
Tower
U igri Tower, cilj je doći do vrha kule i spasiti princezu pronalaženjem ključeva i izbegavanjem otrovnih jabuka. Svaki red kule sadrži unapred definisan broj bezbednih polja (ključeva) i otrovnih jabuka, u zavisnosti od izabrane težine.
Događaj u igri Tower određuje položaj bezbednih polja (odnosno ključeva) u svakom redu.
Kula ima ukupno 9 redova. Broj kolona i raspodela ključeva i otrovnih jabuka razlikuju se u zavisnosti od izabrane težine:
Lako: 4 kolona - 3 ključa i 1 otrovna jabuka po redu
Srednje: 3 kolona - 2 ključa i 1 otrovna jabuka po redu
Teško: 2 kolona - 1 ključ i 1 otrovna jabuka po redu
Ekspert: 3 kolona: - 1 ključ i 2 otrovne jabuke po redu
Master: 4 kolona - 1 ključ i 3 otrovne jabuke po redu
Ishod za svaki red određuje se generisanjem nasumičnih pozicija ključeva (bezbednih polja) unutar dostupnih kolona, na osnovu konfiguracije težine.
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
U igri Chicken, cilj je pomeriti kokošku preko što više traka bez sletanja na opasnu traku.
Svaki uspešan korak napred povećava množilac isplate. Igrač može izvršiti cashout u bilo kom trenutku pre nego što kokoška skoči na opasnu traku. Ako kokoška stigne do opasne zone pre nego što igrač izvrši cashout, opklada je izgubljena.
Glavni događaj u igri Chicken je određivanje opasne trake – konkretne trake na kojoj će kokoška izgubiti.
U igri Chicken postoje 4 težine. Broj traka koje kokoška može preći razlikuje se u zavisnosti od izabrane težine:
Lako: 19 traka
Srednje: 17 traka
Teško: 15 traka
Ekspert: 10 traka
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
U igri Plinko igrači mogu izabrati piramidu visine od 8 do 16. Kada se loptica pusti sa vrha, padaće levo ili desno 8 do 16 puta, svaki put kada pogodi klin na Plinko tabli. Događaj u igri Plinko određuje da li loptica pada levo ili desno na svakom nivou, što predstavljaju 0 i 1.
// 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
U igri Dice, bacanje kockice može imati vrednost između 0.00 i 100.00. Događaj u igri Dice određuje ovu vrednost. To radimo koristeći (floats * 10,001) / 100). Kako uključujemo vrednosti do 2 decimalnih mesta i broj 0, postoji ukupno 10,000 + 1 = 10,001 mogućih ishoda (uključujući decimalna mesta).
// 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
U igri Limbo, cilj je pogoditi množilac >1. Ako je rezultat igre veći od množioca, korisnik pobeđuje u igri. Događaj u igri je generisanje float vrednosti koja je iznad 1 i prati distribuciju hiperboličke krive.
// 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
U igri Keno, događaj u igri zahteva identifikaciju 10 jedinstvenih pozicija dragulja na keno tabli. Da bismo to postigli, generišemo 10 različitih float vrednosti između 1 i 40., koje predstavljaju svaku poziciju na keno tabli. Zatim se koristi mehanizam za obradu dupliranih float vrednosti i vraćanje konačnih 10 lokacija dragulja
// 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
U igri Mines, događaj u igri zahteva određivanje pozicija mina na Mines tabli sa 25 polja. Na osnovu izbora korisnika o broju mina, generišemo listu celih brojeva od 0 do 24 koji predstavljaju 25 polja na tabli.
// 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;
Roulette
Naš Roulette se zasniva na evropskom točku sa jednim „0“, koji ima 37 različitih polja u rasponu od 0 do 36. Događaj u igri Roulette je izračunavanje polja među 37 polja na kojem će se loptica zaustaviti.
// 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
U igri Wheel, korisnik bira broj segmenata na točku. U zavisnosti od segmenta na kojem se pokazivač zaustavi, korisnik osvaja množilac tog segmenta. Događaj u igri određuje segment.
// 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
U igri Blackjack koristi se neograničen špil karata. Stoga svaki potez uvek ima istu verovatnoću. Događaj u igri Blackjack određuje kartu koja se izvlači kada igrač ili bankar izvuče kartu iz špila.
// 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
U igri Hilo koristi se neograničen špil karata. Stoga svaki potez uvek ima istu verovatnoću. Cilj igre je pogoditi da li će sledeća karta imati veću ili manju vrednost od trenutne karte. Događaj u igri Hilo određuje koju kartu korisnik sledeću izvlači (ako je izvuč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;
Crash
Postoje 2 dela u izračunavanju rezultata igre Crash
Bitcoin hash bloka
Seed
Bitcoin hash
Detalji se nalaze u ovom tvitu:
Hash bloka 779588 može se pronaći u BTC block exploreru (https://btcscan.org/block/000000000000000000033ab71b5fa7edcafe388e5f49719f1de8e1f8d0670460) i podudara se sa hashom prikazanim u tvitu.
Seed
Proces generisanja seedova za 10 miliona Crash igara osmišljen je da osigura pravičnost i transparentnost, sprečavajući bilo kakvu mogućnost manipulacije od strane Shuffle. Evo kako se seedovi generišu i verifikuju:
Početno generisanje seeda: Seed za 10 milionitu igru nasumično bira Shuffle.
Sekvencijalno heširanje za generisanje seedova: Za generisanje seedova za sve ostale igre koristimo metod obrnutog heširanja:
Seed za svaku igru rezultat je heširanja seeda naredne igre. Konkretno, hash za 9,999,999. igru je SHA256 hash hasha 10 milionite igre.
Ovo ulančavanje se nastavlja tako da seed svake igre nastaje heširanjem hasha naredne igre, pri čemu seed prve igre nastaje iz hasha druge igre.
Verifikacija integriteta seeda:
Objavljivanjem heširane vrednosti hasha korišćenog u prvoj igri, igrači mogu nezavisno da verifikuju integritet hasha za sve igre do 10 milionite igre.
Ovom metodom, ako znate hash za bilo koju konkretnu igru, možete verifikovati seedove za sve prethodne igre. Na primer, ako znate seed igre 1323185, možete heširati taj seed kako biste proverili da li odgovara seedu igre 1323184, i tako redom, sve do prve igre.
Na primer, u igri 1323185 (https://shuffle.com/games/originals/crash?md-id=1323185&modal=crashGame), hash je 2f824ebb9548a4d24d042ecab390acd1dc931048f696dc03c738937852825ac0
U igri 1323184 (https://shuffle.com/games/originals/crash?md-id=1323184&modal=crashGame), hash je 20f42ccc46fed8e005767f85eb4bd5d42d3bd2a72b01ae77dcc7071bec280265
Hash igre 1323184 je SHA256 hash hasha igre 1323185. Možete koristiti online SHA256 kalkulator kao što je https://xorbin.com/tools/sha256-hash-calculator da biste to verifikovali
Transparentnost i bezbednost:
Korišćenjem budućeg BTC hash-a bloka, koji nije pod kontrolom Shuffle, i objavljivanjem heširane verzije seeda prve igre, korisnici mogu dokazati da su rezultati Crash igre fer i da nisu menjani.
Slide
Slide koristi isti provably fair i proces generisanja seedova kao Crash. Generisanje seedova je javno obavljeno na x.com, a objavu možete pronaći ovde.
Hash bloka 952294 može se pronaći u BTC block exploreru (https://btcscan.org/block/00000000000000000000a382760ff19cdb7f9f22147b9123f3e471fb3c6d129a) i podudara se sa hashom prikazanim u tvitu.
Baccarat
U igri Baccarat koristi se neograničen špil karata. Stoga svaki potez uvek ima istu verovatnoću. Događaj u igri Baccarat određuje karte koje se dele rukama Igrača i Bankara tokom početnog deljenja i svih dodatnih izvlačenja, u skladu sa standardnim pravilima izvlačenja u igri Baccarat.
Karte se dele sledećim redosledom iz generisanog niza float vrednosti:
Prva karta Igrača - indeks float vrednosti 0
Prva karta Bankara - indeks float vrednosti 1
Druga karta Igrača - indeks float vrednosti 2
Druga karta Bankara - indeks float vrednosti 3
Treća karta Igrača (ako se izvuče) - indeks float vrednosti 4
Treća karta Bankara (ako se izvuče)
indeks float vrednosti 4 - ako igrač nije izvukao treću kartu
indeks float vrednosti 5 - ako igrač izvuče treću kartu
// 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
U igri Blitz koristi se neograničen špil karata. Stoga svaki potez uvek ima istu verovatnoću. Događaj u igri Blitz određuje karte koje se dele igraču prema izabranom broju izvlačenja i procenjuje da li su sve izvučene karte jedinstvene.
// 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
U igri Coinflip, cilj je pravilno pogoditi na koju će stranu bačeni novčić pasti. Događaj u igri Coinflip određuje ishod (GLAVA ili PISMO) svakog bacanja novčića. Coinflip ima tri režima — Classic (jedno bacanje), Classic Progressive (ponavljano bacanje i cashout u bilo kom trenutku) i Target (izaberite broj bacanja i minimalni broj tačnih pogodaka potreban za pobedu) — ali sva tri režima ishode bacanja određuju na isti način.
Svako bacanje određuje se generisanjem float vrednosti i njenim mapiranjem na 0 ili 1, baš kao što Plinko mapira svoje float vrednosti na padove levo/desno:
// 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 — generiše se jedno bacanje (count = 1). Igrač pobeđuje ako se njegova izabrana strana podudara sa ishodom bacanja.
Classic Progressive — bacanja se generišu jedno po jedno dok igrač nastavlja, ali ishod svakog bacanja je fiksiran od početka runde: N-to bacanje se uvek dobija generisanjem bacanja od 1 do N i uzimanjem poslednjeg, tako da otkrivanje bacanja jednog po jednog dok igrač napreduje ne menja ishod nijednog konkretnog bacanja. Igrač može izvršiti cashout nakon svakog uspešnog bacanja; runda se završava pri prvom promašaju.
Target — igrač bira ukupan broj bacanja (do 20) i minimalni broj tačnih pogodaka potreban za pobedu. Sva bacanja se generišu kao jedna serija (count = totalFlips), a runda je dobijena ako je broj bacanja koja odgovaraju igračevom izboru najmanje jednak izabranom minimumu.
Floor is Lava
Cilj: Pređite mrežu dimenzija 7×7 (49 polja) kroz tri uzastopna nivoa bez stajanja na polje koje se pretvara u lavu.
Svaki nivo se odvija u rundama fiksne veličine — grupa polja se zajedno pretvara u lavu u svakoj rundi — a cashout možete izvršiti nakon što preživite bilo koju rundu.
Generisanje table
Pre početka runde, raspored polja za sva tri nivoa izvlači se u jednoj Provably Fair shuffle: nasumična permutacija celih brojeva 0..146 (49 polja × 3 nivoa) izvlači se bez ponavljanja iz generatora zasnovanog na seedu, a zatim se deli po nivoima:
// 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
Izvlačenje jedne 147-vrednosne permutacije umesto tri odvojene 49-vrednosne shuffle je samo trik za efikasnost — pošto tačno 49 od 147 vrednosti pripada opsegu svakog nivoa, svaki nivo i dalje dobija nezavisan, ravnomerno nasumičan redosled svojih 49 polja.
Runde: kako se lava spušta
Redosled od 49 polja na svakom nivou deli se na uzastopne delove koji se ne preklapaju: fiksan broj polja po rundi (dropsPerRound), za fiksan broj rundi (roundsPerLevel), pri čemu su preostala polja na kraju ona koja prežive ceo nivo:
tilesDroppedInRound(level, dropsPerRound, roundIndex) = levelBoard.slice(roundIndex * dropsPerRound, (roundIndex + 1) * dropsPerRound)
tilesThatSurviveLevel(level, survivingCount) = levelBoard.slice(-survivingCount)
Pošto je shuffle unapred fiksirao redosled polja, skup polja koja postaju lava u rundi ne bira se kao reakcija na vaš izbor — to je onaj deo prethodno-shuffled liste koji je „na redu“ u toj rundi.
Pri svakom izboru, birate jedno polje (selectedTile). To polje ne sme već pripadati grupi lave iz prethodne runde na ovom nivou. Runda se zatim rešava poređenjem vašeg jednog polja sa celom grupom lave u rundi (selectedTile):
isLoss = droppedTiles.includes(selectedTile)
Ako je vaše polje jedno od polja koja se spuštaju u ovoj rundi, igra se završava. U suprotnom, preživeli ste rundu — bez obzira na to koliko je drugih polja palo zajedno s njim.
Težina konfiguracija
Četiri težine prave odnos između veličine runde i broja rundi. Svaka i dalje obuhvata celu tablu od 49 polja (dropsPerRound × roundsPerLevel + survivingTiles = 49):
Težina | Padanja po rundi | Rundi po nivou | Preživela polja |
Lako | 7 | 6 | 7 |
Srednje | 11 | 4 | 5 |
Teško | 23 | 2 | 3 |
Toksično | 48 | 1 | 1 |
Napredovanje kroz nivoe i igru
Igra ima 3 nivoa, svaki sa sopstvenom nezavisno-shuffled tablom od 49 polja. Preživljavanjem svih rundi na nivou završavate ga i prelazite na tablu sledećeg nivoa, počevši od prve runde; završavanjem trećeg nivoa završavate igru.
Cashout
Cashout možete izvršiti nakon što preživite bilo koju rundu — već vaš prvi uspešan izbor ga otključava.
Množilac
multiplier = edgeMultiplier * 49^(levelsCleared+1) / (tilesRemainingInLevel * survivingTiles^levelsCleared)
levelsCleared je broj do sada potpuno završenih nivoa, tilesRemainingInLevel smanjuje se za broj polja koja padaju u rundi svaki put kada preživite rundu na trenutnom nivou, i survivingTiles je broj preživelih po nivou za izabranu težinu iz gornje tabele.
Ovo je cena sa fer kvotama: inverzna vrednost kumulativne verovatnoće dostizanja te tačne tačke (završeni nivoi × preživljene runde) uz ravnomerno nasumičan raspored polja, prilagođena prednosti kuće.


