हमला बनाम रक्षा और विजेता कौन है? [बन्द है]


12

मैं मोबाइल में एक नया सरल गेम बनाने की प्रक्रिया में हूं और मैंने निम्नलिखित भाग में कई दिन बिताए हैं।

सादगी के लिए, मान लें कि मेरे पास दो लड़ाकू हैं। उनमें से एकमात्र विशेषता हमला और रक्षा है। जब पहला हमला होता है, तो केवल एक चीज जो उस पर हमला करती है और प्रतिद्वंद्वी की रक्षा। और इसके विपरीत।

उनके पास उपकरण, वस्तुएं, सहनशक्ति या स्वास्थ्य नहीं है। सिर्फ हमला बनाम रक्षा।

उदाहरण:

  • लड़ाकू 1:

    हमला: 50, रक्षा: 35

  • लड़ाकू 2:

    हमला 20, रक्षा: 80

लड़ने की प्रक्रिया सिर्फ एक हमला होगी जो विजेता को निर्धारित करेगी। इसलिए, कोई एकाधिक हमला या दौर नहीं। मैं इसे नियतात्मक नहीं बनाना चाहता, लेकिन अनपेक्षित का एक हल्का संस्करण जोड़ें। कम हमले वाला एक सेनानी उच्च रक्षा के साथ एक और लड़ाकू जीतने में सक्षम होगा (लेकिन निश्चित रूप से हर बार नहीं)

मेरा पहला विचार यह था कि इसे रैखिक बनाया जाए और एक समान यादृच्छिक संख्या जनरेटर को कॉल किया जाए।

If Random() < att1 / (att1 + def2) {
    winner = fighter1
} else {
    winner = fighter2
} 

हमले के साथ उदाहरण 50 और रक्षा 80, हमलावर सेनानी को जीतने के लिए लगभग 38% होगा। हालांकि, यह मुझे लगता है कि अप्रत्याशित बहुत दूर है और सबसे खराब सेनानियों को बहुत जीत मिलेगी।

मैं सोच रहा था कि आपने इसी तरह की परिस्थितियों पर कैसे काम किया है।

PS मैंने इस QnA और अन्य स्रोतों में बहुत खोज की और मुझे एसई के लिए भी व्यापक रूप में उल्लिखित समान प्रश्न मिले। लेकिन उन लोगों के पास कई विशेषताएं, हथियार, आइटम, कक्षाएं आदि हैं जो इसे बहुत जटिल बना सकते हैं। मुझे लगता है कि मेरा संस्करण एसई की QAA शैली में इसे फिट करने के लिए बहुत सरल है।


1
ऐसे कौन से मामले हैं जिनकी आप तलाश कर रहे हैं? हमले और रक्षा के लिए आप किन मूल्यों को देख रहे हैं और क्या उन सीमाओं में किसी भी दो संख्याओं का कभी कोई निश्चित परिणाम होना चाहिए? उदाहरण के लिए, क्या आक्रमणकारी 10 के साथ एक लड़ाकू रक्षा 90 पर एक सेनानी को हरा सकता है?
नील्स

@ user2645227 मैं कह सकता हूं कि सीमा 1 और 400 के बीच है। नहीं, मैं कोई भी निर्णायक निर्णय नहीं लेना चाहता हूं और 1 को रक्षा 400 पर हमला करने की संभावना देता हूं, लेकिन वास्तव में दुर्लभ मामलों में।
तस्सो

1
इसलिए यदि आप Att (min) -def (अधिकतम) और Att (अधिकतम) -def (min) लेते हैं जो आपको 800 से -400 से 400 तक की सीमा प्रदान करता है। आप पूरी रेंज को कवर करने के लिए अपनी यादृच्छिक रेंज चाहते हैं। रक्षा - हमला आपको दहलीज के रूप में एक स्केलिंग मार्जिन देगा जो आपको जीतने के लिए हिट करना होगा। इससे यादृच्छिकता को थोड़ा कम करना चाहिए। आगे के परिणामों को केंद्रीकृत करने के लिए आप किसी भी समय फिलिप के उदाहरण या फिडल का उपयोग कर सकते हैं जब तक कि आप उस वक्र को नहीं मारते हैं जिसे आप खोज रहे हैं।
नील्स

जवाबों:


24

यदि आप चाहते हैं कि आपकी लड़ाई के परिणाम अधिक अनुमानित हों, लेकिन पूरी तरह से नियतात्मक नहीं हैं, तो एन प्रणाली का एक सर्वश्रेष्ठ है।

लड़ाई के nसमय (जहां nएक असमान संख्या होनी चाहिए) को दोहराएं और अधिक बार जीतने वाले विजेता को घोषित करें। nकम आश्चर्य की जीत और नुकसान के लिए आपका मूल्य जितना बड़ा होगा।

const int FIGHT_REPETITONS = 5 // best 3 of 5. Adjust to taste.

int fighter1wins = 0;
int fighter2wins = 0;

for (int i = 0; I < FIGHT_REPETITONS; I++) {

    If (Random() < att1 / (att1 + def2)) {
        fighter1wins++;
    } else {
        fighter2wins++;
    } 

}

If (fighter1wins > fighter2wins) {
    winner = fighter1
} else {
    winner = fighter2
} 

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

double averagedRandom3() {
    return (Random() + Random() + Random()) / 3.0;
}

इस तरह एक वितरण वक्र होगा:

3D20 / 3 का वितरण

(किसी भी तरह की तस्वीर शिष्टाचार - गेम मैकेनिक फ़ार्मुलों को डिज़ाइन करने के लिए एक बहुत ही उपयोगी उपकरण जो यादृच्छिकता को शामिल करता है, न कि केवल फ़ोकस के लिए)

मेरी वर्तमान परियोजना में मैं एक सहायक-फ़ंक्शन का उपयोग कर रहा हूं जो एक मनमाना नमूना आकार सेट करने की अनुमति देता है:

double averagedRandom(int averageness) {
     double result = 0.0;
     for (var i = 0; i < averageness; i++) {
         result += Random();
     }
     return result / (double)averageness;
}

बेहतर तरीका लगता है। एक सवाल। औसतनग्राहक 3 () फ़ंक्शन में, आपको +इसके बजाय उपयोग करना चाहिए *या मुझे गलत समझा गया कि यह क्या करता है?
तस्सो

@ टासोस हां, + होना चाहिए, न कि *। मेरे पास एक यादृच्छिक-फ़ंक्शन भी है जो कई नमूनों को गुणा करता है। यह आपको कम मूल्यों के लिए एक मजबूत पूर्वाग्रह के साथ एक यादृच्छिक संख्या फ़ंक्शन देता है, जो कुछ स्थितियों में भी उपयोगी हो सकता है।
फिलीपींस

1
मैं प्रश्न को 1-2 दिनों के लिए खुला रखूंगा और यदि मेरे पास कोई अन्य उत्तर नहीं है, तो मैं आपका चयन करूंगा। मैंने इसे अपडाउन किया है, लेकिन अगर आपको कोई आपत्ति नहीं है तो अन्य उत्तरों के लिए भी मौका देना चाहता हूं।
टासोस

मुझे लगता है कि इस उत्तर को पहले से ही पर्याप्त वोट मिले जो इस उत्तर को अंक के रूप में चिह्नित करने के लिए योग्य बनाता है: पी
हमजा हसन

1
अगर कुछ लोग वैकल्पिक दृष्टिकोण के साथ आते हैं तो मैं भी उत्सुक होऊंगा। एक व्यक्ति ने इस उत्तर को अस्वीकार कर दिया। शायद वे एक विकल्प प्रदान करना चाहेंगे।
फिलिप

8

यह वही है जो मैंने अपने लॉर्ड्स ऑफ कॉन्क्वेस्ट इमिटेटर एप्लेट में एक लड़ाई के विजेता को निर्धारित करने के लिए उपयोग किया था। इस खेल में, आपकी स्थिति के समान, बस एक हमले का मूल्य और एक रक्षा मूल्य है। हमलावर के जीतने की संभावना अधिक होती है और हमलावर के पास जितने अधिक बिंदु होते हैं, और रक्षा के 50% मौके का मूल्यांकन करने वाले समान मूल्यों के साथ, रक्षा के अधिक अंक होते हैं।

कलन विधि

  1. एक यादृच्छिक सिक्का पलटें।

    1 क। प्रमुख: रक्षा एक बिंदु खो देता है।

    1b। पूंछ: सिर एक बिंदु खो देता है।

  2. यदि रक्षा और हमलावर दोनों के पास अभी भी अंक हैं, तो चरण 1 पर वापस जाएं।

  3. जो भी 0 अंक से नीचे है वह लड़ाई हार जाता है।

    3 ए। 0 से नीचे हमलावर: हमला विफल रहता है।

    3 बी। 0 से नीचे रक्षा: हमला सफल होता है।

मैंने इसे जावा में लिखा था, लेकिन इसे आसानी से अन्य भाषाओं में अनुवाद किया जाना चाहिए।

Random rnd = new Random();
while (att > 0 && def > 0)
{
    if (rnd.nextDouble() < 0.5)
        def--;
    else
        att--;
}
boolean attackSucceeds = att > 0;

एक उदाहरण

उदाहरण के लिए, मान लें कि att = 2 और def = 2 है, बस यह सुनिश्चित करने के लिए कि संभावना 50% है।

लड़ाई का फैसला अधिकतम n = att + def - 1सिक्के के उतार-चढ़ाव में किया जाएगा, या इस उदाहरण में 3 (यह अनिवार्य रूप से यहां 3 का सबसे अच्छा है)। सिक्का फ़्लिप के 2 n संभावित संयोजन हैं। यहाँ, "W" का अर्थ है कि हमलावर ने सिक्का फ्लिप जीत लिया, और "L" का अर्थ है हमलावर ने सिक्का फ्लिप खो दिया।

L,L,L - Attacker loses
L,L,W - Attacker loses
L,W,L - Attacker loses
L,W,W - Attacker wins
W,L,L - Attacker loses
W,L,W - Attacker wins
W,W,L - Attacker wins
W,W,W - Attacker wins

हमलावर 4/8, या 50% मामलों में जीतता है।

गणित

इस सरल एल्गोरिथ्म से उत्पन्न होने वाली गणितीय संभावनाएं एल्गोरिथ्म की तुलना में अधिक जटिल हैं।

संयोजनों की संख्या से जहां x xs के संयोजन की संख्या दी गई है:

C(n, x) = n! / (x! * (n - x)!)

जब 0और att - 1Ls के बीच हो तो हमलावर जीत जाता है । सफल संयोजनों की संख्या से संयोजनों की राशि के बराबर है 0के माध्यम से att - 1, एक संचयी द्विपदी बंटन:

    (att - 1)
w =     Σ     C(n, x)
      x = 0

हमलावर की संभावना जीत रहा है डब्ल्यू 2 से विभाजित n , एक संचयी द्विपदी संभावना:

p = w / 2^n

यहाँ इस कोड को जावा में मध्यस्थता attऔर defमूल्यों के लिए इस संभावना की गणना करने के लिए दिया गया है :

/**
 * Returns the probability of the attacker winning.
 * @param att The attacker's points.
 * @param def The defense's points.
 * @return The probability of the attacker winning, between 0.0 and 1.0.
 */
public static double probWin(int att, int def)
{
    long w = 0;
    int n = att + def - 1;
    if (n < 0)
        return Double.NaN;
    for (int i = 0; i < att; i++)
        w += combination(n, i);

    return (double) w / (1 << n);
}

/**
 * Computes C(n, k) = n! / (k! * (n - k)!)
 * @param n The number of possibilities.
 * @param k The number of choices.
 * @return The combination.
 */
public static long combination(int n, int k)
{
    long c = 1;
    for (long i = n; i > n - k; i--)
        c *= i;
    for (long i = 2; i <= k; i++)
        c /= i;
    return c;
}

परीक्षण कोड:

public static void main(String[] args)
{
    for (int n = 0; n < 10; n++)
        for (int k = 0; k <= n; k++)
            System.out.println("C(" + n + ", " + k + ") = " + combination(n, k));

    for (int att = 0; att < 5; att++)
        for (int def = 0; def < 10; def++)
            System.out.println("att: " + att + ", def: " + def + "; prob: " + probWin(att, def));
}

आउटपुट:

att: 0, def: 0; prob: NaN
att: 0, def: 1; prob: 0.0
att: 0, def: 2; prob: 0.0
att: 0, def: 3; prob: 0.0
att: 0, def: 4; prob: 0.0
att: 1, def: 0; prob: 1.0
att: 1, def: 1; prob: 0.5
att: 1, def: 2; prob: 0.25
att: 1, def: 3; prob: 0.125
att: 1, def: 4; prob: 0.0625
att: 1, def: 5; prob: 0.03125
att: 2, def: 0; prob: 1.0
att: 2, def: 1; prob: 0.75
att: 2, def: 2; prob: 0.5
att: 2, def: 3; prob: 0.3125
att: 2, def: 4; prob: 0.1875
att: 2, def: 5; prob: 0.109375
att: 2, def: 6; prob: 0.0625
att: 3, def: 0; prob: 1.0
att: 3, def: 1; prob: 0.875
att: 3, def: 2; prob: 0.6875
att: 3, def: 3; prob: 0.5
att: 3, def: 4; prob: 0.34375
att: 3, def: 5; prob: 0.2265625
att: 3, def: 6; prob: 0.14453125
att: 3, def: 7; prob: 0.08984375
att: 4, def: 0; prob: 1.0
att: 4, def: 1; prob: 0.9375
att: 4, def: 2; prob: 0.8125
att: 4, def: 3; prob: 0.65625
att: 4, def: 4; prob: 0.5
att: 4, def: 5; prob: 0.36328125
att: 4, def: 6; prob: 0.25390625
att: 4, def: 7; prob: 0.171875
att: 4, def: 8; prob: 0.11328125

टिप्पणियों

0.0यदि हमलावर के पास 0अंक हैं, 1.0तो संभावनाएं हैं, यदि हमलावर के पास अंक हैं, लेकिन रक्षा के पास 0अंक हैं, 0.5यदि अंक समान हैं, तो कम से कम 0.5अगर हमलावर के पास रक्षा की तुलना में कम अंक हैं, और 0.5यदि हमलावर के पास रक्षा से अधिक अंक हैं, तो इससे अधिक ।

ले रहा है att = 50और def = 80, मुझे BigDecimalअतिप्रवाह से बचने के लिए एस पर स्विच करने की आवश्यकता थी , लेकिन मुझे लगभग 0.0040 की संभावना है।

आप मान और मूल्यों attके औसत होने के लिए संभावना को बदलकर 0.5 के करीब कर सकते हैं । Att = 50, Def = 80 बन जाता है (65, 80), जो 0.1056 की संभावना पैदा करता है।attdef


1
एक और दिलचस्प दृष्टिकोण। एल्गोरिथ्म को भी आसानी से देखा जा सकता है, जो काफी रोमांचक लग सकता है।
फिलीपींस

5

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

if (att1 + norm(0, sigma) - def2 > 0) {
  winner = fighter1;
}
else {
  winner = fighter2;
}

फ़ंक्शन norm(x0, sigma)मानक विचलन सिग्मा के साथ x0 पर केंद्रित एक सामान्य वितरण से नमूना फ्लोट देता है। अधिकांश प्रोग्रामिंग भाषाएं इस तरह के फ़ंक्शन के साथ एक पुस्तकालय प्रदान करती हैं, लेकिन यदि आप इसे बनाना चाहते हैं तो इस प्रश्न पर एक नज़र डालें । आपको सिग्मा को ऐसे समायोजित करना होगा कि यह 'सही लगे', लेकिन 10-20 का मान शुरू करने के लिए एक अच्छी जगह हो सकती है।

कुछ सिग्मा मूल्यों के लिए, किसी दिए गए जीत की संभावना att1 - def2इस तरह दिखती है: जीत की संभावना


यह भी इंगित करने के लायक हो सकता है कि सामान्य वितरित मूल्यों का कोई वास्तविक सीमा नहीं है, इसलिए जब किसी गेम में सामान्य-वितरित यादृच्छिक मानों का उपयोग किया जाता है, तो यह परिणाम से बचने के लिए समझदारी बना सकता है लेकिन बहुत चरम मूल्यों की असंभव स्थिति उत्पन्न नहीं होने देता है जो खेल को तोड़ सकता है।
फिलिप
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.