ट्रैक
/
C++
C++
/
अभ्यास
/
ट्रोलों को ट्रोल कीजिए
ट्रोलों को ट्रोल कीजिए

ट्रोलों को ट्रोल कीजिए

सीखने का अभ्यास

परिचय

एन्यूमरेशन

अब तक हमने ज़्यादातर संख्याओं और स्ट्रिंग के साथ काम किया है। वास्तविक दुनिया का मॉडल बनाने के लिए हमें कभी-कभी एक सीमित संख्या में ऐसी वैल्यू चाहिए होती हैं जो कोई वेरिएबल ले सकता है। आप एक ऐसा अलग टाइप चाह सकते हैं जिसमें कुछ अलग-अलग नामों वाली कुछ अलग वैल्यू हों। उदाहरण के लिए, स्केटबोर्ड बनाने की फैक्ट्री में डेक का मटेरियल सिर्फ maple, bamboo या plastic में से कोई एक हो सकता है।

आप इन वैल्यू को पूर्णांक में एन्कोड कर सकते हैं, लेकिन तब आपको अतिरिक्त कोड लिखकर यह जाँचना पड़ेगा कि मटेरियल के लिए सिस्टम से कोई अमान्य वैल्यू तो नहीं आ रही है। उन जादुई संख्याओं का अर्थ सोर्स कोड में ढूँढ़ना मुश्किल होता है, और उनमें गलतियाँ होने की आशंका बनी रहती है। enumerations की मदद से ऐसा कोड लिखा जा सकता है जिसका मतलब साफ़ हो, और अनजाने में की गई तुलना की गलतियों को रोका जा सकता है।

उदाहरण

इस तरह के एन्यूमरेशन का खास नाम scoped enumeration है। नीचे दिया गया कोड दिखाता है कि DeckMaterial enumeration कैसे लिखा जाता है। परिभाषा में enum class कीवर्ड और अंत में लगे ; पर ध्यान दीजिए:

enum class DeckMaterial {
    maple,
    bamboo,
    plastic
};

अब स्केट की दुकान में दाम तय करने वाले फंक्शन को देखिए, और उस स्कोप रिज़ॉल्यूशन ऑपरेटर (::) पर ध्यान दीजिए जो बताता है कि enumerator किस enumeration का है:

double deck_price(double base_price, DeckMaterial material) {
    if(material == DeckMaterial::plastic) {
        return base_price * 0.9;
    }
    return base_price * 1.3;
}

स्कोप

सोचिए, आपके पास पहियों के मटेरियल के लिए एक और enumeration है:

enum class WheelMaterial {
    steel,
    clay,
    plastic
};

पहिए और डेक, दोनों plastic के बने हो सकते हैं, फिर भी इन दोनों में उलझन नहीं हो सकती। ये दो अलग टाइप हैं: DeckMaterial वाला plastic और WheelMaterial वाला plastic। हर enumeration के अपने enumerators अपने ही स्कोप में रहते हैं, यानी अपने ही namespace में। इसी वजह से इन्हें scoped enumerations कहा जाता है।

Advanced

अनस्कोप्ड एन्यूमरेशन

आप सोच रहे होंगे कि जब नाम scoped है, तो unscoped एन्यूमरेशन भी होंगे, और यह सही है। Unscoped enumerations की लोकप्रियता घटती जा रही है, क्योंकि ये सब एक ही ग्लोबल नेमस्पेस साझा करते हैं। इसी साझेदारी की वजह से ऊपर के उदाहरण में दिए plastic जैसे एक ही enumerators वाले दो unscoped enumerations नहीं बना सकते।

इसके अलावा, unscoped enumerations अपने आप पूर्णांक में बदल जाते हैं। नीचे दिए उदाहरण में एक चौंकाने वाला नतीजा देखिए:

enum CitrusFruits {
    lemons,  // 0
    oranges, //1
};

enum IceCream {
    walnut,  // 0
    apples,  // 1
};

bool comparison{apples == oranges};
// => true

// Example from above:
bool comparison{DeckMaterial::plastic == WheelMaterial::plastic};
// => Does not compile!

अगर आप scoped enumerations को पूर्णांक में बदलना चाहते हैं, तो static_cast<int> इस्तेमाल कर सकते हैं।

switch स्टेटमेंट

दूसरी भाषाओं की तरह C++ में भी switch स्टेटमेंट होता है। switch स्टेटमेंट लंबे if ... else if स्टेटमेंट लिखने का छोटा तरीका है। स्विच बनाने के लिए सबसे पहले switch कीवर्ड लिखते हैं, और उसके बाद एक पूर्णांक। इसके बाद हम हर शर्त को case कीवर्ड से घोषित करते हैं। हम एक default केस भी लिख सकते हैं, जो तब चलेगा जब ऊपर की case शर्तों में से कोई भी न मिले। हर केस का अंत break (या return) स्टेटमेंट से होना चाहिए।

int price{0};
int adults{3};
int kids{2};

switch (int group_size{adults + kids}) {
    case 1:
        price = 50;
        break;
    case 2:
        price = 70;
        break;
    default:
        price = group_size * 30;
}

फॉल-थ्रू

स्विच की बनावट में एक ज़रूरी बात यह है कि कोड तब तक चलता रहता है जब तक कोई break (या return) स्टेटमेंट उसे रोक न दे। इससे ऐसा व्यवहार मिल सकता है जिसकी उम्मीद आपने नहीं की होगी।

int adults{1};
int kids{0};
switch (int group_size{adults + kids}) {
    case 1:
        price = 50;
    case 2:
        price = 70;
    default:
        price = group_size * 30;
}
// price will be 30!

कोड के इस तरह चलते रहने का सबसे बड़ा इस्तेमाल वह स्टेटमेंट है जिस पर कई लेबल लगे हों। कई स्विच नतीजों के लिए एक ही कोड चलाया जा सकता है। इस तरह, मान लीजिए किसी बुकिंग ऐप में, ग्रुप साइज़ 2 और 3 के लिए कॉल किया जाने वाला फंक्शन एक ही हो सकता है:

switch (group_size) {
case 1:
    book_room();
    break;
case 2:
case 3:
    book_apartment(group_size);
    break;
default:
    book_house(group_size);
}
// book_apartment happens when group_size is 2 or 3

निर्देश

आपकी दोस्त हेल्मा ने एक छोटा ऑनलाइन गेम बनाया था, जो बहुत तेज़ी से लोकप्रिय हो गया। इसका नाम HellMath है। इस छोटे से समुदाय में कुछ ट्रोल भी आ गए, जो गेम और फोरम दोनों को काफी अप्रिय बना देते हैं। हेल्मा ने आपसे कहा है कि आप एक नया अनुमति सिस्टम बनाइए, ताकि उपद्रवियों को अलग किया जा सके।

फोरम तीन अलग-अलग कार्रवाइयों का समर्थन करता है:

  • पढ़ना
  • लिखना
  • हटाना

खातों के चार प्रकार हैं, और हर प्रकार की अपनी अलग डिफॉल्ट अनुमतियाँ हैं:

  • गेस्ट: पोस्ट पढ़ सकते हैं।
  • यूज़र और ट्रोल: पोस्ट पढ़ और लिख सकते हैं।
  • मॉडरेटर: पोस्ट पढ़, लिख और हटा सकते हैं, उनके पास सारी अनुमतियाँ हैं।

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

इस तरीके को शैडो-बैनिंग कहते हैं।

1. यूज़र टाइप और अनुमतियाँ सेट कीजिए।

सबसे पहले, खातों के चारों प्रकारों को दर्शाने के लिए एक AccountStatus एन्यूमरेशन बनाइए: troll, guest, user, और mod.

इसके बाद, तीनों अनुमति प्रकारों को दर्शाने के लिए एक Action एन्यूमरेशन बनाइए: read, write, और remove.

2. ट्रोल्स को सिर्फ दूसरे ट्रोल्स को ही दिखाइए।

फोरम की हर पोस्ट अपने मेटाडेटा में पोस्ट करने वाले का AccountStatus संग्रहीत करती है। ध्यान रखिए कि ट्रोल्स की पोस्ट सिर्फ दूसरे ट्रोल्स को ही दिखाई जाएँ।

हेल्मा को एक display_post फंक्शन चाहिए, जो AccountStatus टाइप के दो आर्गुमेंट लेता है और एक bool लौटाता है। पहला आर्गुमेंट पोस्ट करने वाले का स्टेटस है, और दूसरा देखने वाले का।

using namespace hellmath;
display_post(AccountStatus::troll, AccountStatus::user);
// => false
display_post(AccountStatus::mod, AccountStatus::guest);
// => true

3. अलग-अलग यूज़रों के लिए अनुमतियाँ जाँचिए।

हेल्मा को यह जाँचने का तरीका चाहिए कि किसी यूज़र के लिए कोई खास कार्रवाई करने की अनुमति है या नहीं।

कृपया एक permission_check फंक्शन बनाइए, जो पहले आर्गुमेंट के रूप में एक Action लेता है और जाँचने के लिए उसके बाद एक AccountStatus। इसे परिचय में दी गई अनुमतियों के अनुसार एक bool लौटाना चाहिए।

permission_check(Action::remove, AccountStatus::guest);
// => false
permission_check(Action::write, AccountStatus::mod);
// => true

4. गेम का एक्सेस दीजिए और खिलाड़ियों की जोड़ी बनाइए।

गेम के असली खिलाड़ियों को उनके कामों के लिए जवाबदेह बनाए रखने के लिए, Hellmath गेस्ट यूज़रों को गेम का एक्सेस नहीं देता। जैसा ऊपर बताया गया है, हेल्मा चाहती है कि ट्रोल दूसरे ट्रोल्स को ही ट्रोल करें। बाकी यूज़रों के बीच गेम में जुड़ने पर कोई रोक नहीं है।

valid_player_combination फंक्शन बनाइए, जो जाँचता है कि दो खिलाड़ी एक ही गेम में शामिल हो सकते हैं या नहीं। इस फंक्शन में AccountStatus टाइप के दो पैरामीटर हैं और यह एक bool लौटाता है।

valid_player_combination(AccountStatus::guest, AccountStatus::mod);
// => false
valid_player_combination(AccountStatus::troll, AccountStatus::troll);
// => true

5. प्राथमिकता वाली कतार बनाइए।

गेम और फोरम के तेज़ी से बढ़ने के कारण अब हेल्मा को यूज़रों के बीच कंप्यूटिंग पावर और बैंडविड्थ बाँटनी पड़ती है। आपात स्थितियों से निपटने के लिए मॉडरेटरों को सबसे ज़्यादा प्राथमिकता दी जाती है। गेस्ट सामान्य यूज़रों के बाद कतार में लगते हैं, और ट्रोल सबसे पीछे रखे जाते हैं।

has_priority फंक्शन बनाइए, जो AccountStatus टाइप के दो आर्गुमेंट लेता है। यह तभी true लौटाता है जब, और सिर्फ तभी जब, पहले खाते की प्राथमिकता दूसरे खाते से सख्ती से ज़्यादा हो।

has_priority(AccountStatus::guest, AccountStatus::mod);
// => false
has_priority(AccountStatus::user, AccountStatus::troll);
// => true
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
C++ Exercism

ट्रोलों को ट्रोल कीजिए शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और C++ को 19 कॉन्सेप्ट100 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।