BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌

BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌

នៅក្នុងការអភិវឌ្ឍន៍ហ្គេម ជារឿយៗអ្នកត្រូវភ្ជាប់អ្វីមួយជាមួយនឹងភាពចៃដន្យ៖ Unity មាន Random ផ្ទាល់ខ្លួនសម្រាប់រឿងនេះ ហើយស្របគ្នាជាមួយនឹងវាមាន System.Random ។ នៅពេលមួយ នៅលើគម្រោងមួយ ខ្ញុំទទួលបានចំណាប់អារម្មណ៍ថា ទាំងពីរអាចដំណើរការខុសគ្នា (ទោះបីជាពួកគេគួរតែមានការចែកចាយដូចគ្នាក៏ដោយ)។

បន្ទាប់មកពួកគេមិនបានចូលទៅក្នុងព័ត៌មានលម្អិតទេ - វាគ្រប់គ្រាន់ហើយដែលការផ្លាស់ប្តូរទៅ System.Random បានដោះស្រាយបញ្ហាទាំងអស់។ ឥឡូវនេះ យើងបានសម្រេចចិត្តពិនិត្យមើលវាឱ្យកាន់តែលម្អិត និងធ្វើការស្រាវជ្រាវបន្តិចបន្តួច៖ តើ RNGs "លំអៀង" ឬអាចព្យាករណ៍បាន និងមួយណាដែលត្រូវជ្រើសរើស។ ជាងនេះទៅទៀត ខ្ញុំបានឮច្រើនជាងម្តងនូវមតិផ្ទុយគ្នាអំពី "ភាពស្មោះត្រង់" របស់ពួកគេ - ចូរយើងព្យាយាមស្វែងយល់ពីរបៀបដែលលទ្ធផលពិតប្រៀបធៀបជាមួយនឹងអ្នកដែលបានប្រកាស។

កម្មវិធីអប់រំខ្លីៗ ឬ RNG គឺពិតជា RNG

ប្រសិនបើអ្នកធ្លាប់ស្គាល់ឧបករណ៍បង្កើតលេខចៃដន្យរួចហើយ អ្នកអាចរំលងទៅផ្នែក "ការសាកល្បង" ភ្លាមៗ។

លេខចៃដន្យ (RN) គឺជាលំដាប់នៃលេខដែលបានបង្កើតដោយប្រើដំណើរការចៃដន្យ (វឹកវរ) ដែលជាប្រភពនៃ entropy ។ នោះគឺនេះគឺជាលំដាប់ដែលធាតុរបស់ពួកគេមិនត្រូវបានទាក់ទងគ្នាដោយច្បាប់គណិតវិទ្យាណាមួយឡើយ - ពួកគេមិនមានទំនាក់ទំនងមូលហេតុនិងឥទ្ធិពលទេ។

អ្វីដែលបង្កើតលេខចៃដន្យត្រូវបានគេហៅថា random number generator (RNG)។ វាហាក់ដូចជាថាអ្វីគ្រប់យ៉ាងគឺបឋម ប៉ុន្តែប្រសិនបើយើងផ្លាស់ប្តូរពីទ្រឹស្ដីទៅការអនុវត្ត នោះតាមពិតវាមិនសាមញ្ញទេក្នុងការអនុវត្ត algorithm កម្មវិធីសម្រាប់បង្កើតលំដាប់បែបនេះ។

ហេតុផលគឺអវត្តមាននៃភាពវឹកវរដូចគ្នានៅក្នុងគ្រឿងអេឡិចត្រូនិកទំនើប។ បើគ្មានវាទេ លេខចៃដន្យឈប់ជាចៃដន្យ ហើយម៉ាស៊ីនភ្លើងរបស់វាប្រែទៅជាមុខងារធម្មតានៃអាគុយម៉ង់ដែលបានកំណត់យ៉ាងច្បាស់។ សម្រាប់ជំនាញឯកទេសមួយចំនួនក្នុងវិស័យ IT នេះគឺជាបញ្ហាធ្ងន់ធ្ងរ (ឧទាហរណ៍ គ្រីបគ្រីប) ប៉ុន្តែសម្រាប់អ្នកផ្សេងទៀតមានដំណោះស្រាយដែលអាចទទួលយកបានទាំងស្រុង។

វាចាំបាច់ក្នុងការសរសេរក្បួនដោះស្រាយដែលនឹងត្រលប់មកវិញ ទោះបីជាមិនមែនជាលេខចៃដន្យក៏ដោយ ប៉ុន្តែឱ្យជិតបំផុតតាមដែលអាចធ្វើទៅបាន - ដែលគេហៅថាលេខចៃដន្យ (PRN) ។ ក្បួនដោះស្រាយក្នុងករណីនេះត្រូវបានគេហៅថា pseudorandom number generator (PRNG) ។

មានជម្រើសជាច្រើនសម្រាប់បង្កើត PRNG ប៉ុន្តែខាងក្រោមនេះនឹងពាក់ព័ន្ធសម្រាប់អ្នករាល់គ្នា៖

  1. តម្រូវការសម្រាប់ការចាប់ផ្តើមបឋម។

    PRNG មិនមានប្រភពនៃ entropy ទេ ដូច្នេះវាត្រូវតែផ្តល់ស្ថានភាពដំបូងមុនពេលប្រើប្រាស់។ វាត្រូវបានបញ្ជាក់ជាលេខ (ឬវ៉ិចទ័រ) ហើយត្រូវបានគេហៅថាគ្រាប់ពូជ (គ្រាប់ពូជចៃដន្យ) ។ ជាញឹកញាប់ ឧបករណ៍រាប់នាឡិកាដំណើរការ ឬសមមូលជាលេខនៃម៉ោងប្រព័ន្ធត្រូវបានប្រើជាគ្រាប់ពូជ។

  2. ការបន្តពូជតាមលំដាប់។

    PRNG ត្រូវបានកំណត់ទាំងស្រុង ដូច្នេះគ្រាប់ពូជដែលបានបញ្ជាក់ក្នុងអំឡុងពេលចាប់ផ្តើមដំបូងកំណត់ដោយឡែកពីលំដាប់នៃលេខនាពេលអនាគតទាំងមូល។ នេះមានន័យថា PRNG ដាច់ដោយឡែកដែលបានចាប់ផ្តើមជាមួយគ្រាប់ពូជដូចគ្នា (នៅពេលផ្សេងគ្នា ក្នុងកម្មវិធីផ្សេងគ្នា នៅលើឧបករណ៍ផ្សេងគ្នា) នឹងបង្កើតលំដាប់ដូចគ្នា។

អ្នកក៏ត្រូវដឹងពីការចែកចាយប្រូបាប៊ីលីតេដែលកំណត់លក្ខណៈ PRNG - តើលេខអ្វីដែលវានឹងបង្កើត និងជាមួយនឹងប្រូបាប៊ីលីតេអ្វី។ ភាគច្រើនជាញឹកញាប់នេះគឺជាការចែកចាយធម្មតា ឬការចែកចាយឯកសណ្ឋាន។
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
ការចែកចាយធម្មតា (ឆ្វេង) និងការចែកចាយឯកសណ្ឋាន (ស្តាំ)

ឧបមាថាយើងមានការស្លាប់ដោយយុត្តិធម៌ដែលមាន 24 ជ្រុង។ ប្រសិនបើអ្នកបោះវា ប្រូបាប៊ីលីតេនៃការទទួលបានលេខមួយនឹងស្មើនឹង 1/24 (ដូចគ្នានឹងប្រូបាប៊ីលីតេនៃការទទួលបានលេខផ្សេងទៀត)។ ប្រសិនបើអ្នកធ្វើការបោះច្រើន និងកត់ត្រាលទ្ធផល អ្នកនឹងសម្គាល់ឃើញថាគែមទាំងអស់ធ្លាក់ចេញជាមួយនឹងប្រេកង់ប្រហាក់ប្រហែលគ្នា។ សំខាន់ ការស្លាប់នេះអាចត្រូវបានចាត់ទុកថាជា RNG ជាមួយនឹងការចែកចាយឯកសណ្ឋាន។

ចុះបើអ្នកបោះគ្រាប់ឡុកឡាក់ទាំង 10 គ្រាប់ក្នុងពេលតែមួយ ហើយរាប់ពិន្ទុសរុប? តើឯកសណ្ឋាននឹងត្រូវបានរក្សាសម្រាប់វាទេ? ទេ ភាគច្រើនជាញឹកញាប់ ចំនួនទឹកប្រាក់នឹងនៅជិត 125 ពិន្ទុ ពោលគឺដល់តម្លៃមធ្យមមួយចំនួន។ ហើយជាលទ្ធផល សូម្បីតែមុនពេលបោះចោល អ្នកអាចប៉ាន់ប្រមាណលទ្ធផលនាពេលអនាគត

ហេតុផលគឺថាមានចំនួនច្រើនបំផុតនៃបន្សំដើម្បីទទួលបានពិន្ទុមធ្យម។ កាន់តែឆ្ងាយពីវា បន្សំតិច - ហើយតាមនោះ ប្រូបាប៊ីលីតេនៃការបាត់បង់កាន់តែទាប។ ប្រសិនបើទិន្នន័យនេះត្រូវបានគេមើលឃើញ វានឹងប្រហាក់ប្រហែលនឹងរូបរាងរបស់កណ្តឹង។ ដូច្នេះជាមួយនឹងការលាតសន្ធឹងខ្លះ ប្រព័ន្ធនៃគ្រាប់ឡុកឡាក់ចំនួន 10 អាចត្រូវបានគេហៅថា RNG ជាមួយនឹងការចែកចាយធម្មតា។

ឧទាហរណ៍មួយទៀតមានតែលើកនេះទេនៅលើយន្តហោះ - បាញ់ចំគោលដៅ។ អ្នកបាញ់នឹងក្លាយជា RNG ដែលបង្កើតលេខគូ (x, y) ដែលត្រូវបានបង្ហាញនៅលើក្រាហ្វ។
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
យល់ស្របថាជម្រើសនៅខាងឆ្វេងគឺខិតទៅជិតជីវិតពិត - នេះគឺជា RNG ជាមួយនឹងការចែកចាយធម្មតា។ ប៉ុន្តែប្រសិនបើអ្នកត្រូវការពង្រាយផ្កាយនៅលើមេឃងងឹតនោះ ជម្រើសត្រឹមត្រូវដែលទទួលបានដោយប្រើ RNG ជាមួយនឹងការចែកចាយឯកសណ្ឋានគឺសមជាង។ ជាទូទៅជ្រើសរើសម៉ាស៊ីនភ្លើងអាស្រ័យលើភារកិច្ចដែលមាននៅនឹងដៃ។

ឥឡូវនេះសូមនិយាយអំពី entropy នៃលំដាប់ PNG ។ ឧទាហរណ៍ មានលំដាប់ដែលចាប់ផ្តើមដូចនេះ៖

89, 93, 33, 32, 82, 21, 4, 42, 11, 8, 60, 95, 53, 30, 42, 19, 34, 35, 62, 23, 44, 38, 74, 36, 52 ១៨, ៥៨, ៧៩, ៦៥, ៤៥, ៩៩, ៩០, ៨២, ២០, ៤១, ១៣, ៨៨, ៧៦, ៨២, ២៤, ៥, ៥៤, ៧២, ១៩, ៨០, ២, ៧៤, ៣៦, ៧១, ៩, ...

តើលេខទាំងនេះចៃដន្យប៉ុណ្ណានៅក្រឡេកមើលដំបូង? ចូរចាប់ផ្តើមដោយពិនិត្យមើលការចែកចាយ។
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
វា​មើល​ទៅ​ជិត​ឯកសណ្ឋាន ប៉ុន្តែ​ប្រសិន​បើ​អ្នក​អាន​លំដាប់​នៃ​លេខ​ពីរ ហើយ​បកស្រាយ​ពួកវា​ជា​កូអរដោណេ​នៅលើ​យន្តហោះ អ្នក​នឹង​ទទួល​បាន​ចំណុច​នេះ៖
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
លំនាំអាចមើលឃើញយ៉ាងច្បាស់។ ហើយចាប់តាំងពីទិន្នន័យនៅក្នុងលំដាប់ត្រូវបានតម្រៀបតាមវិធីជាក់លាក់មួយ (នោះគឺវាមាន entropy ទាប) នេះអាចបណ្តាលឱ្យមាន "ភាពលំអៀង" យ៉ាងខ្លាំង។ យ៉ាងហោចណាស់ PRNG បែបនេះមិនស័ក្តិសមសម្រាប់បង្កើតកូអរដោនេនៅលើយន្តហោះទេ។

លំដាប់មួយទៀត៖

42, 72, 17, 0, 30, 0, 15, 9, 47, 19, 35, 86, 40, 54, 97, 42, 69, 19, 20, 88, 4, 3, 67, 27, 42 ១៨, ៥៨, ៧៩, ៦៥, ៤៥, ៩៩, ៩០, ៨២, ២០, ៤១, ១៣, ៨៨, ៧៦, ៨២, ២៤, ៥, ៥៤, ៧២, ១៩, ៨០, ២, ៧៤, ៣៦, ៧១, ៩, ...

អ្វីៗហាក់ដូចជាល្អនៅទីនេះ សូម្បីតែនៅលើយន្តហោះក៏ដោយ៖
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
តោះមើលបរិមាណ (អានបីលេខក្នុងពេលតែមួយ)៖
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌
ហើយម្តងទៀតលំនាំ។ វាមិនអាចបង្កើតការមើលឃើញជាបួនវិមាត្របានទេ។ ប៉ុន្តែគំរូអាចមាននៅលើវិមាត្រនេះ និងនៅលើទំហំធំជាងនេះ។

នៅក្នុងការគ្រីបគ្រីប ដែលតម្រូវការតឹងរ៉ឹងបំផុតត្រូវបានដាក់លើ PRNGs ស្ថានភាពបែបនេះមិនអាចទទួលយកបានតាមប្រភេទទេ។ ដូច្នេះ ក្បួនដោះស្រាយពិសេសត្រូវបានបង្កើតឡើងដើម្បីវាយតម្លៃគុណភាពរបស់វា ដែលយើងនឹងមិនប៉ះពាល់នៅពេលនេះទេ។ ប្រធានបទគឺទូលំទូលាយ ហើយសមនឹងទទួលបានអត្ថបទដាច់ដោយឡែកមួយ។

សាកល្បង

បើ​យើង​មិន​ដឹង​អ្វី​ឲ្យ​ប្រាកដ តើ​ត្រូវ​ធ្វើ​យ៉ាង​ណា? តើវាសមនឹងការឆ្លងកាត់ផ្លូវទេ ប្រសិនបើអ្នកមិនដឹងថាភ្លើងចរាចរណ៍មួយណាអនុញ្ញាត? ផលវិបាកអាចខុសគ្នា។

ដូចគ្នាដែរចំពោះភាពចៃដន្យដ៏ល្បីនៅក្នុង Unity។ ជាការល្អប្រសិនបើឯកសារបង្ហាញព័ត៌មានលម្អិតចាំបាច់ ប៉ុន្តែរឿងរ៉ាវដែលបានលើកឡើងនៅដើមអត្ថបទនេះបានកើតឡើងយ៉ាងជាក់លាក់ដោយសារតែខ្វះភាពជាក់លាក់ដែលចង់បាន។

ហើយ​ប្រសិន​បើ​អ្នក​មិន​ដឹង​ពី​របៀប​ដែល​ឧបករណ៍​នេះ​ដំណើរ​ការ អ្នក​នឹង​មិន​អាច​ប្រើ​វា​បាន​ត្រឹម​ត្រូវ​ទេ។ ជាទូទៅ ដល់ពេលដែលត្រូវពិនិត្យ និងធ្វើការពិសោធន៍ ដើម្បីប្រាកដថាយ៉ាងហោចណាស់មានការចែកចាយ។

ដំណោះស្រាយគឺសាមញ្ញ និងមានប្រសិទ្ធភាព - ប្រមូលស្ថិតិ ទទួលបានទិន្នន័យគោលបំណង និងមើលលទ្ធផល។

ប្រធានបទនៃការសិក្សា

មានវិធីជាច្រើនដើម្បីបង្កើតលេខចៃដន្យនៅក្នុង Unity - យើងបានសាកល្បងប្រាំ។

  1. System.Random.Next(). បង្កើតចំនួនគត់ក្នុងជួរតម្លៃដែលបានផ្តល់ឱ្យ។
  2. System.Random.NextDouble(). បង្កើតលេខភាពជាក់លាក់ពីរដងក្នុងចន្លោះពី [0; ១).
  3. UnityEngine.Random.Range(). បង្កើតលេខជាក់លាក់តែមួយ (អណ្តែត) ក្នុងជួរតម្លៃដែលបានផ្តល់ឱ្យ។
  4. UnityEngine.Random.value។ បង្កើតលេខជាក់លាក់តែមួយ (អណ្តែត) ក្នុងចន្លោះពី [0; ១).
  5. Unity.Mathematics.Random.NextFloat(). ផ្នែកនៃបណ្ណាល័យ Unity.Mathematics ថ្មី។ បង្កើតលេខជាក់លាក់តែមួយ (អណ្តែត) ក្នុងជួរតម្លៃដែលបានផ្តល់ឱ្យ។

ស្ទើរតែគ្រប់ទីកន្លែងនៅក្នុងឯកសារ ការចែកចាយឯកសណ្ឋានត្រូវបានបញ្ជាក់ លើកលែងតែ UnityEngine.Random.value (ដែលការចែកចាយមិនត្រូវបានបញ្ជាក់ ប៉ុន្តែដោយការប្រៀបធៀបជាមួយ UnityEngine.Random.Range() ឯកសណ្ឋានក៏ត្រូវបានរំពឹងទុក) និង Unity.Mathematics.Random .NextFloat() (ដែលនៅក្នុងមូលដ្ឋានគឺ xorshift algorithm ដែលមានន័យថាម្តងទៀតអ្នកត្រូវរង់ចាំការចែកចាយឯកសណ្ឋាន)។

តាមលំនាំដើម លទ្ធផលដែលរំពឹងទុកត្រូវបានយកដូចដែលបានបញ្ជាក់នៅក្នុងឯកសារ។

វិធីសាស្រ្ត

យើងបានសរសេរកម្មវិធីតូចមួយដែលបង្កើតលំដាប់នៃលេខចៃដន្យដោយប្រើវិធីសាស្រ្តនីមួយៗដែលបានបង្ហាញ ហើយរក្សាទុកលទ្ធផលសម្រាប់ដំណើរការបន្ថែម។

ប្រវែងនៃលំដាប់នីមួយៗគឺ 100 លេខ។
ជួរនៃលេខចៃដន្យគឺ [0, 100) ។

ទិន្នន័យត្រូវបានប្រមូលពីវេទិកាគោលដៅជាច្រើន៖

  • ប្រព័ន្ធប្រតិបត្តិការ Windows
    — Unity v2018.3.14f1, របៀបកម្មវិធីនិពន្ធ, Mono, .NET Standard 2.0
  • MacOS
    — Unity v2018.3.14f1, របៀបកម្មវិធីនិពន្ធ, Mono, .NET Standard 2.0
    — Unity v5.6.4p4, របៀបកម្មវិធីនិពន្ធ, Mono, .NET Standard 2.0
  • ប្រព័ន្ធប្រតិបត្តិការ Android
    — Unity v2018.3.14f1, build per device, Mono, .NET Standard 2.0
  • ប្រព័ន្ធប្រតិបត្តិការ iOS
    — Unity v2018.3.14f1, build per device, il2cpp, .NET Standard 2.0

Реализация

យើងមានវិធីផ្សេងគ្នាជាច្រើនដើម្បីបង្កើតលេខចៃដន្យ។ សម្រាប់ពួកវានីមួយៗ យើងនឹងសរសេរថ្នាក់រុំដាច់ដោយឡែក ដែលគួរផ្តល់ៈ

  1. លទ្ធភាព​ក្នុង​ការ​កំណត់​ជួរ​តម្លៃ [min/max)។ នឹងត្រូវបានកំណត់តាមរយៈអ្នកសាងសង់។
  2. វិធីសាស្រ្តត្រឡប់ MF ។ ចូរ​ជ្រើសរើស​បណ្តែត​តាម​ប្រភេទ ព្រោះ​វា​ទូទៅ​ជាង។
  3. ឈ្មោះនៃវិធីសាស្រ្តជំនាន់សម្រាប់សម្គាល់លទ្ធផល។ ដើម្បីភាពងាយស្រួល យើងនឹងត្រឡប់ជាតម្លៃឈ្មោះពេញនៃថ្នាក់ + ឈ្មោះវិធីសាស្ត្រដែលប្រើដើម្បីបង្កើត MF ។

ជាដំបូង ចូរយើងប្រកាសនូវ abstraction ដែលនឹងត្រូវបានតំណាងដោយ IRandomGenerator interface៖

namespace RandomDistribution
{
    public interface IRandomGenerator
    {
        string Name { get; }

        float Generate();
    }
}

ការអនុវត្ត System.Random.Next()

វិធីសាស្ត្រនេះអនុញ្ញាតឱ្យអ្នកកំណត់ជួរតម្លៃ ប៉ុន្តែវាត្រឡប់ចំនួនគត់ ប៉ុន្តែអណ្តែតគឺត្រូវការ។ អ្នកអាចបកស្រាយចំនួនគត់ជាអណ្តែត ឬអ្នកអាចពង្រីកជួរនៃតម្លៃដោយលំដាប់ជាច្រើននៃរ៉ិចទ័រ ដោយផ្តល់សំណងដល់ពួកគេជាមួយនឹងជំនាន់នីមួយៗនៃមធ្យមភាគ។ លទ្ធផល​នឹង​មាន​ដូច​ជា​ចំណុច​ថេរ​ដែល​មាន​លំដាប់​នៃ​ភាព​ត្រឹមត្រូវ។ យើង​នឹង​ប្រើ​ជម្រើស​នេះ​ព្រោះ​វា​ខិត​ទៅ​ជិត​តម្លៃ​អណ្តែត​ពិត។

using System;

namespace RandomDistribution
{
    public class SystemIntegerRandomGenerator : IRandomGenerator
    {
        private const int DefaultFactor = 100000;
        
        private readonly Random _generator = new Random();
        private readonly int _min;
        private readonly int _max;
        private readonly int _factor;


        public string Name => "System.Random.Next()";


        public SystemIntegerRandomGenerator(float min, float max, int factor = DefaultFactor)
        {
            _min = (int)min * factor;
            _max = (int)max * factor;
            _factor = factor;
        }


        public float Generate() => (float)_generator.Next(_min, _max) / _factor;
    }
}

ការអនុវត្ត System.Random.NextDouble()

នៅទីនេះជួរថេរនៃតម្លៃ [0; ១). ដើម្បីបញ្ចាំងវាទៅលើអ្វីដែលបានបញ្ជាក់នៅក្នុង constructor យើងប្រើនព្វន្ធសាមញ្ញ៖ X * (max − min) + min ។

using System;

namespace RandomDistribution
{
    public class SystemDoubleRandomGenerator : IRandomGenerator
    {
        private readonly Random _generator = new Random();
        private readonly double _factor;
        private readonly float _min;


        public string Name => "System.Random.NextDouble()";


        public SystemDoubleRandomGenerator(float min, float max)
        {
            _factor = max - min;
            _min = min;
        }


        public float Generate() => (float)(_generator.NextDouble() * _factor) + _min;
    }
}

ការអនុវត្ត UnityEngine.Random.Range()

វិធីសាស្រ្តនៃថ្នាក់ឋិតិវន្ត UnityEngine.Random នេះអនុញ្ញាតឱ្យអ្នកកំណត់ជួរនៃតម្លៃ និងត្រឡប់ប្រភេទអណ្តែត។ អ្នកមិនចាំបាច់ធ្វើការផ្លាស់ប្តូរបន្ថែមទេ។

using UnityEngine;

namespace RandomDistribution
{
    public class UnityRandomRangeGenerator : IRandomGenerator
    {
        private readonly float _min;
        private readonly float _max;


        public string Name => "UnityEngine.Random.Range()";


        public UnityRandomRangeGenerator(float min, float max)
        {
            _min = min;
            _max = max;
        }


        public float Generate() => Random.Range(_min, _max);
    }
}

ការអនុវត្ត UnityEngine.Random.value

លក្ខណៈសម្បត្តិតម្លៃនៃថ្នាក់ឋិតិវន្ត UnityEngine.Random ត្រឡប់ប្រភេទអណ្តែតពីជួរតម្លៃថេរ [0; ១). ចូរ​យើង​ដាក់​គម្រោង​វា​ទៅ​លើ​ជួរ​ដែល​បាន​ផ្តល់​ឱ្យ​ក្នុង​វិធី​ដូច​គ្នា​នឹង​ពេល​អនុវត្ត System.Random.NextDouble()។

using UnityEngine;

namespace RandomDistribution
{
    public class UnityRandomValueGenerator : IRandomGenerator
    {
        private readonly float _factor;
        private readonly float _min;


        public string Name => "UnityEngine.Random.value";


        public UnityRandomValueGenerator(float min, float max)
        {
            _factor = max - min;
            _min = min;
        }


        public float Generate() => (float)(Random.value * _factor) + _min;
    }
}

ការអនុវត្ត Unity.Mathematics.Random.NextFloat()

វិធីសាស្ត្រ NextFloat() នៃថ្នាក់ Unity.Mathematics.Random ត្រឡប់ចំណុចអណ្តែតនៃប្រភេទ float និងអនុញ្ញាតឱ្យអ្នកបញ្ជាក់ជួរនៃតម្លៃ។ ភាពខុសប្លែកគ្នាតែមួយគត់គឺថាឧទាហរណ៍នីមួយៗនៃ Unity.Mathematics.Random នឹងត្រូវចាប់ផ្តើមជាមួយគ្រាប់ពូជមួយចំនួន - វិធីនេះយើងនឹងជៀសវាងការបង្កើតលំដាប់ដដែលៗ។

using Unity.Mathematics;

namespace RandomDistribution
{
    public class UnityMathematicsRandomValueGenerator : IRandomGenerator
    {
        private Random _generator;
        private readonly float _min;
        private readonly float _max;


        public string Name => "Unity.Mathematics.Random.NextFloat()";


        public UnityMathematicsRandomValueGenerator(float min, float max)
        {
            _min = min;
            _max = max;
            _generator = new Random();
            _generator.InitState(unchecked((uint)System.DateTime.Now.Ticks));
        }


        public float Generate() => _generator.NextFloat(_min, _max);
    }
}

ការអនុវត្ត MainController

ការអនុវត្តជាច្រើននៃ IRandomGenerator គឺរួចរាល់ហើយ។ បន្ទាប់មកអ្នកត្រូវបង្កើតលំដាប់ និងរក្សាទុកសំណុំទិន្នន័យលទ្ធផលសម្រាប់ដំណើរការ។ ដើម្បីធ្វើដូច្នេះ យើងនឹងបង្កើតឈុតមួយ និងស្គ្រីប MainController តូចមួយនៅក្នុង Unity ដែលនឹងធ្វើការងារចាំបាច់ទាំងអស់ ហើយក្នុងពេលតែមួយទទួលខុសត្រូវចំពោះអន្តរកម្មជាមួយ UI ។

ចូរកំណត់ទំហំនៃសំណុំទិន្នន័យ និងជួរនៃតម្លៃ MF ហើយក៏ទទួលបានវិធីសាស្ត្រដែលត្រឡប់អារេនៃម៉ាស៊ីនភ្លើងដែលបានកំណត់រចនាសម្ព័ន្ធ និងរួចរាល់ដើម្បីដំណើរការ។

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        private const int DefaultDatasetSize = 100000;

        public float MinValue = 0f;
        public float MaxValue = 100f;

        ...

        private IRandomGenerator[] CreateRandomGenerators()
        {
            return new IRandomGenerator[]
            {
                new SystemIntegerRandomGenerator(MinValue, MaxValue),
                new SystemDoubleRandomGenerator(MinValue, MaxValue),
                new UnityRandomRangeGenerator(MinValue, MaxValue),
                new UnityRandomValueGenerator(MinValue, MaxValue),
                new UnityMathematicsRandomValueGenerator(MinValue, MaxValue)
            };
        }

        ...
    }
}

ឥឡូវ​យើង​បង្កើត​សំណុំ​ទិន្នន័យ។ ក្នុងករណីនេះ ការបង្កើតទិន្នន័យនឹងត្រូវបានផ្សំជាមួយនឹងការកត់ត្រាលទ្ធផលទៅក្នុងស្ទ្រីមអត្ថបទ (ក្នុងទម្រង់ csv)។ ដើម្បីរក្សាទុកតម្លៃនៃ IRandomGenerator នីមួយៗ ជួរឈរដាច់ដោយឡែករបស់វាត្រូវបានបែងចែក ហើយជួរទីមួយមាន ឈ្មោះរបស់ម៉ាស៊ីនភ្លើង។

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        ...
		
        private void GenerateCsvDataSet(TextWriter writer, int dataSetSize, params IRandomGenerator[] generators)
        {
            const char separator = ',';
            int lastIdx = generators.Length - 1;

            // write header
            for (int j = 0; j <= lastIdx; j++)
            {
                writer.Write(generators[j].Name);
                if (j != lastIdx)
                    writer.Write(separator);
            }
            writer.WriteLine();

            // write data
            for (int i = 0; i <= dataSetSize; i++)
            {
                for (int j = 0; j <= lastIdx; j++)
                {
                    writer.Write(generators[j].Generate());
                    if (j != lastIdx)
                        writer.Write(separator);
                }

                if (i != dataSetSize)
                    writer.WriteLine();
            }
        }

        ...
    }
}

អ្វីដែលនៅសេសសល់គឺត្រូវហៅវិធីសាស្ត្រ GenerateCsvDataSet ហើយរក្សាទុកលទ្ធផលទៅក្នុងឯកសារ ឬផ្ទេរទិន្នន័យភ្លាមៗតាមបណ្តាញពីឧបករណ៍ចុងទៅម៉ាស៊ីនមេ។

namespace RandomDistribution
{
    public class MainController : MonoBehaviour
    {
        ...
		
        public void GenerateCsvDataSet(string path, int dataSetSize, params IRandomGenerator[] generators)
        {
            using (var writer = File.CreateText(path))
            {
                GenerateCsvDataSet(writer, dataSetSize, generators);
            }
        }


        public string GenerateCsvDataSet(int dataSetSize, params IRandomGenerator[] generators)
        {
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                GenerateCsvDataSet(writer, dataSetSize, generators);
                return writer.ToString();
            }
        }

        ...
    }
}

ប្រភពគម្រោងគឺនៅ GitLab.

Результаты

គ្មានអព្ភូតហេតុកើតឡើងទេ។ អ្វី​ដែល​ពួក​គេ​បាន​រំពឹង​ទុក​គឺ​ជា​អ្វី​ដែល​ពួក​គេ​ទទួល​បាន - ក្នុង​គ្រប់​ករណី​ទាំង​អស់ ការ​ចែក​ចាយ​ដោយ​មិន​មាន​តម្រុយ​ពី​ការ​សមគំនិត។ ខ្ញុំ​មិន​ឃើញ​ចំណុច​ក្នុង​ការ​ដាក់​ក្រាហ្វ​ដាច់​ដោយ​ឡែក​សម្រាប់​វេទិកា​នោះ​ទេ - ពួកគេ​ទាំង​អស់​បង្ហាញ​លទ្ធផល​ប្រហែល​គ្នា។

ការពិតគឺនេះ៖
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌

ការមើលឃើញនៃលំដាប់នៅលើយន្តហោះពីវិធីសាស្រ្តទាំងប្រាំជំនាន់៖
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌

និងការមើលឃើញជា 3D ។ ខ្ញុំ​នឹង​ទុក​តែ​លទ្ធផល​នៃ System.Random.Next() ដើម្បី​កុំ​ឲ្យ​មាន​ខ្លឹមសារ​ដូចគ្នា​បេះបិទ។
BlessRNG ឬពិនិត្យមើល RNG ដើម្បីយុត្តិធម៌

រឿងដែលបានប្រាប់នៅក្នុងការណែនាំអំពីការចែកចាយធម្មតារបស់ UnityEngine.Random មិនបាននិយាយឡើងវិញដោយខ្លួនឯងទេ៖ ទាំងដំបូងគឺខុស ឬអ្វីមួយបានផ្លាស់ប្តូរនៅក្នុងម៉ាស៊ីន។ ប៉ុន្តែឥឡូវនេះយើងប្រាកដ។

ប្រភព: www.habr.com

បន្ថែមមតិយោបល់