Bagaimana saya menghindari garis “terlalu” beruntung / tidak beruntung dalam pembuatan bilangan acak?

30

Saat ini saya sedang berurusan dengan sistem pertarungan multipemain di mana kerusakan yang ditangani oleh para pemain selalu dikalikan dengan faktor acak antara 0,8 dan 1,2.

Secara teori, RNG yang benar-benar acak akhirnya dapat menghasilkan jumlah yang sama beberapa kali (lihat dilema Tetris ). Ini bisa menghasilkan pertandingan di mana pemain selalu membuat kerusakan sangat tinggi sementara yang lain selalu membuat kerusakan sangat rendah.

Apa yang bisa saya lakukan untuk memastikan ini tidak terjadi? Apakah beberapa RNG lebih baik daripada yang lain untuk menghindari pengulangan?

Pengguna tidak ditemukan
sumber
Saya tidak melihat cara kerjanya. Tentu saja Anda akan mendapatkan urutan x1, x2, x3, x4 .. di mana semua x besar. Bukankah itu hanya acak?
Bebek Komunis

Jawaban:

26

Anda dapat menyelesaikannya dengan cara yang sama dengan Tetris, dengan membuat daftar hasil kerusakan dan pengacakan yang telah ditentukan sebelumnya.

Katakanlah Anda tahu pemain akan menangani kerusakan 0,8x hingga 1,2x dengan distribusi linier. Ambil daftar [0.8, 0.9, 1.0, 1.1, 1.2]. Acak secara acak , jadi Anda mendapatkan misal [1.2, 1.0, 0.8, 0.9, 1.1].

Pertama kali pemain memberikan Damage, mereka melakukan 1.2x. Lalu 1x. Lalu, dll, ke 1.1x. Hanya ketika array kosong Anda harus membuat dan mengocok array baru.

Dalam praktiknya, Anda mungkin ingin melakukan ini ke 4+ array sekaligus (mis. Mulai dengan [0.8.0.8.0.8.0.8.0.9.0.9.0.9.0.9, ...]). Kalau tidak, periode urutannya cukup rendah sehingga pemain dapat mengetahui apakah hit mereka berikutnya "baik" atau tidak. (Meskipun itu juga dapat menambahkan lebih banyak strategi untuk pertempuran, seperti dalam tabel Hoimi Dragon Quest IX , yang orang tahu cara menyelidiki dengan melihat angka penyembuhan dan men-tweak sampai Anda dijamin drop langka.)


sumber
3
Untuk membuatnya sedikit lebih acak, Anda selalu bisa memiliki setengah daftar sebagai angka acak, dan setengah lainnya dihitung sebagai (2-x) untuk mendapatkan rata-rata yang benar.
Adam
2
@ Adam: Metode itu benar-benar hanya berfungsi untuk contoh khusus ini; jika Anda berurusan dengan potongan Tetris daripada merusak pengganda, apakah blok 2 - S?
6
Istilah yang biasa untuk ini adalah semacam sistem "acak tanpa penggantian". Ini hanya analog dengan menggunakan setumpuk kartu daripada dadu, sungguh.
Kylotan
Bahkan lebih baik, Anda bisa melakukan setengah angka benar-benar acak, dan hanya setengah dari mereka tunduk pada aturan ini.
o0 '.
1
Itu masih bisa mengakibatkan distribusi lokal tidak menyerupai distribusi global, yang memang tidak diinginkan. Istilah seperti "benar-benar acak" adalah pseudomathematics yang tidak jelas; semakin Anda menentukan sifat statistik apa yang Anda inginkan, semakin jelas maksud dan desain game Anda.
5

Saya sebenarnya menulis beberapa kode untuk melakukan ini . Intinya adalah menggunakan statistik untuk memperbaiki coretan sial. Cara Anda dapat melakukan ini adalah untuk melacak berapa kali peristiwa telah terjadi dan menggunakannya untuk membiasakan nomor yang dihasilkan oleh PRNG.

Pertama, bagaimana kita melacak persentase acara? Cara naif melakukan ini adalah menjaga semua angka yang pernah dihasilkan dalam memori dan rata-rata keluar: yang akan bekerja tetapi sangat tidak efisien. Setelah sedikit berpikir saya datang dengan yang berikut (yang pada dasarnya adalah rata-rata bergerak kumulatif )

Ambil sampel PRNG berikut (tempat kami membeli jika sampel>> 0,5):

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

Perhatikan bahwa setiap nilai berkontribusi hingga 1/5 dari hasil akhir. Mari kita lihat dengan cara lain:

Values: 0.1, 0.5
Events: 0  , 1

Perhatikan bahwa 0kontribusi berkontribusi 50% dari nilai dan 1kontribusi 50% nilai. Diambil sedikit lebih jauh:

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

Sekarang nilai pertama berkontribusi 66% dari nilai dan 33% terakhir. Kami pada dasarnya dapat menyaring ini ke proses berikut:

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

Sekarang kita perlu mem-bias hasil dari nilai sampel dari PRNG, karena kita akan mencari peluang persentase di sini segalanya jauh lebih mudah (dibandingkan, katakanlah, jumlah kerusakan acak dalam RTS). Ini akan sulit untuk dijelaskan karena 'baru saja terpikir olehku'. Jika rata-rata lebih rendah itu berarti bahwa kita perlu meningkatkan peluang acara terjadi dan sebaliknya. Demikian beberapa contoh

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%

Sekarang apa yang 'terpikir oleh saya' adalah bahwa dalam contoh pertama 83% hanya "0,5 dari 0,6" (dengan kata lain "0,5 dari 0,5 ditambah 0,1"). Dalam istilah peristiwa acak yang artinya:

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

Jadi untuk menghasilkan suatu acara pada dasarnya Anda akan menggunakan kode berikut:

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

Dan karena itu Anda mendapatkan kode yang saya masukkan di intinya. Saya cukup yakin ini semua dapat digunakan dalam skenario kasus kerusakan acak, tapi saya belum meluangkan waktu untuk mencari tahu.

Penafian: Ini semua statistik buatan sendiri, saya tidak punya pendidikan di lapangan. Tes unit saya lulus.

Jonathan Dickinson
sumber
Tampak seperti kesalahan pada contoh pertama Anda karena nilai 0,1 dan 0,9 menghasilkan 0 event. Tapi Anda pada dasarnya menggambarkan menjaga rata-rata bergerak kumulatif ( en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average ) dan mengoreksi berdasarkan itu. Satu risiko adalah bahwa setiap hasil akan berkorelasi terbalik secara signifikan dengan hasil sebelumnya, meskipun korelasi ini akan menurun seiring waktu.
Kylotan
1
Saya akan tergoda untuk mengubah ini untuk menggunakan sistem 'integrator bocor' sebagai gantinya: mulai dengan rata-rata yang diinisialisasi ke 0,5 dan bukannya menghitung sampel memilih nilai konstan sewenang-wenang (mis. 10, 20, 50, atau 100) yang tidak bertambah. . Maka setidaknya korelasi antara 2 nilai selanjutnya konstan sepanjang penggunaan generator. Anda juga dapat mengubah nilai konstan - nilai yang lebih besar berarti koreksi lebih lambat dan keacakan yang lebih jelas.
Kylotan
@Kylotan terima kasih, terima kasih telah memberikan namanya. Saya tidak yakin persis apa yang Anda maksud dengan komentar kedua Anda - mungkin memberikan jawaban baru?
Jonathan Dickinson
Itu cukup pintar dan tidak memiliki batasan array. Saya mengerti saran Kylotan, yaitu menginisialisasi samplespada nilai maksimumnya (dalam hal ini, 100) dari awal. Dengan begitu, tidak perlu 99 iterasi untuk RNG stabil. Either way, satu-satunya kelemahan saya dapat melihat dengan metode ini adalah tidak menjamin keadilan, itu hanya memastikan rata-rata yang konstan.
Pengguna tidak ditemukan
@ jSepia - memang, Anda masih akan mendapatkan keadilan / ketidakadilan tetapi akan diikuti (biasanya) dengan lari seimbang. Misalnya dalam tes unit saya, saya 'memaksa' 100 non-procs dan bertemu dengan ~ 60 procs ketika saya melakukan sampel nyata. Di bawah situasi yang tidak terpengaruh (jika Anda melihat kode), proc 50% biasanya melihat, paling buruk, menjalankan 2/3 di kedua arah. Tapi satu pemain bisa berlari memungkinkan mereka mengalahkan pemain lain. Jika Anda ingin bias lebih kuat untuk adil: total = (average / 2) + desired.
Jonathan Dickinson
3

Apa yang Anda minta sebenarnya adalah kebalikan dari kebanyakan PRNG, distribusi non-linear. Cukup masukkan semacam logika pengembalian yang berkurang dalam aturan Anda, Dengan anggapan bahwa segala sesuatu di atas 1,0x adalah "pukulan kritis", katakan saja bahwa setiap putaran peluang Anda untuk mendapatkan kritik naik sebesar X, sampai Anda mendapatkannya di titik mana mereka reset ke Y. Anda kemudian melakukan dua gulungan setiap putaran, satu untuk menentukan crit atau tidak, dan kemudian satu lagi untuk besarnya sebenarnya.

pembuat kode
sumber
1
Ini adalah pendekatan umum yang akan saya ambil, Anda menggunakan distribusi seragam RNG tetapi mengubahnya. Anda juga dapat menggunakan output dari RNG sebagai input untuk distribusi kustom Anda sendiri yang menyesuaikan kembali berdasarkan sejarah terkini, yaitu untuk memaksa varians dalam output, sehingga terlihat "lebih acak" dalam istilah persepsi manusia.
Michael
3
Saya benar-benar tahu tentang MMO yang melakukan sesuatu seperti ini, tetapi peluang seorang kritikus benar-benar meningkat setiap kali Anda mendapatkannya sampai Anda tidak mendapatkannya, maka ia akan mereset ke nilai yang sangat rendah. Hal ini menyebabkan goresan langka yang sangat memuaskan pemain.
coderanger
Kedengarannya seperti alg yang baik, mantra kering yang panjang selalu membuat frustasi, tetapi itu tidak menyebabkan goresan gila.
Michael
2
Memperbaiki ini tidak memerlukan distribusi nonlinear, itu hanya mensyaratkan bahwa himpunan waktu sekuensial pendek dari distribusi memiliki sifat yang sama dengan distribusi itu sendiri.
Beginilah
2

Sid Meier memiliki pidato yang luar biasa di GDC 2010 tentang topik ini dan game Peradaban Saya akan mencoba mencari dan menempelkan tautan nanti. Pada dasarnya, keacakan yang dirasakan tidak sama dengan keacakan yang sebenarnya. Untuk membuat segalanya terasa adil, Anda perlu menganalisis hasil sebelumnya dan memperhatikan psikologi pemain.

Hindari goresan nasib buruk di semua biaya (jika dua belokan sebelumnya tidak beruntung, nasib berikutnya harus dijamin beruntung). Pemain harus selalu lebih beruntung dari lawan AI.

Kromster berkata mendukung Monica
sumber
0

Gunakan bias pergeseran

Generator dasar menggunakan distribusi yang seragam antara dan untuk menghasilkan . Awalnya atur nilai bias, , menjadi .01rb0

Distribusi keseluruhan akan menjadi bias dengan rumus berikut:

rexp(b)

Efeknya di sini adalah bahwa ketika positif, jumlah yang dihasilkan akan menjadi bias terhadap . Ketika negatif, angka yang dihasilkan akan bias menuju .b1b0

Ambil nomor ini dan skala sesuai dengan kisaran yang diinginkan.

Setiap kali seorang pemain berguling dengan baik, kurangi dari bias. Setiap kali pemain berputar dengan tidak baik, tambahkan ke bias. Jumlah yang diubah dapat diskalakan dengan seberapa (tidak) menguntungkan gulungan itu atau bisa menjadi jumlah yang datar (atau kombinasi). Anda perlu menyesuaikan nilai-nilai spesifik agar sesuai dengan perasaan yang Anda inginkan.

Beefster
sumber