ट्रैक
/
Python
Python
/
अभ्यास
/
एलेन का एलियन गेम
एलेन का एलियन गेम

एलेन का एलियन गेम

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

परिचय

Python में ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग

अगर आप फंक्शनल, डिक्लेरेटिव या इम्पेरेटिव शैली में प्रोग्रामिंग करते आए हैं, तो ध्यान ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग (OOP) पर ले जाना आपको थोड़ा अजीब लग सकता है। OOP का तरीका प्रोग्रामर से कहता है कि वह किसी समस्या को एक या अधिक objects के रूप में सोचे, जो आपस में बातचीत करते हैं, अपनी स्थिति बनाए रखते हैं और डेटा पर काम करते हैं। ऑब्जेक्ट असली दुनिया की चीज़ों को दर्शा सकते हैं (जैसे कार या बिल्लियाँ), या अधिक अमूर्त अवधारणाओं को (जैसे पूर्णांक, वाहन या स्तनधारी)। हर ऑब्जेक्ट कंप्यूटर मेमोरी में एक अलग इंस्टेंस बन जाता है और पूरे मॉडल के किसी एक हिस्से को दर्शाता है।

क्लास

Classes नए ऑब्जेक्ट टाइप की परिभाषाएँ हैं, और इन्हीं से ऑब्जेक्ट के नए instances बनाए जाते हैं। ये अक्सर डेटा के साथ उस डेटा पर काम करने वाला कोड या फंक्शन जोड़ देती हैं। इस अर्थ में क्लास एक तरह का खाका या निर्देशों का समूह होती हैं, जिनसे एक जैसे टाइप के कई ऑब्जेक्ट बनाए और इस्तेमाल किए जा सकते हैं। एक जटिल प्रोग्राम में कई क्लास हो सकती हैं, और हर क्लास कई अलग-अलग तरह के ऑब्जेक्ट बनाती है। किसी क्लास से ऑब्जेक्ट बनाने की प्रक्रिया को instantiation (या क्लास का इंस्टेंस बनाना) कहा जाता है।

Python में क्लास की परिभाषा सीधी और आसान होती है:

class MyClass:
    # Class body goes here

क्लास एट्रिब्यूट

क्लास फील्ड (जिन्हें properties, attributes, data members या variables भी कहा जाता है) क्लास की बॉडी में जोड़े जा सकते हैं:

class MyClass:
    number = 5
    string = "Hello!"

MyClass का एक इंस्टेंस (ऑब्जेक्ट) क्लास को कॉल करके बनाया जा सकता है और किसी नाम से बाँधा जा सकता है (ठीक वैसे ही जैसे किसी फंक्शन को कॉल किया जाता है):

>>> new_object = MyClass()

# Class is instantiated and resulting object is bound to the "new_object" name.
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>

Class attributes किसी क्लास से बने सभी ऑब्जेक्ट (या इंस्टेंस) में साझा रहते हैं, और इन्हें dot notation से इस्तेमाल किया जा सकता है, यानी ऑब्जेक्ट के नाम के बाद और एट्रिब्यूट के नाम से पहले लगाया गया एक .:

>>> new_object = MyClass()

# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5

# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'

# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()

>>> second_new_object
# Note: the object address "at 0x15ad99970" will vary by computer.
<__main__.MyClass at 0x15ad99970>

# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True

क्लास एट्रिब्यूट क्लास के अंदर ही, बाकी किसी भी मेथड से पहले परिभाषित किए जाते हैं। ये क्लास के ही होते हैं, जिससे क्लास के सभी इंस्टेंस इन्हें साझा कर सकते हैं। चूँकि ये एट्रिब्यूट साझा होते हैं, इनकी वैल्यू का इस्तेमाल और बदलाव क्लास से सीधे किया जा सकता है। क्लास एट्रिब्यूट की वैल्यू बदलने पर क्लास से बने सभी ऑब्जेक्ट के लिए वैल्यू बदल जाती है:

>>> obj_one = MyClass()
>>> obj_two = MyClass()

# Accessing a class attribute from an object.
>>> obj_two.number
5

# Accessing the class attribute from the class itself.
>>> MyClass.number
5

# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27

# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27

>>> obj_two.number
27

हर समय एक जैसा डेटा रखने वाले ढेर सारे ऑब्जेक्ट होना कोई खास उपयोगी बात नहीं है। अच्छी बात यह है कि क्लास से बने ऑब्जेक्ट को उनके अपने instance attributes (या इंस्टेंस प्रॉपर्टी, वेरिएबल या फील्ड) की मदद से अपने हिसाब से बनाया जा सकता है। जैसा कि नाम से ही पता चलता है, इंस्टेंस एट्रिब्यूट हर ऑब्जेक्ट के लिए अलग होते हैं और इन्हें अलग-अलग बदला जा सकता है।

__init__() से ऑब्जेक्ट इंस्टैंशिएशन को अपने हिसाब से ढालना

विशेष "डंडर मेथड" (यानी "डबल अंडरस्कोर मेथड" का छोटा रूप) __init__() का इस्तेमाल क्लास इंस्टेंस को अपने हिसाब से बनाने के लिए किया जाता है, और इससे ऑब्जेक्ट के इंस्टेंस एट्रिब्यूट या प्रॉपर्टी को शुरुआती वैल्यू दी जा सकती है। इंस्टेंस एट्रिब्यूट को शुरुआती वैल्यू देने में इसकी भूमिका के कारण __init__() को class constructor या initializer भी कहा जाता है। __init__() एक ज़रूरी पैरामीटर लेता है जिसका नाम self है, और यह नए शुरू किए गए या नए बने ऑब्जेक्ट को दर्शाता है। इसके बाद self पैरामीटर के बाद, इंस्टेंस एट्रिब्यूट या प्रॉपर्टी का डेटा __init__() के आर्गुमेंट के रूप में दिया जा सकता है।

नीचे दिए उदाहरण में MyClass में अब location_x और location_y नाम के इंस्टेंस एट्रिब्यूट हैं। जैसा कि आप देख सकते हैं, ये दोनों एट्रिब्यूट __init__() को दिए गए location (एक टपल) आर्गुमेंट के पहले और दूसरे इंडेक्स पर असाइन किए गए हैं। जब आप क्लास का इंस्टेंस बनाते हैं, तो क्लास इंस्टेंस के location_x और location_y एट्रिब्यूट को शुरुआती वैल्यू मिल जाती है और ऑब्जेक्ट बन जाता है:

class MyClass:
    # These are class attributes, variables, or fields.
    number = 5
    string = "Hello!"

    # This is the class "constructor", with a "location" parameter that is a tuple.
    def __init__(self, location):

        # This is an instance or object property, attribute, or variable.
        # Note that we are unpacking the tuple argument into two separate instance variables.
        self.location_x = location[0]
        self.location_y = location[1]

# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))

# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))

# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1

>>> new_object_two.location_x
-8

ध्यान दीजिए कि ऊपर MyClass को शुरू करते समय आपको सिर्फ एक ही आर्गुमेंट देना होता है। क्लास को कॉल करने पर self भेजने का काम Python खुद कर लेता है।

मेथड

method एक ऐसा function है जो या तो खुद क्लास से बँधा होता है (जिसे क्लास मेथड कहते हैं, और इस पर आगे किसी अभ्यास में बात होगी) या क्लास के किसी इंस्टेंस (ऑब्जेक्ट) से। किसी ऑब्जेक्ट (इंस्टेंस) पर काम करने वाले मेथड को self को पहला पैरामीटर बनाकर परिभाषित करना होता है। इसके बाद बाकी पैरामीटर आप वैसे ही परिभाषित कर सकते हैं जैसे किसी "सामान्य" या बिना बँधे फंक्शन के लिए करते हैं:

class MyClass:
    number = 5
    string = "Hello!"

    # Class constructor.
    def __init__(self, location):
        # Instance properties
        self.location_x = location[0]
        self.location_y = location[1]

    # Instance method. Note "self" as first parameter.
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

एट्रिब्यूट की तरह ही, मेथड को कॉल करने के लिए बस ऑब्जेक्ट के नाम के बाद और मेथड के नाम से पहले एक . लगाना होता है। कॉल किए गए मेथड को पहले पैरामीटर के रूप में ऑब्जेक्ट की कोई प्रति देने की ज़रूरत नहीं होती। Python खुद ही self भर देता है:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)

# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)

क्लास एट्रिब्यूट का इस्तेमाल इंस्टेंस मेथड के अंदर भी उसी तरह किया जा सकता है जैसे क्लास के बाहर किया जाता है:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

    # Alter class variable number for all instances from within an instance.
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1


>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5

>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6

pass के साथ कार्यान्वयन को खाली छोड़ना या स्टब करना

पिछले कॉन्सेप्ट अभ्यासों और प्रैक्टिस अभ्यास के स्टब में, आपने फंक्शन के अंदर असली कोड की जगह pass कीवर्ड का इस्तेमाल देखा होगा। pass कीवर्ड सिंटैक्स की दृष्टि से मान्य प्लेसहोल्डर है। यह Python को खाली फंक्शन या क्लास की परिभाषा पर सिंटैक्स एरर देने से रोकता है। आसान शब्दों में कहें तो, यह Python इंटरप्रेटर से कहने का एक तरीका है: "चिंता मत करो! यहाँ कोड ज़रूर आएगा, बस अभी तक नहीं आया।"

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return  self.location_x, self.location_y

    # Alter class variable number for all instances
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1

    # This will compile and run without error, but has no current functionality.
    def pending_functionality(self):
       # Stubbing or placholding the body of this method.
       pass

निर्देश

एलेन एक ऐसा गेम बना रही है जिसमें खिलाड़ी को एलियन से लड़ना है। उसने अभी-अभी ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग (OOP) सीखी है और वह उत्सुक है कि classes के इस्तेमाल से उसके प्रोग्राम को क्या-क्या फायदा हो सकता है।

एलेन को बहुत खुशी हुई कि आपने मदद करने की पेशकश की, और उसने आपको वे एलियन प्रोग्राम करने का काम सौंपा है जिनसे खिलाड़ी को लड़ना है।

1. Alien क्लास बनाइए

Alien क्लास को एक ऐसे कंस्ट्रक्टर के साथ बनाइए जो दो पैरामीटर लेता है, <x_coordinate> और <y_coordinate>, और उन्हें x_coordinate तथा y_coordinate इंस्टेंस वेरिएबलो में रखता है। हर एलियन का हेल्थ लेवल भी शुरू में 3 होगा, इसलिए health वेरिएबल को भी इनिशियलाइज़ करना होगा।

>>> alien = Alien(2, 0)
>>> alien.x_coordinate
2
>>> alien.y_coordinate
0
>>> alien.health
3

अब हर एलियन अपनी जगह और अपनी हेल्थ खुद ट्रैक कर सकेगा।

2. hit मेथड

एलेन चाहती है कि Alien class में एक hit मेथड हो, जो कॉल किए जाने पर एलियन ऑब्जेक्ट की हेल्थ 1 कम कर दे। इस तरह वह एलियन की हेल्थ हाथ से बदलने के बजाय सीधे <alien>.hit() कॉल कर सकती है। यह आप पर है कि hit() हेल्थ पॉइंट्स को शून्य तक पहुँचाता है या शून्य से नीचे भी ले जाता है।

>>> alien = Alien(0, 0)

# Initialized health value.
>>> alien.health
3

# Decrements health by 1 point.
>>> alien.hit()
>>> alien.health
2

3. is_alive मेथड

आपको समझ आता है कि अगर हेल्थ ऐसे ही घटती रही, तो किसी समय वह शायद 0 तक पहुँच जाएगी (या उससे भी नीचे!)। बेहतर होगा कि एक is_alive मेथड जोड़ दिया जाए, जिसे एलेन झट से कॉल करके देख सके कि एलियन... वैसे... ज़िंदा है या नहीं। 😉 <alien>.is_alive() को एक बूलियन लौटाना चाहिए।

>>> alien.health
1
>>> alien.is_alive()
True
>>> alien.hit()
>>> alien.health
0
>>> alien.is_alive()
False

4. teleport मेथड

एलेन के गेम में एलियन टेलीपोर्ट कर सकते हैं! आपको एक teleport मेथड लिखना होगा जो नई x_coordinate और y_coordinate वैल्यू लेता है और उसी हिसाब से एलियन के निर्देशांक बदल देता है।

>>> alien.teleport(5, -4)
>>> alien.x_coordinate
5
>>> alien.y_coordinate
-4

5. collision_detection मेथड

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

>>> alien.collision_detection(other_object)
>>>

6. एलियन काउंटर

एलेन एक नई माँग लेकर लौटी है। वह जानना चाहती है कि गेम के दौरान अब तक कितने एलियन बन चुके हैं। उसके मुताबिक इसका स्कोरिंग सिस्टम से कुछ संबंध है।

उदाहरण के लिए:

>>> alien_one = Alien(5, 1)
>>> alien_one.total_aliens_created
1
>>> alien_two = Alien(3, 0)
>>> alien_two.total_aliens_created
2
>>> alien_one.total_aliens_created
2
# Accessing the variable from the class directly
>>> Alien.total_aliens_created
2

7. एलियन की सूची बनाइए

एलेन को आपका अब तक का काम बहुत पसंद आया है, पर उसे एक और मदद चाहिए। वह चाहती है कि एक अलग (Alien() क्लास के बाहर) फंक्शन हो, जो पोज़िशन की सूची (जो tuples के रूप में दी गई हो) लेकर Alien() ऑब्जेक्ट की list बनाए।

उदाहरण के लिए:

>>> alien_start_positions = [(4, 7), (-1, 0)]
>>> aliens = new_aliens_collection(alien_start_positions)
...
>>> for alien in aliens:
...     print(alien.x_coordinate, alien.y_coordinate)
(4, 7)
(-1, 0)
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Python Exercism

एलेन का एलियन गेम शुरू करने के लिए तैयार हैं?

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