Saya seorang pengembang web-game dan saya mendapat masalah dengan angka acak. Katakanlah seorang pemain memiliki peluang 20% untuk mendapatkan pukulan kritis dengan pedangnya. Itu berarti, 1 dari 5 hit harus kritis. Masalahnya adalah saya mendapat hasil kehidupan nyata yang sangat buruk - kadang-kadang pemain mendapatkan 3 crits dalam 5 hits, kadang-kadang tidak ada dalam 15 hit. Pertempuran agak pendek (3-10 hit) jadi penting untuk mendapatkan distribusi acak yang bagus.
Saat ini saya menggunakan PHP mt_rand()
, tetapi kami hanya memindahkan kode kami ke C ++, jadi saya ingin menyelesaikan masalah ini di mesin baru permainan kami.
Saya tidak tahu apakah solusinya adalah generator acak yang seragam, atau mungkin untuk mengingat keadaan acak sebelumnya untuk memaksa distribusi yang tepat.
Jawaban:
Saya setuju dengan jawaban sebelumnya bahwa keacakan nyata dalam menjalankan kecil beberapa permainan tidak diinginkan - sepertinya terlalu tidak adil untuk beberapa kasus penggunaan.
Saya menulis Shuffle Bag sederhana seperti implementasi di Ruby dan melakukan beberapa pengujian. Implementasi melakukan ini:
Itu dianggap tidak adil berdasarkan probabilitas batas. Misalnya, untuk probabilitas 20%, Anda bisa menetapkan 10% sebagai batas bawah dan 40% sebagai batas atas.
Dengan menggunakan batasan itu, saya menemukan bahwa dengan 10 hit, 14,2% dari waktu implementasi pseudorandom yang sebenarnya menghasilkan hasil yang di luar batas tersebut . Sekitar 11% dari waktu, 0 hit kritis dicetak dalam 10 percobaan. 3,3% dari waktu, 5 atau lebih hit kritis mendarat dari 10. Tentu saja, menggunakan algoritma ini (dengan jumlah roll minimum 5), jumlah yang jauh lebih kecil (0,03%) dari menjalankan "Fairish" berada di luar batas . Sekalipun implementasi di bawah ini tidak cocok (tentu saja hal yang lebih pintar dapat dilakukan), perlu dicatat bahwa secara mencolok sering kali pengguna Anda akan merasa tidak adil dengan solusi pseudorandom nyata.
Inilah daging
FairishBag
tulisan saya di Ruby. Seluruh implementasi dan simulasi Monte Carlo cepat tersedia di sini (inti) .Pembaruan: Menggunakan metode ini meningkatkan kemungkinan keseluruhan untuk mendapatkan hit kritis, menjadi sekitar 22% menggunakan batas di atas. Anda dapat mengimbangi ini dengan mengatur probabilitas "nyata" nya sedikit lebih rendah. Probabilitas 17,5% dengan modifikasi berukuran menghasilkan probabilitas jangka panjang yang diamati sekitar 20%, dan membuat jangka pendek berjalan terasa adil.
sumber
Yang Anda butuhkan adalah tas shuffle . Ini memecahkan masalah true random menjadi terlalu acak untuk game.
Algoritmanya kira-kira seperti ini: Anda memasukkan 1 hit kritis dan 4 non-kritis ke dalam tas. Kemudian Anda mengacak pesanan mereka di dalam tas dan memilihnya satu per satu. Ketika tas kosong, Anda mengisinya lagi dengan nilai yang sama dan mengacaknya. Dengan begitu Anda akan mendapatkan rata-rata 1 klik kritis per 5 klik, dan paling banyak 2 klik kritis dan 8 tidak kritis berturut-turut. Tingkatkan jumlah item dalam tas untuk lebih banyak keacakan.
Berikut adalah contoh implementasi (di Jawa) dan test case-nya yang saya tulis beberapa waktu lalu.
sumber
Anda memiliki kesalahpahaman tentang apa arti acak.
Manakah dari ini yang lebih acak?
Sementara plot kedua terlihat lebih merata, plot yang lebih acak sebenarnya adalah plot pertama. Pikiran manusia sering melihat pola secara acak, jadi kita melihat rumpun di plot pertama sebagai pola, tetapi tidak - mereka hanya bagian dari sampel yang dipilih secara acak.
sumber
Mengingat perilaku yang Anda minta, saya pikir Anda mengacak variabel yang salah.
Daripada mengacak apakah hit ini akan kritis, coba acakkan jumlah belokan hingga hit kritis berikutnya terjadi. Misalnya, pilih saja angka antara 2 & 9 setiap kali pemain mendapat kritikan, dan kemudian berikan mereka kritikan berikutnya setelah banyak putaran berlalu. Anda juga dapat menggunakan metode dadu untuk lebih mendekati distribusi normal - misalnya, Anda akan mendapatkan kritikal berikutnya dalam giliran 2D4.
Saya percaya teknik ini digunakan dalam RPG yang memiliki pertemuan acak di dunia luar juga - Anda mengacak penghitung langkah, dan setelah banyak langkah itu, Anda tertabrak lagi. Rasanya jauh lebih adil karena Anda hampir tidak pernah dihantam oleh dua pertemuan berturut-turut - jika itu terjadi sekali saja, para pemain menjadi marah.
sumber
Pertama, tentukan distribusi "tepat". Angka acak adalah, well, acak - hasil yang Anda lihat sepenuhnya konsisten dengan keacakan (semu).
Memperluas hal ini, saya berasumsi apa yang Anda inginkan adalah perasaan "adil", sehingga pengguna tidak dapat mencapai 100 putaran tanpa keberhasilan. Jika demikian, saya akan melacak jumlah kegagalan sejak keberhasilan terakhir, dan menimbang hasil yang dihasilkan. Anggap Anda ingin 1 dalam 5 gulungan "berhasil". Jadi, Anda secara acak menghasilkan angka dari 1 hingga 5, dan jika itu 5, bagus.
Jika tidak, catat kegagalannya, dan lain kali, buat angka dari 1 hingga 5, tetapi tambahkan pada katakanlah, lantai (numFailures / 2). Jadi kali ini, sekali lagi, mereka memiliki peluang 1 banding 5. Jika gagal, lain kali interval kemenangan adalah 4 dan 5; peluang sukses 2 in 5. Dengan pilihan-pilihan ini, setelah 8 kegagalan, mereka pasti akan berhasil.
sumber
Bagaimana kalau mengganti mt_rand () dengan sesuatu seperti ini?
(RFC 1149.5 menetapkan 4 sebagai nomor acak standar-IEEE.)
Dari XKCD .
sumber
Semoga artikel ini akan membantu Anda: http://web.archive.org/web/20090103063439/http://www.gamedev.net:80/reference/design/features/randomness/
Metode menghasilkan 'angka acak' ini umum di game rpg / mmorpg.
Masalah yang dipecahkannya adalah (ekstrak) ini:
sumber
Yang Anda inginkan bukanlah angka acak, tetapi angka yang tampaknya acak bagi manusia. Lainnya telah menyarankan algoritma individual, yang dapat membantu Anda, seperti Shuffle Bad.
Untuk analisis terperinci dan luas dari domain ini, lihat AI Game Programming Wisdom 2 . Seluruh buku ini layak dibaca untuk setiap pengembang game, gagasan "angka yang tampaknya acak" dibahas di bab ini:
Keacakan yang Difilter untuk Keputusan AI dan Logika Game :
Abstrak: Kearifan konvensional menunjukkan bahwa semakin baik generator angka acak, permainan Anda akan semakin tidak dapat diprediksi. Namun, menurut studi psikologi, keacakan yang sebenarnya dalam jangka pendek sering terlihat jelas tidak acak bagi manusia. Artikel ini menunjukkan bagaimana membuat keputusan AI acak dan logika permainan terlihat lebih acak bagi pemain, sambil tetap mempertahankan keacakan statistik yang kuat.
Anda juga mungkin menemukan bab lain yang menarik:
Statistik Angka Acak
Abstrak: Angka acak paling banyak digunakan oleh Kecerdasan Buatan dan game pada umumnya. Mengabaikan potensi mereka berarti membuat game dapat diprediksi dan membosankan. Menggunakannya secara salah bisa sama buruknya dengan mengabaikannya begitu saja. Memahami bagaimana angka acak dihasilkan, keterbatasannya dan kemampuannya, dapat menghilangkan banyak kesulitan dalam menggunakannya di game Anda. Artikel ini menawarkan wawasan tentang angka acak, generasi mereka, dan metode untuk memisahkan yang baik dari yang buruk.
sumber
Tentunya setiap generasi nomor acak memiliki peluang untuk menghasilkan menjalankan seperti itu? Anda tidak akan mendapatkan set sampel yang cukup besar dalam 3-10 gulungan untuk melihat persentase yang sesuai.
Mungkin yang Anda inginkan adalah ambang belas kasihan ... ingat 10 gulungan terakhir, dan jika mereka belum mendapatkan pukulan kritis, berikan mereka freebie. Menghaluskan sling dan panah keacakan.
sumber
Solusi terbaik Anda mungkin bermain-pengujian dengan beberapa non yang berbeda skema acak yang dan memilih salah satu yang membuat pemain paling bahagia.
Anda juga dapat mencoba kebijakan mundur untuk nomor yang sama dalam pertemuan tertentu, misalnya, jika seorang pemain menggulirkan
1
pada giliran pertama mereka menerimanya. Untuk mendapatkan yang lain1
mereka harus menggulung 21
s secara berurutan. Untuk mendapatkan ketiga,1
mereka membutuhkan 3 berturut-turut, tanpa batas.sumber
Sayangnya yang Anda minta adalah penghasil angka yang tidak acak - karena Anda ingin hasil sebelumnya diperhitungkan saat menentukan nomor berikutnya. Saya rasa ini bukan cara penghasil bilangan acak.
Jika Anda ingin 1 dari setiap 5 hit menjadi kritis maka cukup pilih angka antara 1 dan 5 dan katakan bahwa hit itu akan menjadi kritis.
sumber
mt_rand () didasarkan pada implementasi Mersenne Twister , yang berarti menghasilkan salah satu distribusi acak terbaik yang bisa Anda dapatkan.
Tampaknya apa yang Anda inginkan bukanlah keacakan sama sekali, jadi Anda harus mulai menentukan dengan tepat apa yang Anda inginkan. Anda mungkin akan menyadari bahwa Anda memiliki harapan yang bertentangan - bahwa hasilnya harus benar-benar acak dan tidak dapat diprediksi, namun pada saat yang sama mereka tidak boleh menunjukkan variasi lokal dari probabilitas yang dinyatakan - tetapi kemudian menjadi dapat diprediksi. Jika Anda menetapkan maksimum 10 non-crits berturut-turut, maka Anda baru saja mengatakan kepada pemain "jika Anda memiliki 9 non-crit berturut-turut, yang berikutnya akan menjadi kritis dengan kepastian 100%" - Anda mungkin juga tidak repot-repot dengan keacakan sama sekali.
sumber
Lebih dari sejumlah kecil tes Anda harus mengharapkan hasil seperti itu:
Keacakan benar hanya dapat diprediksi pada ukuran set besar, sehingga sangat mungkin untuk melempar koin dan mendapatkan kepala 3 kali berturut-turut pertama kali, namun lebih dari beberapa juta flips Anda akan berakhir dengan sekitar 50-50.
sumber
Saya melihat banyak jawaban menyarankan untuk melacak nomor yang dihasilkan sebelumnya atau untuk mengocok semua nilai yang mungkin.
Secara pribadi, saya tidak setuju, bahwa 3 crit berturut-turut buruk. Saya juga tidak setuju bahwa 15 non-crits berturut-turut itu buruk.
Saya akan memecahkan masalah, dengan memodifikasi peluang itu sendiri, setelah setiap angka. Contoh (untuk menunjukkan ide):
Semakin lama Anda tidak mendapatkan kritik - semakin tinggi peluang yang Anda miliki untuk tindakan selanjutnya ke kritik. Reset yang saya sertakan sepenuhnya opsional dan perlu pengujian untuk mengetahui apakah perlu atau tidak. Mungkin diinginkan atau tidak diinginkan untuk memberikan probabilitas kritik yang lebih tinggi untuk lebih dari satu tindakan berturut-turut, setelah rantai aksi non-kritik yang panjang.
Hanya melempar 2 sen saya ...
sumber
Beberapa jawaban teratas adalah penjelasan yang bagus, jadi saya hanya akan fokus pada algoritma yang memberi Anda kendali atas kemungkinan "coretan buruk" sementara tidak pernah menjadi deterministik. Inilah yang saya pikir harus Anda lakukan:
Alih-alih menentukan p , parameter distribusi Bernoulli, yang merupakan probabilitas Anda untuk hit kritis, tentukan a dan b , parameter distribusi beta, "konjugat prior" dari distribusi Bernoulli. Anda perlu melacak A dan B , jumlah hit kritis dan non-kritis sejauh ini.
Sekarang, untuk menentukan a dan b , pastikan bahwa a / (a + b) = p, peluang hit kritis. Yang rapi adalah bahwa (a + b) menghitung seberapa dekat Anda ingin A / (A + B) menjadi p secara umum.
Anda melakukan pengambilan sampel seperti ini:
biarkan
p(x)
menjadi fungsi kepadatan probabilitas dari distribusi beta. Ini tersedia di banyak tempat, tetapi Anda dapat menemukannya di GSL sebagai gsl_ran_beta_pdf.Pilih hit kritis dengan pengambilan sampel dari distribusi bernoulli dengan probabilitas p_1 / (p_1 + p_2)
Jika Anda menemukan bahwa angka acak memiliki terlalu banyak "goresan buruk", skala a dan b , tetapi dalam batasnya, ketika a dan b pergi hingga tak terbatas, Anda akan memiliki pendekatan kocokan kocokan yang dijelaskan sebelumnya.
Jika Anda menerapkan ini, beri tahu saya bagaimana hasilnya!
sumber
Jika Anda menginginkan distribusi yang menghambat nilai pengulangan, Anda bisa menggunakan algoritma penolakan berulang sederhana.
misalnya
Kode ini menolak nilai berulang 95% dari waktu, membuat pengulangan tidak mungkin tetapi tidak mustahil. Secara statistik ini agak jelek, tetapi mungkin akan menghasilkan hasil yang Anda inginkan. Tentu saja, itu tidak akan mencegah distribusi seperti "5 4 5 4 5". Anda bisa menjadi pelamun dan menolak yang terakhir kedua (katakanlah) 60% dari waktu dan yang ketiga terakhir (katakanlah) 30%.
Saya tidak merekomendasikan ini sebagai desain game yang bagus. Cukup menyarankan cara mencapai apa yang Anda inginkan.
sumber
Tidak begitu jelas apa yang Anda inginkan. Dimungkinkan untuk membuat fungsi sedemikian rupa sehingga 5 kali pertama Anda menyebutnya, ia mengembalikan angka 1-5 dalam urutan acak.
Tapi itu tidak terlalu acak. Pemain akan tahu bahwa dia akan mendapatkan tepat 5 dalam 5 serangan berikutnya. Mungkin itu yang Anda inginkan, dan dalam hal ini, Anda hanya perlu kode itu sendiri. (buat larik yang berisi angka-angka lalu kocok)
Atau, Anda bisa tetap menggunakan pendekatan Anda saat ini, dan menganggap bahwa hasil Anda saat ini disebabkan oleh generator acak yang buruk. Perhatikan bahwa tidak ada yang salah dengan nomor Anda saat ini. Nilai acak adalah acak. terkadang Anda mendapatkan 2, 3 atau 8 dengan nilai yang sama berturut-turut. Karena mereka acak. Generator acak yang baik hanya menjamin bahwa rata-rata, semua angka akan dikembalikan secara merata.
Tentu saja jika Anda telah menggunakan generator acak yang buruk, yang mungkin membuat hasil Anda miring, dan jika demikian, hanya beralih ke generator acak yang lebih baik akan menyelesaikan masalah. (Lihat perpustakaan Boost.Random untuk generator yang lebih baik)
Atau, Anda bisa mengingat nilai N terakhir yang dikembalikan oleh fungsi acak Anda, dan timbang hasilnya. (contoh sederhana adalah, "untuk setiap kemunculan hasil baru, ada kemungkinan 50% kita harus membuang nilainya dan mendapatkan yang baru"
Jika saya harus menebak, saya akan mengatakan tetap dengan keacakan "sebenarnya" adalah taruhan terbaik Anda. Pastikan Anda menggunakan generator acak yang bagus, dan terus seperti yang Anda lakukan sekarang.
sumber
Anda dapat membuat daftar yang berisi angka dari 1 hingga 5, dan menyortirnya secara acak. Kemudian cukup buka daftar yang Anda buat. Anda memiliki jaminan berlari ke setiap nomor setidaknya sekali ... Ketika Anda selesai dengan 5 angka pertama, cukup buat 5 angka lainnya ...
sumber
Saya merekomendasikan sistem persentase progresif seperti Blizzard menggunakan: http://www.shacknews.com/onearticle.x/57886
Secara umum Anda menggulung RNG kemudian membandingkannya dengan nilai untuk menentukan apakah berhasil atau tidak. Itu mungkin terlihat seperti:
Yang perlu Anda lakukan adalah menambahkan peningkatan kesempatan dasar ...
Jika Anda ingin lebih mewah, cukup mudah untuk menambahkan lebih banyak. Anda dapat membatasi jumlah yang bisa didapat oleh progressiveChance untuk menghindari peluang kritis 100% atau mengatur ulangnya pada acara tertentu. Anda juga dapat memiliki peningkatan progressiveChance dalam jumlah yang lebih kecil setiap dorongan dengan sesuatu seperti progressiveChance + = (1 - progressiveChance) * SKALA tempat SKALA <1.
sumber
Nah, jika Anda sedikit ke matematika, Anda mungkin dapat mencoba distribusi eksponensial
Misalnya, jika lambda = 0,5, nilai yang diharapkan adalah 2 (baca artikel itu!), Berarti Anda kemungkinan besar akan menekan / crit / apa pun setiap putaran kedua (seperti 50%, ya?). Tetapi dengan distribusi probabilitas seperti itu, Anda pasti akan melewatkan (atau melakukan yang berlawanan dengan apa pun) pada putaran ke-0 (yang, di mana peristiwa telah terjadi dan turn_counter telah diatur ulang), memiliki peluang 40% untuk mencapai giliran berikutnya, sekitar 65% kesempatan untuk melakukannya putaran ke-2 (berikutnya setelah berikutnya), sekitar 80% untuk mencapai peringkat ke-3 dan seterusnya.
Seluruh tujuan dari distribusi itu adalah jika seseorang memiliki peluang hit 50% dan ia melewatkan 3 kali berturut-turut, ia akan melakukan shurely (well, lebih dari 80% peluang, dan ia meningkatkan setiap giliran berikutnya) mengenai. Ini mengarah ke hasil yang lebih "adil", menjaga kemungkinan 50% secara keseluruhan tidak berubah.
Mengambil kesempatan 20% Anda dari kritik, Anda punya
Masih sekitar 0,2% (vs 5%) kemungkinan 3 crits + 2 non-crits dalam 5 putaran konsekuen. Dan ada 14% kemungkinan dari 4 non-crits, 5% dari 5, 1,5% untuk 6, 0,3% untuk 7, 0,07% untuk 8 non-crit sebagai akibatnya. Saya bertaruh "lebih adil" dari 41%, 32%, 26%, 21% dan 16%.
Semoga Anda tidak bosan sampai mati.
sumber
Bagaimana dengan membuat peluang kritis tergantung pada serangan N terakhir. Satu skema sederhana adalah semacam rantai markov: http://en.wikipedia.org/wiki/Markov_chain tetapi kodenya juga sangat sederhana.
Tentu saja Anda harus membuat matematika Anda karena kemungkinan kritis lebih rendah daripada peluang kritis setelah Anda tahu bahwa itu sudah cukup berubah sejak yang terakhir
sumber
OP,
Cukup banyak, jika Anda ingin adil, itu tidak akan acak.
Masalah permainan Anda adalah panjang pertandingan yang sebenarnya. Semakin lama kecocokannya, semakin sedikit keacakan yang akan Anda lihat (crit akan cenderung 20%) dan akan mendekati nilai yang Anda inginkan.
Anda mendapat dua opsi, pra-hitung serangan berdasarkan gulungan sebelumnya. Yang mana Anda akan mendapatkan satu krit setiap 5 serangan (berdasarkan 20% serangan Anda), tetapi Anda dapat membuat urutannya terjadi secara acak.
listOfFollowingAttacks = {Hit, Hit, Hit, Miss, Crit};
Itulah pola yang Anda inginkan. Jadi buat itu pilih secara acak dari daftar itu, sampai kosong, mereka membuatnya kembali.
Itu adalah pola yang saya buat untuk permainan saya, itu bekerja dengan sangat baik, untuk apa yang saya inginkan.
pilihan kedua Anda, akan, meningkatkan kesempatan untuk kritik, Anda mungkin akan melihat angka yang lebih merata di akhir semua serangan (menganggap bahwa pertandingan Anda berakhir agak cepat). Semakin sedikit kesempatan, semakin banyak RNG yang Anda dapatkan.
sumber
Anda melihat distribusi linier, ketika Anda mungkin menginginkan distribusi normal.
Jika Anda ingat kembali pada masa muda Anda bermain D & D, Anda diminta untuk melempar beberapa n-sided die, lalu jumlah hasilnya.
Misalnya, menggulung dadu bersisi 4 x 6 berbeda dengan menggulirkan dadu bersisi 1 x 24.
sumber
City of Heroes sebenarnya memiliki mekanik yang disebut "streakbreaker" yang memecahkan masalah ini dengan tepat. Cara kerjanya adalah bahwa setelah serangkaian kesalahan panjang terkait dengan probabilitas hit terendah dalam string, serangan berikutnya dijamin akan menjadi hit. Misalnya, jika Anda melewatkan serangan dengan lebih dari 90% untuk memukul peluang maka serangan berikutnya akan otomatis mengenai, tetapi jika peluang hit Anda lebih rendah seperti 60% maka Anda harus memiliki beberapa kesalahan berturut-turut untuk memicu "streakbreaker" (I tidak tahu angka pastinya)
sumber
ini benar-benar dapat diprediksi ... tetapi Anda tidak pernah bisa yakin.
sumber
Bagaimana dengan menimbang nilainya?
Misalnya, jika Anda memiliki peluang 20% untuk hit kritis, hasilkan angka antara 1 dan 5 dengan satu angka mewakili hit kritis, atau angka antara 1 dan 100 dengan 20 angka menjadi hit kritis.
Tetapi selama Anda bekerja dengan nomor acak atau pseudorandom, tidak ada cara untuk berpotensi menghindari hasil yang Anda lihat saat ini. Itu sifat keacakan.
sumber
Reaksi atas: "Masalahnya adalah saya mendapat hasil kehidupan nyata yang sangat buruk - kadang-kadang pemain mendapat 3 crits dalam 5 hits, kadang-kadang tidak ada dalam 15 hit."
Anda memiliki peluang antara 3 dan 4% untuk tidak mendapatkan apa pun dalam 15 hit ...
sumber
Saya akan mengusulkan "mati putback tertunda secara acak" sebagai berikut:
in-array
) awalnya diisi dengan nilai dari 0 hingga n-1, yang lainnya (out-array
) kosongin-array
in-array
keout-array
out-array
kembali kein-array
Ini memiliki sifat yang akan "bereaksi" lebih lambat semakin besar n . Misalnya, jika Anda menginginkan peluang 20%, pengaturan n ke 5 dan memukul pada 0 adalah "kurang acak" daripada pengaturan n ke 10 dan memukul pada 0 atau 1, dan menjadikannya 0 hingga 199 dari 1000 akan hampir tidak bisa dibedakan dari keacakan benar atas sampel kecil. Anda harus menyesuaikan n dengan ukuran sampel Anda.
sumber
Pra-hitung hit kritis acak untuk setiap pemain.
sumber
Saya pikir mungkin Anda menggunakan fungsi distribusi acak yang salah. Anda mungkin tidak ingin pemerataan atas angka. Cobalah distribusi yang normal sehingga hit kritis menjadi lebih jarang daripada hit 'biasa'.
Saya bekerja dengan Java jadi saya tidak yakin di mana Anda dapat menemukan sesuatu untuk C ++ yang memberi Anda angka acak dengan distribusi normal tetapi harus ada sesuatu di luar sana.
sumber