Oyun etkinlikleri nedir?
Daha önce, generateFloats ve byteGenerator işlevlerini kullanarak 0 ile 1 arasında rastgele kayan noktalı sayılar oluşturduk. Oyun etkinlikleri, oluşturulan bu kayan noktalı sayıları gerçek oyun sonuçlarına dönüştürür. Bu, farklı oyunlar için farklı şekillerde gerçekleşir. Plinko'da kayan noktalı sayılar, topun düşüş yönünü belirlemeye yardımcı olur. Dice'ta kayan noktalı sayılar, zar atışının sonucunu belirlemeye yardımcı olur.
Aşağıda, kayan noktalı sayıları platformumuzdaki her özgün oyun için adil etkinliklere veya sonuçlara nasıl dönüştürdüğümüzün ayrıntılı bir açıklaması yer almaktadır.
Tower
Tower'da oyunun amacı, anahtarları bularak ve zehirli elmalardan kaçınarak kulenin tepesine ulaşmak ve prensesi kurtarmaktır. Kulenin her sırasında, seçilen zorluğa bağlı olarak önceden tanımlanmış sayıda güvenli karo (anahtar) ve zehirli elma bulunur.
Tower'daki oyun etkinliği, her sıradaki güvenli karoların (veya anahtarların) konumunu belirlemektir.
Kulede toplam 9 sıra vardır. Sütun sayısı ile anahtarların ve zehirli elmaların dağılımı, seçilen zorluğa göre değişir:
Kolay: 4 sütun - sıra başına 3 anahtar ve 1 zehirli elma
Orta: 3 sütun - sıra başına 2 anahtar ve 1 zehirli elma
Zor: 2 sütun - sıra başına 1 anahtar ve 1 zehirli elma
Uzman: 3 sütun: - sıra başına 1 anahtar ve 2 zehirli elma
Usta: 4 sütun - sıra başına 1 anahtar ve 3 zehirli elma
Her sıranın sonucu, zorluk yapılandırmasına göre mevcut sütunlar içinde anahtarların (güvenli karoların) rastgele konumlarının oluşturulmasıyla belirlenir.
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
Chicken'da amaç, tehlike şeridine inmeden tavuğu mümkün olduğunca çok şeritten geçirmektir.
Her başarılı ileri adım, ödeme çarpanını artırır. Oyuncu, tavuk tehlike şeridine atlamadan önce istediği zaman nakde çevirebilir. Oyuncu nakde çevirmeden önce tavuk tehlike bölgesine ulaşırsa bahis kaybedilir.
Chicken'daki temel oyun etkinliği, tehlike şeridinin, yani tavuğun kaybedeceği belirli şeridin belirlenmesidir.
Chicken'da 4 zorluk seviyesi vardır. Tavuğun geçebileceği şerit sayısı, seçilen zorluğa bağlı olarak değişir:
Kolay: 19 Şerit
Orta: 17 Şerit
Zor: 15 Şerit
Uzman: 10 Şerit
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
Plinko'da oyuncular 8 ile 16 yüksekliğinde bir piramit arasından seçim yapabilir. Top üstten bırakıldığında, Plinko tahtasındaki bir pime her çarptığında 8 ila 16 kez sola veya sağa düşer. Plinko'daki oyun etkinliği, topun her seviyede sola mı yoksa sağa mı düştüğünü 0 ve 1 ile temsil edildiği şekilde belirlemektir.
// 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
Dice'ta bir zar atışı 0.00 ile 100.00 arasındaki değerlerde olabilir. Dice'taki oyun etkinliği bu değeri belirlemektir. Bunu (floats * 10,001) / 100) kullanarak yaparız. 2 ondalık basamağa kadar olan değerleri ve 0 sayısını dahil ettiğimiz için, toplam 10,000 + 1 = 10,001 olası sonuç (ondalık basamaklar dahil) vardır.
// 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
Limbo'da oyunun amacı bir çarpanı tahmin etmektir >1. Oyun sonucu çarpandan büyükse kullanıcı oyunu kazanır. Oyun etkinliği, 1 üzerinde olan ve hiperbolik eğri dağılımını izleyen bir kayan noktalı değer oluşturmaktır.
// 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
Keno'da oyun etkinliği, keno tahtasındaki 10 benzersiz mücevher konumunun belirlenmesini gerektirir. Bunu gerçekleştirmek için, keno tahtasındaki her konumu temsil eden 1 ile 40 arasında 10 farklı kayan noktalı sayı oluştururuz. Ardından, yinelenen kayan noktalı sayıları işlemek ve nihai 10 mücevher konumunu döndürmek için bir kullanılır.
// 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
Mines'ta oyun etkinliği, 25 karodan oluşan mayın tahtasındaki mayınların konumlarının belirlenmesini gerektirir. Kullanıcının seçtiği mayın sayısına göre, tahtadaki 25 alanı temsil etmek için 0 ile 24 arasında bir tam sayı listesi oluştururuz.
// 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
Roulette oyunumuz, 0 ile 36 arasında değişen 37 farklı cebe sahip Avrupa tarzı tek ‘0’ çarkına dayanır. Roulette'taki oyun etkinliği, topun ineceği 37 cepten ilgili cebi hesaplamaktır.
// 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
Wheel'de kullanıcı, çarkın sahip olacağı segment sayısını seçer. İşaretçi hangi segmentte durursa kullanıcı o segmentteki çarpanı kazanır. Oyun etkinliği segmenti belirlemektir.
// 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
Blackjack'te oyun sınırsız bir kart destesiyle oynanır. Bu nedenle her tur her zaman aynı olasılığa sahiptir. Blackjack'taki oyun etkinliği, oyuncu veya banker desteden bir kart çektiğinde çekilen kartı belirlemektir.
// 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
Hilo'da oyun sınırsız bir kart destesiyle oynanır. Bu nedenle her tur her zaman aynı olasılığa sahiptir. Oyunun amacı, bir sonraki kartın mevcut karttan daha yüksek veya daha düşük değerde olup olmadığını tahmin etmektir. Hilo'daki oyun etkinliği, kullanıcının bir sonraki çekeceği kartı (çekilirse) belirlemektir.
// 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
Bir crash oyununun sonucunun hesaplanmasında 2 bölüm vardır
Bitcoin blok hash'i
Seed
Bitcoin Hash
Ayrıntılar bu tweette yer alıyor:
779588 numaralı bloğun hash'i BTC blok gezgininde bulunabilir (https://btcscan.org/block/000000000000000000033ab71b5fa7edcafe388e5f49719f1de8e1f8d0670460), ve tweette gösterilen hash ile eşleşir.
Seed
10 milyon crash oyunu için seed oluşturma süreci, adaleti ve şeffaflığı sağlamanın yanı sıra Shuffle tarafından herhangi bir manipülasyon olasılığını önleyecek şekilde tasarlanmıştır. Seed'lerin nasıl oluşturulduğu ve doğrulandığı aşağıda açıklanmıştır:
İlk Seed Oluşturma: 10 milyonuncu oyunun seed'i Shuffle tarafından rastgele seçilir.
Seed Oluşturmak için Sıralı Hashleme: Diğer tüm oyunların seed'lerini oluşturmak için geriye doğru hashleme yöntemi kullanırız:
Her oyunun seed'i, sonraki oyunun seed'inin hashlenmesi sonucunda elde edilir. Özellikle, 9,999,999inci oyunun hash'i, 10 milyonuncu oyunun hash'inin SHA256 hash'idir.
Bu zincirleme işlem, her oyunun seed'i sonraki oyunun hash'inin hashlenmesinden türetilerek devam eder ve ilk oyunun seed'inin ikinci oyunun hash'inden türetilmesiyle sonuçlanır.
Seed Bütünlüğünün Doğrulanması:
İlk oyunda kullanılan hash'in hashlenmiş değeri yayınlanarak oyuncular, 10 milyonuncu oyuna kadar tüm oyunların hash bütünlüğünü bağımsız olarak doğrulayabilir.
Bu yöntemi kullanarak, belirli bir oyunun hash'ini biliyorsanız önceki tüm oyunların seed'lerini doğrulayabilirsiniz. Örneğin, 1323185 numaralı oyunun seed'ini biliyorsanız, bu seed'i hashleyerek 1323184 numaralı oyunun seed'iyle eşleştiğini doğrulayabilir ve bu şekilde ilk oyuna kadar devam edebilirsiniz.
Örneğin, 1323185 numaralı oyunda (https://shuffle.com/games/originals/crash?md-id=1323185&modal=crashGame), hash 2f824ebb9548a4d24d042ecab390acd1dc931048f696dc03c738937852825ac0 şeklindedir
1323184 numaralı oyunda (https://shuffle.com/games/originals/crash?md-id=1323184&modal=crashGame), hash 20f42ccc46fed8e005767f85eb4bd5d42d3bd2a72b01ae77dcc7071bec280265 şeklindedir
1323184 numaralı oyunun hash'i, 1323185 hash'inin SHA256 hash'idir. Bunu doğrulamak için aşağıdaki gibi çevrimiçi bir SHA256 hesaplayıcısı kullanabilirsiniz: https://xorbin.com/tools/sha256-hash-calculator bunu doğrulamak için
Şeffaflık ve Güvenlik:
Shuffle kontrolü dışında olan gelecekteki bir BTC blok hash'i kullanılarak ve ilk oyunun seed'inin hashlenmiş sürümü yayınlanarak, kullanıcılar crash oyunu sonuçlarının adil olduğunu ve üzerinde oynanmadığını kanıtlayabilir.
Slide
Slide, Crash ile aynı provably fair ve seed oluşturma sürecini kullanır. Seed oluşturma işlemi herkese açık olarak şu platformda yapıldı: x.com, ve gönderiye buradan.
952294 numaralı bloğun hash'i BTC blok gezgininde bulunabilir (https://btcscan.org/block/00000000000000000000a382760ff19cdb7f9f22147b9123f3e471fb3c6d129a) ve tweette gösterilen hash ile eşleşir.
Baccarat
Baccarat'ta oyun sınırsız bir kart destesiyle oynanır. Bu nedenle her tur her zaman aynı olasılığa sahiptir. Baccarat'taki oyun etkinliği, standart Baccarat kart çekme kurallarını izleyen ilk dağıtım ve ek çekilişler boyunca hem Oyuncu hem de Banker ellerine dağıtılan kartları belirlemektir.
Kartlar, oluşturulan kayan noktalı sayı dizisinden aşağıdaki sırayla dağıtılır:
Oyuncunun ilk kartı - kayan noktalı sayı indeksi 0
Banker'ın ilk kartı - kayan noktalı sayı indeksi 1
Oyuncunun ikinci kartı - kayan noktalı sayı indeksi 2
Banker'ın ikinci kartı - kayan noktalı sayı indeksi 3
Oyuncunun üçüncü kartı (çekilirse) - kayan noktalı sayı indeksi 4
Banker'ın üçüncü kartı (çekilirse)
kayan noktalı sayı indeksi 4 - oyuncu üçüncü kartı çekmezse
kayan noktalı sayı indeksi 5 - oyuncu üçüncü kartı çekerse
// 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
Blitz'te oyun sınırsız bir kart destesiyle oynanır. Bu nedenle her tur her zaman aynı olasılığa sahiptir. Blitz'teki oyun etkinliği, oyuncuya seçtiği çekiliş sayısı boyunca dağıtılan kartları belirlemek ve çekilen tüm kartların benzersiz olup olmadığını değerlendirmektir.
// 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
Coinflip'te amaç, çevrilen paranın hangi yüzüne düştüğünü doğru tahmin etmektir. Coinflip'teki oyun etkinliği, her para atışının sonucunu (YAZI veya TURA) belirlemektir. Coinflip'in üç modu vardır — Classic (tek atış), Classic Progressive (tekrar tekrar atın ve istediğiniz noktada nakde çevirin) ve Target (kazanmak için gerekli atış sayısını ve minimum doğru tahmin sayısını seçin) — ancak üçünün de atış sonuçları aynı şekilde türetilir.
Her atış, bir kayan noktalı sayı oluşturulup Plinko'nun kayan noktalı sayılarını sol/sağ düşüşlere eşlemesi gibi tam olarak 0 veya 1 ile eşleştirilerek belirlenir:
// 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 — bir atış oluşturulur (count = 1). Oyuncu, seçtiği taraf atışla eşleşirse kazanır.
Classic Progressive — oyuncu devam ettikçe atışlar birer birer oluşturulur, ancak her atışın sonucu turun başlangıcından itibaren sabittir: N'inci atış her zaman 1 ile N arasındaki atışlar oluşturulup sonuncusu alınarak türetilir; dolayısıyla oyuncu ilerlerken atışların tek tek açıklanması, herhangi bir atışın sonucunu değiştirmez. Oyuncu her başarılı atıştan sonra nakde çevirebilir; tur ilk başarısız tahminde sona erer.
Target — oyuncu toplam atış sayısını (en fazla 20) ve kazanmak için gereken minimum doğru tahmin sayısını seçer. Tüm atışlar tek bir toplu işlem olarak oluşturulur (count = totalFlips) ve oyuncunun tahminiyle eşleşen atış sayısı seçilen minimuma en az eşitse tur kazanılır.
Floor is Lava
Amaç: Lav haline dönüşen bir karoya basmadan, art arda üç seviye boyunca 7×7 boyutunda bir ızgarayı (49 karo) geçin.
Her seviye sabit boyutlu "turlarda" oynanır — her turda bir grup karo birlikte lava düşer — ve herhangi bir turu atlattıktan sonra nakde çevirebilirsiniz.
Tahta oluşturma
Tur başlamadan önce, üç seviyenin tamamının karo düzeni tek bir provably-fair shuffle içinde çekilir: seed'li oluşturucudan 0..146 (49 karo × 3 seviye) tam sayılarının rastgele bir permütasyonu geri koymadan çekilir, ardından seviyelere göre ayrılır:
// 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
Üç ayrı 49 değerli shuffle yerine tek bir 147 değerli permütasyon çekmek yalnızca bir verimlilik yöntemidir — 147 değerin tam olarak 49 tanesi her seviyenin aralığına düştüğü için, her seviye yine kendi 49 karosunun bağımsız ve eşit olasılıklı rastgele sıralamasına sahip olur.
Turlar: lav nasıl düşer
Her seviyenin 49 karoluk sıralaması, ardışık ve çakışmayan parçalara bölünür: tur başına sabit sayıda karo (dropsPerRound), sabit sayıda tur için (roundsPerLevel), sonunda kalan karolar ise tüm seviyeyi atlatan karolardır:
tilesDroppedInRound(level, dropsPerRound, roundIndex) = levelBoard.slice(roundIndex * dropsPerRound, (roundIndex + 1) * dropsPerRound)
tilesThatSurviveLevel(level, survivingCount) = levelBoard.slice(-survivingCount)
shuffle karo sırasını en baştan belirlediği için, turun lav kümesi seçiminize tepki olarak seçilmez — önceden shuffle olan listenin bu turda "sırası gelen" dilimidir.
Her seçimde bir karo belirlersiniz (selectedTile). Bu karo, bu seviyedeki önceki bir turdan gelen lav grubuna zaten ait olmamalıdır. Tur daha sonra tek karonuzu turun tüm lav grubuyla karşılaştırarak sonuçlanır (selectedTile):
isLoss = droppedTiles.includes(selectedTile)
Karonuz bu turda düşen karolardan biriyse koşu sona erer. Aksi hâlde, onunla birlikte kaç başka karo düştüğüne bakılmaksızın turu atlatmış olursunuz.
Zorluk yapılandırması
Dört zorluk seviyesi, tur boyutu ile tur sayısı arasında denge kurar. Her biri yine toplam 49 karoluk tahtayı oluşturur (dropsPerRound × roundsPerLevel + survivingTiles = 49):
Zorluk | Tur başına düşüş | Seviye başına tur | Hayatta kalan karolar |
Kolay | 7 | 6 | 7 |
Orta | 11 | 4 | 5 |
Zor | 23 | 2 | 3 |
Toxic | 48 | 1 | 1 |
Seviye ve oyun ilerlemesi
Bir oyunda 3 seviye bulunur ve her birinin kendine ait, bağımsız olarak shuffle edilmiş 49 karoluk tahtası vardır. Bir seviyedeki tüm turları atlatmak o seviyeyi tamamlar ve sizi ilk turdan başlayarak sonraki seviyenin tahtasına geçirir; üçüncü seviyeyi tamamlamak oyunu bitirir.
Nakde çevirme
Herhangi bir turu atlattıktan sonra nakde çevirebilirsiniz — ilk başarılı seçiminiz bunu zaten açar.
Çarpan
multiplier = edgeMultiplier * 49^(levelsCleared+1) / (tilesRemainingInLevel * survivingTiles^levelsCleared)
levelsCleared şimdiye kadar tamamen tamamlanan seviye sayısıdır, tilesRemainingInLevel mevcut seviyede bir turu her atlattığınızda, turun düşüş sayısı kadar azalır ve survivingTiles yukarıdaki tablodaki zorluğun seviye başına hayatta kalan sayısıdır.
Bu, adil oranlı bir fiyattır: eşit olasılıklı rastgele karo yerleşimi altında tam olarak o noktaya ulaşmanın (tamamlanan seviyeler × atlatılan turlar) kümülatif olasılığının tersidir ve kasa avantajına göre ölçeklendirilir.


