Rasgele sayı oluşturmada “çok” şanslı / şanssız çizgilerden nasıl kaçınabilirim?


30

Şu anda, oyuncular tarafından verilen hasarın her zaman 0,8 ile 1,2 arasında rastgele bir faktörle çarpıldığı çok oyunculu bir dövüş sistemi ile uğraşıyorum.

Teoride, gerçek anlamda rastgele bir RNG, sonunda birçok kez aynı sayıyı verebilir ( Tetris ikilemine bakınız ). Bu, oyuncunun her zaman çok yüksek hasar almasına neden olurken, diğeri her zaman çok düşük hasar verir.

Bunun olmadığından emin olmak için ne yapabilirim? Bazı RNG'ler tekrarlamadan kaçınmakta diğerlerinden daha mı iyi?


Bunun nasıl çalıştığını anlamadım. Tabii ki, tüm x'in büyük olduğu bir x1, x2, x3, x4 .. dizisini elde edeceksiniz. Bu sadece rastgele değil mi?
Komünist Ördek

Yanıtlar:


26

Önceden ayarlanmış bir hasar sonucu listesi ve karışma listesini Tetris'in yaptığı gibi çözebilirsiniz.

Diyelim ki oyuncu doğrusal bir dağılımla 0.8x - 1.2x arası hasar verecek. [0.8, 0.9, 1.0, 1.1, 1.2] listesine alın. Rasgele karıştırın , böylece elde edersiniz, örneğin [1.2, 1.0, 0.8, 0.9, 1.1].

Oyuncunun ilk hasar vermesi durumunda, 1.2x. Sonra 1x. Sonra, vb, 1.1x. Yalnızca dizi boş olduğunda yeni bir dizi oluşturup karıştırmalısınız.

Uygulamada, muhtemelen bir kerede 4+ diziye bunu yapmak isteyeceksiniz (örn. [0.8,0.8.0.8,0.8,0.9,0.9,0.9,0.9, ...] ile başlar). Aksi halde, dizinin süresi oyuncuların bir sonraki vuruşlarının "iyi" olup olmadığını anlayabilecekleri kadar düşüktür. (Her ne kadar bu, savaşa daha fazla strateji ekleyebilse de, Dragon Quest IX'in Hoimi tablosunda olduğu gibi , insanların şifa numaralarına bakarak nasıl sorgulayabileceklerini ve nadir bir düşüş garanti edene kadar ince ayar yapabileceklerini keşfettiler .)


3
Biraz daha rastgele yapmak için listenin yarısını rasgele sayılar olarak, diğer yarısını da ortalamanın doğru olması için (2-x) olarak hesaplayabilirsiniz.
Adam

2
@Adam: Bu yöntem gerçekten sadece bu özel örnek için işe yarıyor; Hasar çarpanları yerine Tetris parçalarıyla uğraşıyorsanız, 2 - S bloğu nedir?

6
Bunun için kullanılan genel terim, sistemin “değişmeden rastgele” olmasıdır. Gerçekten de zar yerine kart destesi kullanmaya benzer.
Kylotan

Daha da iyisi, sayıların yarısını gerçekten rastgele yapabilirsiniz ve bunların yalnızca yarısı bu kurala tabidir.
'.

1
Yine de, yerel dağıtımın küresel dağılıma benzememesiyle sonuçlanabilir, ki bu tam olarak sorunun ne istememesidir. "Gerçekten rastgele" gibi terimler belirsiz sözde matematikseldir; İstediğiniz istatistiksel özellikleri ne kadar çok tanımlarsanız, niyetiniz ve oyun tasarımınız o kadar net olur.

5

Aslında bunu yapmak için bazı kodlar yazdım . Bunun amacı şanssız çizgileri düzeltmek için istatistik kullanıyor. Bunu yapabilmenizin yolu, etkinliğin kaç kez gerçekleştiğini takip etmek ve PRNG tarafından oluşturulan sayıyı önyargılı hale getirmek için kullanmaktır.

Öncelikle, olayların yüzdesini nasıl takip ederiz? Bunu yapmanın saf yolu, şimdiye kadar üretilen tüm sayıları bellekte tutmak ve onları ortalamaktır: hangisi işe yarayacak ama korkunç derecede verimsiz. Küçük bir düşünceden sonra aşağıdakileri gündeme getirdim (temelde kümülatif bir hareketli ortalama ).

Aşağıdaki PRNG numunelerini alın (numunenin> = 0,5 olması durumunda işlem yapalım):

Values: 0.1, 0.5, 0.9, 0.4, 0.8
Events: 0  , 1  , 1  , 0  , 1
Percentage: 60%

Her değerin nihai sonucun 1 / 5'ine katkıda bulunduğuna dikkat edin. Buna başka bir yoldan bakalım:

Values: 0.1, 0.5
Events: 0  , 1

0Değerin% 50'sine ve değerin% 50'sine katkıda bulunduğuna dikkat edin 1. Biraz daha ileri götürülmüş:

Values: [0.1, 0.5], 0.9
Events: [0  , 1  ], 1

Şimdi ilk değerler, değerin% 66'sına ve son% 33'üne katkıda bulunur. Temel olarak bunu aşağıdaki prosese damlatabiliriz:

result = // 0 or 1 depending on the result of the event that was just generated
new_samples = samples + 1

average = (average * samples / new_samples) + (result * 1 / new_samples)
// Essentially:
average = (average * samples / new_samples) + (result / new_samples)

// You might want to limit this to, say, 100.
// Leaving it to carry on increasing can lead to unfairness
// if the game draws on forever.
samples = new_samples

Şimdi PRNG'den örneklenen değerin sonucunu önyargılı hale getirmemiz gerekiyor, çünkü burada bir yüzde şans için gidiyoruz (işler, RTS'deki rastgele miktarlara karşı). Bunu açıklamak zor olacak çünkü 'başıma geldi'. Eğer ortalama daha düşükse, olayın meydana gelme şansını arttırmamız gerektiği ve bunun tersi de geçerlidir. Yani bazı örnekler

average = 0.1
desired = 0.5
corrected_chance = 83%

average = 0.2
desired = 0.5
corrected_chance = 71%

average = 0.5
desired = 0.5
corrected_change = 50%

Şimdi “başıma gelenler”, ilk örnekte% 83'ün yalnızca "0.6'dan 0.6" (başka bir deyişle "0.5'ten 0.5 artı 0.1") olduğu anlamına geliyor. Rastgele olay terimlerinde şu anlama gelir:

procced = (sample * 0.6) > 0.1
// or
procced = (sample * 0.6) <= 0.5

Dolayısıyla bir etkinlik oluşturmak için temel olarak aşağıdaki kodu kullanırsınız:

total = average + desired
sample = rng_sample() * total // where the RNG provides a value between 0 and 1
procced = sample <= desired

Ve böylece özümde koyduğum kodu alırsın. Bunların rastgele hasar durum senaryosunda kullanılabileceğinden eminim, ancak bunu anlamaya zamanım olmadı.

Feragatname: Bu, tüm evde üretilen istatistikler, bu alanda eğitimim yok. Birim testlerim yine de başarılı.


İlk örneğinizde bir hataya benziyor, çünkü hem 0,1 hem de 0,9 değeri 0 olayıyla sonuçlanıyor. Ancak, temelde kümülatif bir hareketli ortalama tutmayı ( en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average ) açıklamayı ve buna göre düzeltmeyi açıklıyorsunuz . Bir risk, her bir sonucun önceki sonuç ile önemli ölçüde ters korelasyon göstermesidir, ancak bu korelasyon zamanla azalır.
Kylotan

1
Bunun yerine bir 'sızdıran entegratör' sistemi kullanmak için bunu değiştirmeye istekli olurum: bunun yerine ortalama 0.5 ile başlar ve örneklerin sayılması yerine, artımlı olmayan rasgele sabit bir değer alır (örn. 10, 20, 50 veya 100). . O zaman en azından müteakip 2 değer arasındaki korelasyon, jeneratör kullanımı boyunca sabittir. Ayrıca sabit değeri ayarlayabilirsin - daha büyük değerler daha yavaş düzeltme ve daha belirgin rastgelelik anlamına gelir.
Kylotan

@Kylotan ismini verdiğiniz için teşekkür ederiz. İkinci yorumunuzla ne demek istediğinizi tam olarak bilmiyorum - belki yeni bir cevap verebilir misiniz?
Jonathan Dickinson,

Bu oldukça zekice ve dizilerin sınırlamaları yok. Kylotan'ın önerisini, başlangıçtan samplesitibaren en yüksek değerinde (bu durumda, 100) başlatacak şekilde anlıyorum . Bu şekilde, RNG'nin stabilize olması 99 tekrarlama gerektirmez. Her iki durumda da, bu yöntemle görebildiğim tek dezavantaj , adilliği garanti etmemesi , sadece sabit bir ortalama sağlaması.
Kullanıcı

jSepia - gerçekten, hala adalet / adaletsizlik koşusu elde edersiniz, ancak (genellikle) dengeli bir koşuyla takip edilirler. Örneğin, birim testimde 100 procs olmayan 'zorla' yaptım ve gerçek örnekleri yaptığımda ~ 60 procs ile karşılaştım. Etkilenmemiş durumlarda (koda bakarsanız)% 50'lik bir işlem genellikle her iki yönde de en azından 2/3 oranında bir işlem görür. Ancak bir oyuncunun diğer oyuncuyu yenmesine izin veren bir koşusu olabilir. Eğer fuara kuvvetle daha önyargı istiyorsanız: total = (average / 2) + desired.
Jonathan Dickinson,

3

İstediğiniz şey aslında PRNG'lerin tam tersi, doğrusal olmayan bir dağılım. Kurallarınızda bir miktar azalan getiri mantığı koymanız yeterlidir, 1.0x üzerindeki her şeyin bir tür "kritik vuruş" olduğunu varsayarsak, her turda bir kriter alma şansını yakalayabilmenizi sağlarsınız. hangi noktaya Y ye sıfırlanırlar. Sonra her turda iki rulo yaparsınız, biri ölçmek ya da ölçmek için diğeri gerçek büyüklük için.


1
Bu benim genel yaklaşımımdır, RNG'nin tek biçimli dağılımını kullanır ama dönüştürürsünüz. Ayrıca RNG'nin çıktısını, kendi geçmişine göre yeniden ayarlayan kendi kişisel dağıtımınıza bir girdi olarak kullanabilirsiniz, yani çıktılarda varyansı zorlamak için, böylece insan algı terimlerinde "daha rastgele" görünebilir.
Michael,

3
Aslında böyle bir şey yapar bir MMO biliyorum, ama kadar crit şansı aslında bir olsun her zaman artar yok tek, o zaman çok düşük bir değere sıfırlar olsun. Bu, oyuncuya çok tatmin edici olan nadir kabuk çizgileri sağlar.
coderanger

İyi bir alg gibi, uzun kuru büyüler her zaman sinir bozucu olmuştur, ancak çılgınca kabuk çizgileri yaratmaz.
Michael,

2
Bunu düzeltmek doğrusal olmayan bir dağıtım gerektirmez, sadece dağılımın kısa zaman sıralı altkümelerinin dağılımın kendisi ile aynı özelliklere sahip olmasını gerektirir.

Blizzard oyunları bunu yapıyor, Warcraft 3'ten beri en az
dreta

2

Sid Meier, GDC 2010'da bu konu ve Uygarlık oyunları hakkında mükemmel bir konuşma yaptı. Bağlantıyı daha sonra bulup yapıştırmaya çalışacağım. Temelde, algılanan rasgelelik, gerçek rasgelelikle aynı değildir. İşleri adil hissettirmek için önceki sonuçları analiz etmeniz ve oyuncuların psikolojisine dikkat etmeniz gerekir.

Her ne pahasına olursa olsun, kötü şans çizgisinden kaçının (eğer önceki iki dönüş şanssızdıysa, bir sonraki şanslı olmanız gerekir). Oyuncu daima AI rakiplerinden daha şanslı olmalıdır.


0

Değişen önyargı kullanın

01rb0

Genel dağıtım, aşağıdaki formülle önyargılı olacaktır:

rexp(-b)

b1b0

Bu sayıyı alın ve istediğiniz aralığa uygun şekilde ölçekleyin.

Bir oyuncu olumlu bir şekilde yuvarlandığında, önyargıdan çıkar. Oyuncu elverişsiz bir şekilde yuvarlandığında, önyargıya ekleyin. Değişen miktar, rulonun ne kadar elverişli olduğu (düz bir miktar (veya bir kombinasyon)) ile ölçeklenebilir. Gittiğiniz hissi sağlayacak şekilde belirli değerleri ayarlamanız gerekecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.