मैं एक भारित संग्रह कैसे बनाऊं और फिर उसमें से एक यादृच्छिक तत्व चुनूं?


34

मेरे पास एक लूट बॉक्स है जिसे मैं एक यादृच्छिक आइटम के साथ भरना चाहता हूं। लेकिन मैं चाहता हूं कि प्रत्येक आइटम को उठाया जाने का एक अलग मौका मिले। उदाहरण के लिए:

  • 10 गोल्ड का 5% मौका
  • तलवार का 20% मौका
  • ढाल का 45% मौका
  • कवच का 20% मौका
  • 10% पोशन की संभावना

मैं इसे कैसे बना सकता हूं ताकि मैं उपरोक्त वस्तुओं में से एक का चयन करूं, जहां उन प्रतिशतों में लूट होने की संभावना है?


1
FYI करें, सिद्धांत रूप में, O (1) प्रति नमूना समय किसी भी परिमित वितरण के लिए संभव है, यहां तक ​​कि एक वितरण जिसकी प्रविष्टियां गतिशील रूप से बदलती हैं। उदाहरण के लिए देखें cstheory.stackexchange.com/questions/37648/…
नील युवा

जवाबों:


37

नरम कोडित संभाव्यता समाधान

हार्डकोड किए गए प्रायिकता समाधान के नुकसान हैं जो आपको अपने कोड में संभावनाओं को सेट करने की आवश्यकता है। आप उन्हें रनटाइम पर निर्धारित नहीं कर सकते। इसे बनाए रखना भी कठिन है।

यहाँ उसी एल्गोरिथ्म का एक गतिशील संस्करण है।

  1. प्रत्येक आइटम की वास्तविक वस्तुओं और वजन के जोड़े की एक सरणी बनाएं
  2. जब आप एक आइटम जोड़ते हैं, तो आइटम के वजन का अपना वजन होना चाहिए और पहले से ही सरणी में सभी वस्तुओं के वजन का योग। इसलिए आपको अलग से राशि ट्रैक करनी चाहिए। खासकर क्योंकि आपको अगले चरण के लिए इसकी आवश्यकता होगी।
  3. किसी वस्तु को पुनः प्राप्त करने के लिए, 0 और सभी वस्तुओं के भार के बीच एक यादृच्छिक संख्या उत्पन्न करें
  4. शुरू से अंत तक सरणी को तब तक व्यवस्थित करें जब तक कि आप एक वजन के साथ एक प्रविष्टि नहीं पाते या यादृच्छिक संख्या से बराबर

यहां टेम्प्लेट क्लास के रूप में जावा में एक नमूना कार्यान्वयन है जिसे आप अपने खेल के उपयोग के लिए किसी भी वस्तु के लिए तुरंत कर सकते हैं। फिर आप ऑब्जेक्ट को विधि के साथ जोड़ सकते हैं .addEntry(object, relativeWeight)और उन प्रविष्टियों में से एक चुन सकते हैं जिन्हें आपने पहले जोड़ा था.get()

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class WeightedRandomBag<T extends Object> {

    private class Entry {
        double accumulatedWeight;
        T object;
    }

    private List<Entry> entries = new ArrayList<>();
    private double accumulatedWeight;
    private Random rand = new Random();

    public void addEntry(T object, double weight) {
        accumulatedWeight += weight;
        Entry e = new Entry();
        e.object = object;
        e.accumulatedWeight = accumulatedWeight;
        entries.add(e);
    }

    public T getRandom() {
        double r = rand.nextDouble() * accumulatedWeight;

        for (Entry entry: entries) {
            if (entry.accumulatedWeight >= r) {
                return entry.object;
            }
        }
        return null; //should only happen when there are no entries
    }
}

उपयोग:

WeightedRandomBag<String> itemDrops = new WeightedRandomBag<>();

// Setup - a real game would read this information from a configuration file or database
itemDrops.addEntry("10 Gold",  5.0);
itemDrops.addEntry("Sword",   20.0);
itemDrops.addEntry("Shield",  45.0);
itemDrops.addEntry("Armor",   20.0);
itemDrops.addEntry("Potion",  10.0);

// drawing random entries from it
for (int i = 0; i < 20; i++) {
    System.out.println(itemDrops.getRandom());
}

यहाँ आपकी एकता, XNA या मोनोमेग परियोजना के लिए C # में समान श्रेणी लागू की गई है :

using System;
using System.Collections.Generic;

class WeightedRandomBag<T>  {

    private struct Entry {
        public double accumulatedWeight;
        public T item;
    }

    private List<Entry> entries = new List<Entry>();
    private double accumulatedWeight;
    private Random rand = new Random();

    public void AddEntry(T item, double weight) {
        accumulatedWeight += weight;
        entries.Add(new Entry { item = item, accumulatedWeight = accumulatedWeight });
    }

    public T GetRandom() {
        double r = rand.NextDouble() * accumulatedWeight;

        foreach (Entry entry in entries) {
            if (entry.accumulatedWeight >= r) {
                return entry.item;
            }
        }
        return default(T); //should only happen when there are no entries
    }
}

और यहाँ जावास्क्रिप्ट में एक है :

var WeightedRandomBag = function() {

    var entries = [];
    var accumulatedWeight = 0.0;

    this.addEntry = function(object, weight) {
        accumulatedWeight += weight;
        entries.push( { object: object, accumulatedWeight: accumulatedWeight });
    }

    this.getRandom = function() {
        var r = Math.random() * accumulatedWeight;
        return entries.find(function(entry) {
            return entry.accumulatedWeight >= r;
        }).object;
    }   
}

समर्थक:

  • किसी भी वजन अनुपात को संभाल सकते हैं। यदि आप चाहते हैं तो सेट में खगोलीय रूप से छोटी संभावना वाले आइटम हो सकते हैं। वजन को भी 100 तक जोड़ने की जरूरत नहीं है।
  • आप रनटाइम पर आइटम और वज़न पढ़ सकते हैं
  • स्मृति उपयोग सरणी में आइटमों की संख्या के लिए आनुपातिक है

कॉन्ट्रा:

  • सही होने के लिए कुछ और प्रोग्रामिंग की आवश्यकता है
  • सबसे खराब स्थिति में, आपको पूरे सरणी ( O(n)रनटाइम जटिलता) को पुनरावृत्त करना पड़ सकता है । इसलिए जब आपके पास आइटम का एक बहुत बड़ा सेट होता है और बहुत बार आकर्षित होता है, तो यह धीमा हो सकता है। एक सरल अनुकूलन सबसे संभावित वस्तुओं को पहले रखना है ताकि एल्गोरिथ्म ज्यादातर मामलों में जल्दी समाप्त हो जाए। एक और अधिक जटिल अनुकूलन आप इस तथ्य का फायदा उठाने के लिए कर सकते हैं कि सरणी को सॉर्ट किया गया है और द्विभाषी खोज करें। इसमें केवल O(log n)समय लगता है।
  • आपको मेमोरी का उपयोग करने से पहले सूची बनाने की आवश्यकता होती है (हालाँकि आप रनटाइम में आसानी से आइटम जोड़ सकते हैं। हटाने वाली वस्तुओं को भी जोड़ा जा सकता है, लेकिन इसके लिए सभी वस्तुओं के संचित भार को अद्यतन करना होगा, जो हटाए गए प्रविष्टि के बाद आते हैं, जो फिर से O(n)सबसे खराब स्थिति है)

2
LINQ का उपयोग करके C # कोड लिखा जा सकता है: रिटर्न प्रविष्टियाँ। FirstOrDefault (e => e.accumulatedWeight> = r)। इससे भी महत्वपूर्ण बात यह है कि इस बात की थोड़ी संभावना है कि फ्लोटिंग पॉइंट प्रिसिजन लॉस के कारण यह अल्गोरिद्म अशक्त हो जाएगा यदि रैंडम वैल्यू संचित मूल्य से थोड़ा अधिक हो जाए। एहतियात के तौर पर, आप अंतिम तत्व में एक छोटा मान (कहते हैं, 1.0) जोड़ सकते हैं, लेकिन फिर आपको अपने कोड में स्पष्ट रूप से बताना होगा कि सूची अंतिम है।
आईएमआईएल

1
इस पर एक छोटा वैरिएंट मैंने व्यक्तिगत रूप से उपयोग किया है, यदि आप चाहते हैं कि रनटाइम में वेट वैल्यू को वेट-प्लस-ऑल-पिछले मूल्य में नहीं बदला जाए, तो आप अपने रैंडम वैल्यू से प्रत्येक पास की गई एंट्री के वज़न को घटा सकते हैं, जब यादृच्छिक मूल्य वर्तमान वस्तुओं के वजन से कम है (या जब वजन घटाना मूल्य बनाता है <0)
Lunin

2
@ BlueRaja-DannyPflughoeft प्रीमैच्योर ऑप्टिमाइज़ेशन ... सवाल एक ओपन लूट बॉक्स से ऑब्जेक्ट को चुनने के बारे में था। कौन प्रति सेकंड 1000 बक्से खोलने जा रहा है?
आईएमआईएल

4
@ आईआईएम: नहीं, प्रश्न एक सामान्य कैच है , जो यादृच्छिक भार वाली वस्तुओं के चयन के लिए है । लुटबॉक्स के लिए विशेष रूप से, यह उत्तर शायद ठीक है क्योंकि इसमें बहुत कम संख्या में आइटम हैं और संभावनाएं नहीं बदलती हैं (हालांकि, चूंकि वे आमतौर पर एक सर्वर पर किए जाते हैं, 1000 / सेकंड एक लोकप्रिय गेम के लिए अवास्तविक नहीं है)
ब्लूराजा - डैनी पफ्लुगुएफ्ट

4
@opa फिर एक डुबकी के रूप में बंद करने के लिए झंडा। क्या वास्तव में एक अच्छे उत्तर को गलत ठहराना सिर्फ इसलिए कि सवाल पहले पूछा गया है?
बाल्ड्रिक

27

नोट: मैंने इस सटीक समस्या के लिए एक C # लाइब्रेरी बनाई

अन्य समाधान ठीक हैं यदि आपके पास केवल कम संख्या में आइटम हैं और आपकी संभावनाएं कभी नहीं बदलती हैं। हालाँकि, बहुत सी वस्तुओं या बदलती संभावनाओं के साथ (उन्हें चुनने के बाद आइटम हटाना) , आप कुछ अधिक शक्तिशाली चाहते हैं।

यहां दो सबसे आम समाधान हैं (दोनों उपरोक्त पुस्तकालय में शामिल हैं)

वॉकर का उपनाम विधि

यदि आपकी संभावनाएं स्थिर हैं तो एक चतुर समाधान जो बहुत तेज़ ( O(1)!) है। संक्षेप में, एल्गोरिथ्म आपकी संभावनाओं से बाहर एक 2 डी डार्टबोर्ड ("उपनाम तालिका") बनाता है और इस पर एक डार्ट फेंकता है।

dartboard

ऑनलाइन लेख बहुत सारे हैं कि यह कैसे काम करता है यदि आप अधिक जानना चाहते हैं।

एकमात्र मुद्दा यह है कि यदि आपकी संभावनाएं बदलती हैं, तो आपको उपनाम तालिका को पुन: उत्पन्न करने की आवश्यकता है, जो धीमा है। इस प्रकार, यदि आपको सामान उठाने के बाद निकालने की आवश्यकता होती है, तो यह आपके लिए समाधान नहीं है।

वृक्ष आधारित समाधान

अन्य सामान्य समाधान यह है कि एक ऐसी सरणी बनाई जाए जहां प्रत्येक वस्तु अपनी संभाव्यता और उससे पहले की सभी वस्तुओं का योग जमा करे। फिर बस [0,1) से एक यादृच्छिक संख्या उत्पन्न करें और उस नंबर को सूची में कहाँ भूमि के लिए एक द्विआधारी खोज करें।

यह समाधान कोड को समझना / समझना बहुत आसान है, लेकिन चयन करना वॉकर के उपनाम विधि की तुलना में धीमा है, और संभावनाओं को बदलना अभी भी बाकी है O(n)। हम सरणी को बाइनरी-सर्च ट्री में बदलकर इसे बेहतर बना सकते हैं, जहां प्रत्येक नोड अपने सबट्रेक्ट में सभी वस्तुओं में योग की संभावनाओं पर नज़र रखता है। फिर जब हम [0,1) से संख्या उत्पन्न करते हैं, तो हम उस आइटम को खोजने के लिए पेड़ से नीचे चल सकते हैं।

यह हमें O(log n)एक आइटम लेने और संभावनाओं को बदलने के लिए देता है! यह NextWithRemoval()बहुत तेज बनाता है !

परिणाम

इन दो दृष्टिकोणों की तुलना में, उपरोक्त पुस्तकालय से कुछ त्वरित मानदंड हैं

         वेटरिग्रैंडाइज़र बेंचमार्क | पेड़ | तालिका
-------------------------------------------------- ---------------------------------
जोड़ें () x10000 + NextWithReplacement () x10: | 4 एमएस | 2 मि
जोड़ें () x10000 + NextWithReplacement () x10000: | 7 एमएस | 4 मि
जोड़ें () x10000 + NextWithReplacement () x100000: | 35 एमएस | 28 एमएस
(जोड़ें () + NextWithReplacement ()) x10000 (interleaved) | 8 एमएस | 5403 मि
जोड़ें () x10000 + NextWithRemoval () x10000: | 10 एमएस | 5948 मि

तो जैसा कि आप देख सकते हैं, स्थिर (गैर-बदलते) संभावनाओं के विशेष मामले के लिए, वॉकर का एलियास विधि लगभग 50-100% तेज है। लेकिन अधिक गतिशील मामलों में, पेड़ तेजी से परिमाण के कई आदेश हैं !


वज़न के आधार पर वस्तुओं की छंटाई करते समय वृक्ष आधारित समाधान भी हमें एक अच्छा रन-टाइम ( nlog(n)) देता है ।
नाथन मेरिल

2
मुझे आपके परिणामों पर संदेह है, लेकिन यह सही उत्तर है। यह सुनिश्चित नहीं है कि यह शीर्ष उत्तर क्यों नहीं है, यह विचार करते हुए कि वास्तव में इस समस्या को संभालने के लिए विहित तरीका है।
whn

किस फाइल में ट्री बेस्ड सॉल्यूशन है? दूसरा, आपकी बेंचमार्क टेबल: वॉकर का उपनाम "टेबल" कॉलम है?
Yakk

1
@Yakk: ट्री-बेस्ड सॉल्यूशन का कोड यहाँ है । यह एक एए-ट्री के ओपन-सोर्स कार्यान्वयन पर बनाया गया है । और आपके दूसरे प्रश्न के लिए 'हाँ'।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
वॉकर हिस्सा बहुत ही लिंक-ओनली है।
संचय

17

फॉर्च्यून समाधान का पहिया

आप इस विधि का उपयोग तब कर सकते हैं जब आपके आइटम पूल में संभावनाओं में एक बड़ा आम भाजक होता है और आपको इसे बहुत बार खींचने की आवश्यकता होती है।

विकल्पों की एक सरणी बनाएं। लेकिन प्रत्येक तत्व को कई बार इसमें डालते हैं, प्रत्येक तत्व के डुप्लिकेट की संख्या के साथ इसके दिखने की संभावना के अनुपात में। ऊपर दिए गए उदाहरण के लिए, सभी तत्वों में संभावनाएं हैं जो 5% के गुणक हैं, इसलिए आप इस तरह 20 तत्वों की एक सरणी बना सकते हैं:

10 gold
sword
sword
sword
sword
shield
shield
shield
shield
shield
shield
shield
armor
armor
armor
armor
potion
potion

फिर केवल 0 और सरणी की लंबाई - 1 के बीच एक यादृच्छिक पूर्णांक बनाकर उस सूची का एक यादृच्छिक तत्व चुनें।

नुकसान:

  • आपको पहली बार किसी आइटम को जेनरेट करने के लिए सरणी बनाने की आवश्यकता है।
  • जब आपके तत्वों में से एक को बहुत कम संभावना होती है, तो आप वास्तव में बड़े सरणी के साथ समाप्त होते हैं, जिसके लिए बहुत अधिक मेमोरी की आवश्यकता होती है।

लाभ:

  • जब आपके पास पहले से ही सरणी है और इसे कई बार से आकर्षित करना चाहते हैं, तो यह बहुत तेज़ है। बस एक यादृच्छिक पूर्णांक और एक सरणी का उपयोग।

3
दूसरे नुकसान से बचने के लिए एक हाइब्रिड समाधान के रूप में, आप अंतिम स्लॉट को "अन्य" के रूप में नामित कर सकते हैं और इसे अन्य साधनों के माध्यम से संभाल सकते हैं, जैसे कि फिलिप के सरणी दृष्टिकोण। इस प्रकार आप उस अंतिम स्लॉट को 99.9% पोशन की संभावना वाले सरणी के साथ भर सकते हैं, और सिर्फ 0.1% का मौका Epic Scepter of the Apocalypse। इस तरह के दो स्तरीय दृष्टिकोण दोनों दृष्टिकोणों का लाभ उठाते हैं।
Cort Ammon -

1
मैं अपने स्वयं के प्रोजेक्ट में कुछ भिन्नता का उपयोग करता हूं। मैं प्रत्येक आइटम और वजन की गणना करता हूं, और उन सभी को एक सरणी में संग्रहीत करता हूं, [('gold', 1),('sword',4),...]सभी भार उठाता हूं , और फिर 0 से एक यादृच्छिक संख्या को जोड़ देता हूं, फिर सरणी को पुनरावृत्त करता हूं और गणना करता हूं कि यादृच्छिक संख्या भूमि (यानी) a reduce)। उन सरणियों के लिए ठीक काम करता है जिन्हें अक्सर अपडेट किया जाता है, और कोई बड़ी मेमोरी हॉग नहीं।

1
@ Thebluefish वह समाधान मेरे अन्य उत्तर "द सॉफ्ट-कोडेड प्रोबायबिलिटीज़ सॉल्यूशन" में वर्णित है
फिलिप्पुस

7

हार्ड कोडित संभाव्यता समाधान

सबसे सरल तरीका यह है कि भारित संग्रह से एक यादृच्छिक वस्तु खोजें, अगर-और कथनों की एक श्रृंखला को नीचे की ओर ले जाना है, जहां प्रत्येक में-और शायद बढ़ जाता है, क्योंकि पिछले एक हिट नहीं होता है।

int rand = random(100); //Random number between 1 and 100 (inclusive)
if(rand <= 5) //5% chance
{
    print("You found 10 gold!");
}
else if(rand <= 25) //20% chance
{
    print("You found a sword!");
}
else if(rand <= 70) //45% chance
{
    print("You found a shield!");
}
else if(rand <= 90) //20% chance
{
    print("You found armor!");
}
else //10% chance
{
    print("You found a potion!");
}

सशर्त इसके मौके के बराबर हैं और पिछली सभी सशर्त संभावनाओं के बराबर हैं क्योंकि पिछली सशर्तियों ने पहले ही उन वस्तुओं के होने की संभावना को समाप्त कर दिया है। तो ढाल के सशर्त के लिए else if(rand <= 70), 70 ढाल के 45% संभावना के बराबर है, साथ ही सोने का 5% मौका और तलवार का 20% मौका है।

लाभ:

  • प्रोग्राम करना आसान है, क्योंकि इसके लिए डेटा संरचनाओं की आवश्यकता नहीं है।

नुकसान:

  • बनाए रखने के लिए मुश्किल है, क्योंकि आपको अपने कोड में अपने ड्रॉप-रेट बनाए रखने की आवश्यकता है। आप उन्हें रनटाइम पर निर्धारित नहीं कर सकते। इसलिए यदि आप भविष्य के कुछ और सबूत चाहते हैं, तो आपको अन्य उत्तरों की जांच करनी चाहिए।

3
यह वास्तव में बनाए रखने के लिए कष्टप्रद होगा। उदाहरण के लिए, यदि आप सोना निकालना चाहते हैं, और औषधि बनाना चाहते हैं, तो आपको उनके बीच सभी वस्तुओं की संभावनाओं को समायोजित करने की आवश्यकता है।
अलेक्जेंडर - मोनिका

1
उस मुद्दे से बचने के लिए, जिसमें @Alexander का उल्लेख है, आप प्रत्येक चरण में वर्तमान दर को घटा सकते हैं, बजाय इसे प्रत्येक स्थिति में जोड़ सकते हैं।
अलेक्जेंडर

2

C # में आप 0 से 100.0f और .First () प्राप्त करने के लिए रेंज में एक यादृच्छिक संख्या के खिलाफ जांच करने के लिए अपने संचायक को चलाने के लिए एक Linq स्कैन का उपयोग कर सकते हैं। तो कोड की एक पंक्ति की तरह।

तो कुछ इस तरह:

var item = a.Select(x =>
{
    sum += x.prob;
    if (rand < sum)
        return x.item;
    else
        return null;
 }).FirstOrDefault());

sumएक शून्य इनिशियलाइज्ड पूर्णांक है और aप्रोब / आइटम स्ट्रक्चर्स / ट्यूपल्स / इंस्टेंस की सूची है। randसीमा में पहले से उत्पन्न यादृच्छिक संख्या है।

यह केवल पहले से चयनित यादृच्छिक संख्या से अधिक होने तक श्रेणियों की सूची में राशि जमा करता है, और आइटम या अशक्त रिटर्न देता है, जहां यदि यादृच्छिक संख्या सीमा (जैसे 100) गलती से कुल भार सीमा से कम है, तो शून्य वापस आ जाएगी। , और चयनित यादृच्छिक संख्या कुल भार सीमा के बाहर है।

हालांकि, आप देखेंगे कि ओपी में वजन एक सामान्य वितरण (बेल कर्व) से निकटता से मेल खाता है। मुझे लगता है कि सामान्य तौर पर आप विशिष्ट रेंज नहीं चाहते हैं, आप एक वितरण चाहते हैं जो एक घंटी वक्र के चारों ओर या केवल घटते हुए घातीय वक्र (उदाहरण के लिए) पर बंद हो जाए। इस मामले में, आप पसंदीदा संभावना के क्रम में क्रमबद्ध वस्तुओं के एक सरणी में एक सूचकांक बनाने के लिए सिर्फ एक गणितीय सूत्र का उपयोग कर सकते हैं। एक अच्छा उदाहरण सामान्य वितरण में सीडीएफ है

यहाँ एक उदाहरण भी

एक अन्य उदाहरण यह है कि किसी सर्कल के निचले दाएं हिस्से को प्राप्त करने के लिए आप 90 डिग्री से 180 डिग्री तक का यादृच्छिक मान ले सकते हैं, cos (r) का उपयोग करके x घटक ले सकते हैं और प्राथमिकता वाले सूची में अनुक्रमित करने के लिए इसका उपयोग कर सकते हैं।

विभिन्न फ़ार्मुलों के साथ आप एक सामान्य दृष्टिकोण रख सकते हैं, जहाँ आप किसी भी लम्बाई (जैसे एन) की प्राथमिकता वाली सूची का इनपुट करते हैं और सूत्र के परिणाम का उदाहरण देते हैं (जैसे: cos (x) 0 से 1 है) गुणा (जैसे: Ncos (x) ) = 0 से एन) सूचकांक प्राप्त करने के लिए।


3
अगर यह सिर्फ एक लाइन है तो क्या आप हमें यह लाइन ऑफ कोड दे सकते हैं? मैं C # से परिचित नहीं हूं इसलिए मुझे नहीं पता कि आपका क्या मतलब है।
HEGX64

@ HEGX64 को जोड़ा गया, लेकिन मोबाइल और एडिटर का उपयोग नहीं किया गया। क्या आप संपादित कर सकते हैं?
सेंटिनल

4
क्या आप किसी विशिष्ट भाषा में विशिष्ट नकल के बजाय, इसके पीछे की अवधारणा को समझाने के लिए इस उत्तर को बदल सकते हैं?
रायमुंड क्रमर

@ RaimundKrämer Erm, किया?
सेंटिनल

स्पष्टीकरण के बिना नीचा दिखाना = बेकार और असामाजिक।
WGroleau

1

संभावनाओं को हार्ड-कोडेड होने की आवश्यकता नहीं है। आइटम और थ्रेसहोल्ड एक सरणी में एक साथ हो सकते हैं।

for X in itemsrange loop
  If items (X).threshold < random() then
     Announce (items(X).name)
     Exit loop
  End if
End loop

आपको अभी भी थ्रेशोल्ड जमा करना है, लेकिन आप इसे कोडिंग के बजाय एक पैरामीटर फ़ाइल बनाते समय कर सकते हैं।


3
क्या आप सही दहलीज की गणना करने के बारे में विस्तार से बता सकते हैं? उदाहरण के लिए, यदि आपके पास 33% संभावना वाले तीन आइटम हैं, तो आप इस तालिका का निर्माण कैसे करेंगे? चूंकि हर बार एक नया यादृच्छिक () उत्पन्न होता है, पहले को 0.3333 की आवश्यकता होगी, दूसरे को 0.5 की आवश्यकता होगी और अंतिम को 1.0 की आवश्यकता होगी। या क्या मैंने एल्गोरिथ्म को गलत पढ़ा था?
पाइप

आप इसे उसी तरह से गणना करते हैं जिस तरह से दूसरों ने अपने उत्तरों में किया है। एक्स आइटम की समान संभावनाओं के लिए, पहली सीमा 1 / X, दूसरी, 2 / X, आदि है
WGroleau

इस एल्गोरिथ्म में 3 आइटम के लिए ऐसा करने से थ्रेशोल्ड 1/3, 2/3 और 3/3 हो जाएंगे, लेकिन परिणाम संभाव्यता 1/3, 4/9 और 2/9 पहले, दूसरे और तीसरे आइटम के लिए। क्या आपको वास्तव random()में लूप में कॉल करने का मतलब है ?
पाइप

नहीं, यह निश्चित रूप से एक बग है। प्रत्येक चेक को एक ही यादृच्छिक संख्या की आवश्यकता होती है।
WGroleau

0

मैंने यह फ़ंक्शन किया: https://github.com/thewheelmaker/GDscript_Weighted_Random Now! आपके मामले में आप इसे इस तरह से उपयोग कर सकते हैं:

on_normal_case([5,20,45,20,10],0)

यह केवल 0 से 4 के बीच एक संख्या देता है, लेकिन आप इसे सरणी में रख सकते हैं जहां आपको आइटम मिले हैं।

item_array[on_normal_case([5,20,45,20,10],0)]

या समारोह में:

item_function(on_normal_case([5,20,45,20,10],0))

यहाँ कोड है। मैंने इसे GDscript पर बनाया है, आप यह कर सकते हैं, लेकिन यह अन्य भाषा को बदल सकता है, तर्क त्रुटियों की जांच भी कर सकता है:

func on_normal_case(arrayy,transformm):
    var random_num=0
    var sum=0
    var summatut=0
    #func sumarrays_inarray(array):
    for i in range(arrayy.size()):
        sum=sum+arrayy[i]
#func no_fixu_random_num(here_range,start_from):
    random_num=randi()%sum+1
#Randomies be pressed down
#first start from zero
    if 0<=random_num and random_num<=arrayy[0]:
        #print(random_num)
        #print(array[0])
        return 0+ transformm
    summatut=summatut+arrayy[0]
    for i in range(arrayy.size()-1):
        #they must pluss together
        #if array[i]<=random_num and random_num<array[i+1]:
        if summatut<random_num and random_num<=summatut+arrayy[i+1]:
            #return i+1+transform
            #print(random_num)
            #print(summatut)
            return i+1+ transformm

        summatut=summatut+arrayy[i+1]
    pass

यह इस तरह काम करता है: on_normal_case ([50,50], 0) यह 0 या 1 देता है, इसमें दोनों की समान संभावना है।

on_normal_case ([50,50], 1) यह 1 या 2 देता है, इसमें दोनों की समान संभावना है।

on_normal_case ([20,80], 1) यह 1 या 2 देता है, इसमें दो प्राप्त करने के लिए बड़ा परिवर्तन है।

on_normal_case ([20,80,20,20,30], 1) यह यादृच्छिक संख्या 1-5 देता है और बड़ी संख्या छोटी संख्याओं की तुलना में अधिक होती है।

on_normal_case ([20,80,0,0,20,20,30,0,0,0,033,33], 45) यह फेंक संख्या 45,46,49,50,51,56 के बीच आप वहां देखते हैं। यह शून्य कभी नहीं होता है।

तो यह फ़ंक्शन केवल एक यादृच्छिक संख्या देता है जो उस सरणी सरणी और ट्रांसफ़ॉर्म नंबर की सीमा पर निर्भर करता है, और एरे में ints प्रायिकता भार है कि एक संख्या आंकी जा सकती है, जहां वह संख्या सरणी पर स्थान है, प्लस ट्रांसफॉर्म नंबर।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.