នៅក្នុងការអភិវឌ្ឍន៍ហ្គេម ជារឿយៗអ្នកត្រូវភ្ជាប់អ្វីមួយជាមួយនឹងភាពចៃដន្យ៖ Unity មាន Random ផ្ទាល់ខ្លួនសម្រាប់រឿងនេះ ហើយស្របគ្នាជាមួយនឹងវាមាន System.Random ។ នៅពេលមួយ នៅលើគម្រោងមួយ ខ្ញុំទទួលបានចំណាប់អារម្មណ៍ថា ទាំងពីរអាចដំណើរការខុសគ្នា (ទោះបីជាពួកគេគួរតែមានការចែកចាយដូចគ្នាក៏ដោយ)។
បន្ទាប់មកពួកគេមិនបានចូលទៅក្នុងព័ត៌មានលម្អិតទេ - វាគ្រប់គ្រាន់ហើយដែលការផ្លាស់ប្តូរទៅ System.Random បានដោះស្រាយបញ្ហាទាំងអស់។ ឥឡូវនេះ យើងបានសម្រេចចិត្តពិនិត្យមើលវាឱ្យកាន់តែលម្អិត និងធ្វើការស្រាវជ្រាវបន្តិចបន្តួច៖ តើ RNGs "លំអៀង" ឬអាចព្យាករណ៍បាន និងមួយណាដែលត្រូវជ្រើសរើស។ ជាងនេះទៅទៀត ខ្ញុំបានឮច្រើនជាងម្តងនូវមតិផ្ទុយគ្នាអំពី "ភាពស្មោះត្រង់" របស់ពួកគេ - ចូរយើងព្យាយាមស្វែងយល់ពីរបៀបដែលលទ្ធផលពិតប្រៀបធៀបជាមួយនឹងអ្នកដែលបានប្រកាស។
កម្មវិធីអប់រំខ្លីៗ ឬ RNG គឺពិតជា RNG
ប្រសិនបើអ្នកធ្លាប់ស្គាល់ឧបករណ៍បង្កើតលេខចៃដន្យរួចហើយ អ្នកអាចរំលងទៅផ្នែក "ការសាកល្បង" ភ្លាមៗ។
លេខចៃដន្យ (RN) គឺជាលំដាប់នៃលេខដែលបានបង្កើតដោយប្រើដំណើរការចៃដន្យ (វឹកវរ) ដែលជាប្រភពនៃ entropy ។ នោះគឺនេះគឺជាលំដាប់ដែលធាតុរបស់ពួកគេមិនត្រូវបានទាក់ទងគ្នាដោយច្បាប់គណិតវិទ្យាណាមួយឡើយ - ពួកគេមិនមានទំនាក់ទំនងមូលហេតុនិងឥទ្ធិពលទេ។
អ្វីដែលបង្កើតលេខចៃដន្យត្រូវបានគេហៅថា random number generator (RNG)។ វាហាក់ដូចជាថាអ្វីគ្រប់យ៉ាងគឺបឋម ប៉ុន្តែប្រសិនបើយើងផ្លាស់ប្តូរពីទ្រឹស្ដីទៅការអនុវត្ត នោះតាមពិតវាមិនសាមញ្ញទេក្នុងការអនុវត្ត algorithm កម្មវិធីសម្រាប់បង្កើតលំដាប់បែបនេះ។
ហេតុផលគឺអវត្តមាននៃភាពវឹកវរដូចគ្នានៅក្នុងគ្រឿងអេឡិចត្រូនិកទំនើប។ បើគ្មានវាទេ លេខចៃដន្យឈប់ជាចៃដន្យ ហើយម៉ាស៊ីនភ្លើងរបស់វាប្រែទៅជាមុខងារធម្មតានៃអាគុយម៉ង់ដែលបានកំណត់យ៉ាងច្បាស់។ សម្រាប់ជំនាញឯកទេសមួយចំនួនក្នុងវិស័យ IT នេះគឺជាបញ្ហាធ្ងន់ធ្ងរ (ឧទាហរណ៍ គ្រីបគ្រីប) ប៉ុន្តែសម្រាប់អ្នកផ្សេងទៀតមានដំណោះស្រាយដែលអាចទទួលយកបានទាំងស្រុង។
វាចាំបាច់ក្នុងការសរសេរក្បួនដោះស្រាយដែលនឹងត្រលប់មកវិញ ទោះបីជាមិនមែនជាលេខចៃដន្យក៏ដោយ ប៉ុន្តែឱ្យជិតបំផុតតាមដែលអាចធ្វើទៅបាន - ដែលគេហៅថាលេខចៃដន្យ (PRN) ។ ក្បួនដោះស្រាយក្នុងករណីនេះត្រូវបានគេហៅថា pseudorandom number generator (PRNG) ។
មានជម្រើសជាច្រើនសម្រាប់បង្កើត PRNG ប៉ុន្តែខាងក្រោមនេះនឹងពាក់ព័ន្ធសម្រាប់អ្នករាល់គ្នា៖
- តម្រូវការសម្រាប់ការចាប់ផ្តើមបឋម។
PRNG មិនមានប្រភពនៃ entropy ទេ ដូច្នេះវាត្រូវតែផ្តល់ស្ថានភាពដំបូងមុនពេលប្រើប្រាស់។ វាត្រូវបានបញ្ជាក់ជាលេខ (ឬវ៉ិចទ័រ) ហើយត្រូវបានគេហៅថាគ្រាប់ពូជ (គ្រាប់ពូជចៃដន្យ) ។ ជាញឹកញាប់ ឧបករណ៍រាប់នាឡិកាដំណើរការ ឬសមមូលជាលេខនៃម៉ោងប្រព័ន្ធត្រូវបានប្រើជាគ្រាប់ពូជ។
- ការបន្តពូជតាមលំដាប់។
PRNG ត្រូវបានកំណត់ទាំងស្រុង ដូច្នេះគ្រាប់ពូជដែលបានបញ្ជាក់ក្នុងអំឡុងពេលចាប់ផ្តើមដំបូងកំណត់ដោយឡែកពីលំដាប់នៃលេខនាពេលអនាគតទាំងមូល។ នេះមានន័យថា PRNG ដាច់ដោយឡែកដែលបានចាប់ផ្តើមជាមួយគ្រាប់ពូជដូចគ្នា (នៅពេលផ្សេងគ្នា ក្នុងកម្មវិធីផ្សេងគ្នា នៅលើឧបករណ៍ផ្សេងគ្នា) នឹងបង្កើតលំដាប់ដូចគ្នា។
អ្នកក៏ត្រូវដឹងពីការចែកចាយប្រូបាប៊ីលីតេដែលកំណត់លក្ខណៈ PRNG - តើលេខអ្វីដែលវានឹងបង្កើត និងជាមួយនឹងប្រូបាប៊ីលីតេអ្វី។ ភាគច្រើនជាញឹកញាប់នេះគឺជាការចែកចាយធម្មតា ឬការចែកចាយឯកសណ្ឋាន។
ការចែកចាយធម្មតា (ឆ្វេង) និងការចែកចាយឯកសណ្ឋាន (ស្តាំ)
ឧបមាថាយើងមានការស្លាប់ដោយយុត្តិធម៌ដែលមាន 24 ជ្រុង។ ប្រសិនបើអ្នកបោះវា ប្រូបាប៊ីលីតេនៃការទទួលបានលេខមួយនឹងស្មើនឹង 1/24 (ដូចគ្នានឹងប្រូបាប៊ីលីតេនៃការទទួលបានលេខផ្សេងទៀត)។ ប្រសិនបើអ្នកធ្វើការបោះច្រើន និងកត់ត្រាលទ្ធផល អ្នកនឹងសម្គាល់ឃើញថាគែមទាំងអស់ធ្លាក់ចេញជាមួយនឹងប្រេកង់ប្រហាក់ប្រហែលគ្នា។ សំខាន់ ការស្លាប់នេះអាចត្រូវបានចាត់ទុកថាជា RNG ជាមួយនឹងការចែកចាយឯកសណ្ឋាន។
ចុះបើអ្នកបោះគ្រាប់ឡុកឡាក់ទាំង 10 គ្រាប់ក្នុងពេលតែមួយ ហើយរាប់ពិន្ទុសរុប? តើឯកសណ្ឋាននឹងត្រូវបានរក្សាសម្រាប់វាទេ? ទេ ភាគច្រើនជាញឹកញាប់ ចំនួនទឹកប្រាក់នឹងនៅជិត 125 ពិន្ទុ ពោលគឺដល់តម្លៃមធ្យមមួយចំនួន។ ហើយជាលទ្ធផល សូម្បីតែមុនពេលបោះចោល អ្នកអាចប៉ាន់ប្រមាណលទ្ធផលនាពេលអនាគត
ហេតុផលគឺថាមានចំនួនច្រើនបំផុតនៃបន្សំដើម្បីទទួលបានពិន្ទុមធ្យម។ កាន់តែឆ្ងាយពីវា បន្សំតិច - ហើយតាមនោះ ប្រូបាប៊ីលីតេនៃការបាត់បង់កាន់តែទាប។ ប្រសិនបើទិន្នន័យនេះត្រូវបានគេមើលឃើញ វានឹងប្រហាក់ប្រហែលនឹងរូបរាងរបស់កណ្តឹង។ ដូច្នេះជាមួយនឹងការលាតសន្ធឹងខ្លះ ប្រព័ន្ធនៃគ្រាប់ឡុកឡាក់ចំនួន 10 អាចត្រូវបានគេហៅថា RNG ជាមួយនឹងការចែកចាយធម្មតា។
ឧទាហរណ៍មួយទៀតមានតែលើកនេះទេនៅលើយន្តហោះ - បាញ់ចំគោលដៅ។ អ្នកបាញ់នឹងក្លាយជា RNG ដែលបង្កើតលេខគូ (x, y) ដែលត្រូវបានបង្ហាញនៅលើក្រាហ្វ។
យល់ស្របថាជម្រើសនៅខាងឆ្វេងគឺខិតទៅជិតជីវិតពិត - នេះគឺជា 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 ១៨, ៥៨, ៧៩, ៦៥, ៤៥, ៩៩, ៩០, ៨២, ២០, ៤១, ១៣, ៨៨, ៧៦, ៨២, ២៤, ៥, ៥៤, ៧២, ១៩, ៨០, ២, ៧៤, ៣៦, ៧១, ៩, ...
តើលេខទាំងនេះចៃដន្យប៉ុណ្ណានៅក្រឡេកមើលដំបូង? ចូរចាប់ផ្តើមដោយពិនិត្យមើលការចែកចាយ។
វាមើលទៅជិតឯកសណ្ឋាន ប៉ុន្តែប្រសិនបើអ្នកអានលំដាប់នៃលេខពីរ ហើយបកស្រាយពួកវាជាកូអរដោណេនៅលើយន្តហោះ អ្នកនឹងទទួលបានចំណុចនេះ៖
លំនាំអាចមើលឃើញយ៉ាងច្បាស់។ ហើយចាប់តាំងពីទិន្នន័យនៅក្នុងលំដាប់ត្រូវបានតម្រៀបតាមវិធីជាក់លាក់មួយ (នោះគឺវាមាន 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 ១៨, ៥៨, ៧៩, ៦៥, ៤៥, ៩៩, ៩០, ៨២, ២០, ៤១, ១៣, ៨៨, ៧៦, ៨២, ២៤, ៥, ៥៤, ៧២, ១៩, ៨០, ២, ៧៤, ៣៦, ៧១, ៩, ...
អ្វីៗហាក់ដូចជាល្អនៅទីនេះ សូម្បីតែនៅលើយន្តហោះក៏ដោយ៖
តោះមើលបរិមាណ (អានបីលេខក្នុងពេលតែមួយ)៖
ហើយម្តងទៀតលំនាំ។ វាមិនអាចបង្កើតការមើលឃើញជាបួនវិមាត្របានទេ។ ប៉ុន្តែគំរូអាចមាននៅលើវិមាត្រនេះ និងនៅលើទំហំធំជាងនេះ។
នៅក្នុងការគ្រីបគ្រីប ដែលតម្រូវការតឹងរ៉ឹងបំផុតត្រូវបានដាក់លើ PRNGs ស្ថានភាពបែបនេះមិនអាចទទួលយកបានតាមប្រភេទទេ។ ដូច្នេះ ក្បួនដោះស្រាយពិសេសត្រូវបានបង្កើតឡើងដើម្បីវាយតម្លៃគុណភាពរបស់វា ដែលយើងនឹងមិនប៉ះពាល់នៅពេលនេះទេ។ ប្រធានបទគឺទូលំទូលាយ ហើយសមនឹងទទួលបានអត្ថបទដាច់ដោយឡែកមួយ។
សាកល្បង
បើយើងមិនដឹងអ្វីឲ្យប្រាកដ តើត្រូវធ្វើយ៉ាងណា? តើវាសមនឹងការឆ្លងកាត់ផ្លូវទេ ប្រសិនបើអ្នកមិនដឹងថាភ្លើងចរាចរណ៍មួយណាអនុញ្ញាត? ផលវិបាកអាចខុសគ្នា។
ដូចគ្នាដែរចំពោះភាពចៃដន្យដ៏ល្បីនៅក្នុង Unity។ ជាការល្អប្រសិនបើឯកសារបង្ហាញព័ត៌មានលម្អិតចាំបាច់ ប៉ុន្តែរឿងរ៉ាវដែលបានលើកឡើងនៅដើមអត្ថបទនេះបានកើតឡើងយ៉ាងជាក់លាក់ដោយសារតែខ្វះភាពជាក់លាក់ដែលចង់បាន។
ហើយប្រសិនបើអ្នកមិនដឹងពីរបៀបដែលឧបករណ៍នេះដំណើរការ អ្នកនឹងមិនអាចប្រើវាបានត្រឹមត្រូវទេ។ ជាទូទៅ ដល់ពេលដែលត្រូវពិនិត្យ និងធ្វើការពិសោធន៍ ដើម្បីប្រាកដថាយ៉ាងហោចណាស់មានការចែកចាយ។
ដំណោះស្រាយគឺសាមញ្ញ និងមានប្រសិទ្ធភាព - ប្រមូលស្ថិតិ ទទួលបានទិន្នន័យគោលបំណង និងមើលលទ្ធផល។
ប្រធានបទនៃការសិក្សា
មានវិធីជាច្រើនដើម្បីបង្កើតលេខចៃដន្យនៅក្នុង Unity - យើងបានសាកល្បងប្រាំ។
- System.Random.Next(). បង្កើតចំនួនគត់ក្នុងជួរតម្លៃដែលបានផ្តល់ឱ្យ។
- System.Random.NextDouble(). បង្កើតលេខភាពជាក់លាក់ពីរដងក្នុងចន្លោះពី [0; ១).
- UnityEngine.Random.Range(). បង្កើតលេខជាក់លាក់តែមួយ (អណ្តែត) ក្នុងជួរតម្លៃដែលបានផ្តល់ឱ្យ។
- UnityEngine.Random.value។ បង្កើតលេខជាក់លាក់តែមួយ (អណ្តែត) ក្នុងចន្លោះពី [0; ១).
- 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
Реализация
យើងមានវិធីផ្សេងគ្នាជាច្រើនដើម្បីបង្កើតលេខចៃដន្យ។ សម្រាប់ពួកវានីមួយៗ យើងនឹងសរសេរថ្នាក់រុំដាច់ដោយឡែក ដែលគួរផ្តល់ៈ
- លទ្ធភាពក្នុងការកំណត់ជួរតម្លៃ [min/max)។ នឹងត្រូវបានកំណត់តាមរយៈអ្នកសាងសង់។
- វិធីសាស្រ្តត្រឡប់ MF ។ ចូរជ្រើសរើសបណ្តែតតាមប្រភេទ ព្រោះវាទូទៅជាង។
- ឈ្មោះនៃវិធីសាស្រ្តជំនាន់សម្រាប់សម្គាល់លទ្ធផល។ ដើម្បីភាពងាយស្រួល យើងនឹងត្រឡប់ជាតម្លៃឈ្មោះពេញនៃថ្នាក់ + ឈ្មោះវិធីសាស្ត្រដែលប្រើដើម្បីបង្កើត 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();
}
}
...
}
}
ប្រភពគម្រោងគឺនៅ
Результаты
គ្មានអព្ភូតហេតុកើតឡើងទេ។ អ្វីដែលពួកគេបានរំពឹងទុកគឺជាអ្វីដែលពួកគេទទួលបាន - ក្នុងគ្រប់ករណីទាំងអស់ ការចែកចាយដោយមិនមានតម្រុយពីការសមគំនិត។ ខ្ញុំមិនឃើញចំណុចក្នុងការដាក់ក្រាហ្វដាច់ដោយឡែកសម្រាប់វេទិកានោះទេ - ពួកគេទាំងអស់បង្ហាញលទ្ធផលប្រហែលគ្នា។
ការពិតគឺនេះ៖
ការមើលឃើញនៃលំដាប់នៅលើយន្តហោះពីវិធីសាស្រ្តទាំងប្រាំជំនាន់៖
និងការមើលឃើញជា 3D ។ ខ្ញុំនឹងទុកតែលទ្ធផលនៃ System.Random.Next() ដើម្បីកុំឲ្យមានខ្លឹមសារដូចគ្នាបេះបិទ។
រឿងដែលបានប្រាប់នៅក្នុងការណែនាំអំពីការចែកចាយធម្មតារបស់ UnityEngine.Random មិនបាននិយាយឡើងវិញដោយខ្លួនឯងទេ៖ ទាំងដំបូងគឺខុស ឬអ្វីមួយបានផ្លាស់ប្តូរនៅក្នុងម៉ាស៊ីន។ ប៉ុន្តែឥឡូវនេះយើងប្រាកដ។
ប្រភព: www.habr.com