आप अपने सिस्टम को देख सकते हैं जैसे कि यह राज्यों और कार्यों की एक श्रृंखला से बना है, जहां f[j]
इनपुट के साथ एक फ़ंक्शन x[j]
सिस्टम स्थिति s[j]
को राज्य में बदलता है s[j+1]
, जैसे:
s[j+1] = f[j](s[j], x[j])
एक राज्य आपकी पूरी दुनिया की व्याख्या है। खिलाड़ी के स्थान, दुश्मन के स्थान, स्कोर, शेष बारूद, आदि। सब कुछ आप अपने खेल का एक फ्रेम आकर्षित करने की आवश्यकता है।
एक फ़ंक्शन कुछ भी है जो दुनिया को प्रभावित कर सकता है। एक फ्रेम परिवर्तन, एक कीपर, एक नेटवर्क पैकेट।
इनपुट वह डेटा है जिसे फ़ंक्शन लेता है। अंतिम फ़्रेम पास होने के बाद एक फ़्रेम परिवर्तन में समय की मात्रा लग सकती है, कुंजीपट में वास्तविक कुंजी दबाया जा सकता है, साथ ही शिफ्ट कुंजी दबाया गया था या नहीं।
इस स्पष्टीकरण के लिए, मैं निम्नलिखित धारणाएँ बनाऊंगा:
अनुमान 1:
गेम के दिए गए रन के लिए राज्यों की मात्रा कार्यों की मात्रा से बहुत बड़ी है। आपके पास संभवतः सैकड़ों हजारों राज्य हैं, लेकिन केवल कई दर्जन फ़ंक्शन (फ़्रेम परिवर्तन, कीबोर्ड, नेटवर्क पैकेट, आदि)। निस्संदेह, इनपुट की राशि राज्यों के ऋण की राशि के बराबर होनी चाहिए।
अनुमान 2:
किसी एक राज्य के भंडारण की स्थानिक लागत (मेमोरी, डिस्क) एक कार्य और उसके इनपुट को संग्रहित करने से बहुत अधिक होती है।
अनुमान 3:
किसी राज्य को प्रस्तुत करने की लौकिक लागत (समय) समान है, या किसी राज्य के कार्य की गणना करने की तुलना में अधिक समय के एक या दो आदेश।
आपके रिप्ले सिस्टम की आवश्यकताओं के आधार पर, रीप्ले सिस्टम को लागू करने के कई तरीके हैं, इसलिए हम सबसे सरल के साथ शुरू कर सकते हैं। मैं कागज के टुकड़ों पर दर्ज शतरंज के खेल का उपयोग करके एक छोटा सा उदाहरण भी लिखूंगा।
विधि 1:
स्टोर s[0]...s[n]
। यह बहुत सरल है, बहुत सीधा है। 2 धारणा के कारण, इस की स्थानिक लागत काफी अधिक है।
शतरंज के लिए, यह प्रत्येक चाल के लिए पूरे बोर्ड को खींचकर पूरा किया जाएगा।
विधि 2:
यदि आपको केवल फॉरवर्ड रिप्ले की आवश्यकता है, तो आप बस स्टोर कर सकते हैं s[0]
, और फिर स्टोर कर सकते हैं f[0]...f[n-1]
(याद रखें, यह केवल फ़ंक्शन की आईडी का नाम है) और x[0]...x[n-1]
(इन कार्यों में से प्रत्येक के लिए इनपुट क्या था)। फिर से खेलना करने के लिए, आप बस के साथ शुरू करते हैं s[0]
, और गणना करते हैं
s[1] = f[0](s[0], x[0])
s[2] = f[1](s[1], x[1])
और इसी तरह...
मैं यहां एक छोटा सा एनोटेशन करना चाहता हूं। कई अन्य टिप्पणीकारों ने कहा कि खेल "निर्धारक होना चाहिए"। जो कोई भी कहता है कि कंप्यूटर साइंस 101 को फिर से लेने की आवश्यकता है, क्योंकि जब तक आपका गेम क्वांटम कंप्यूटर पर चलने का नहीं है, सभी कंप्यूटर प्रोग्राम डीटेरिमिनिस्टिक हैं। यही कारण है कि कंप्यूटर इतना भयानक है।
हालाँकि, चूंकि आपका कार्यक्रम सबसे अधिक संभावना बाहरी कार्यक्रमों पर निर्भर करता है, पुस्तकालयों से लेकर सीपीयू के वास्तविक कार्यान्वयन तक, यह सुनिश्चित करना कि आपके कार्य प्लेटफ़ॉर्म के बीच समान व्यवहार करते हैं, काफी मुश्किल हो सकता है।
यदि आप छद्म यादृच्छिक संख्याओं का उपयोग करते हैं, तो आप या तो अपने इनपुट के हिस्से के रूप में उत्पन्न संख्याओं को स्टोर कर सकते हैं x
, या अपने राज्य के हिस्से के रूप में प्रिंग फ़ंक्शन की स्थिति s
, और फ़ंक्शन के भाग के रूप में इसके कार्यान्वयन को स्टोर कर सकते हैं f
।
शतरंज के लिए, यह प्रारंभिक बोर्ड (जो ज्ञात है) को आरेखित करके पूरा किया जाएगा और फिर प्रत्येक चाल का वर्णन करते हुए कहा जाएगा कि कौन सा टुकड़ा कहाँ गया। यह है कि वे वास्तव में इसे कैसे करते हैं, वैसे।
विधि 3:
अब, आप सबसे अधिक संभावना है कि आप फिर से खेलना चाहते हैं। यही है, s[n]
एक मनमानी के लिए गणना करें n
। विधि 2 का उपयोग करके, आपको गणना करने s[0]...s[n-1]
से पहले गणना करने की आवश्यकता है s[n]
, जो कि धारणा 2 के अनुसार, काफी धीमी हो सकती है।
इसे लागू करने के लिए, विधि 3, विधियों 1 और 2 का एक सामान्यीकरण है: स्टोर f[0]...f[n-1]
और x[0]...x[n-1]
विधि 2 की तरह, लेकिन स्टोर भी s[j]
, सभी के j % Q == 0
लिए एक निरंतर Q
। आसान शब्दों में, इसका मतलब है कि आप प्रत्येक Q
राज्य में से एक पर एक बुकमार्क स्टोर करते हैं। उदाहरण के लिए Q == 100
, आप स्टोर करते हैंs[0], s[100], s[200]...
s[n]
एक मनमानी के लिए गणना करने के लिए n
, आप पहले संग्रहीत पहले लोड करते हैं s[floor(n/Q)]
, और फिर से सभी कार्यों की गणना floor(n/Q)
करते हैं n
। अधिक से अधिक, आप Q
कार्यों की गणना करेंगे । छोटे मानों की Q
गणना तेजी से Q
होती है, लेकिन अधिक स्थान की खपत करते हैं, जबकि कम स्थान की खपत के बड़े मूल्य , लेकिन गणना करने में अधिक समय लेते हैं।
पद्धति 3 के साथ Q==1
विधि 1 के समान है, जबकि विधि 3 के साथ Q==inf
विधि 2 के समान है।
शतरंज के लिए, यह हर चाल को पूरा करने के साथ-साथ हर 10 बोर्ड (एक Q==10
) में से एक होगा।
विधि 4:
आप पुनरावृत्ति रिवर्स करना चाहते हैं, तो आप विधि 3. का एक छोटा सा बदलाव मान लीजिए कर सकते हैं Q==100
, और आप गणना करना चाहते हैं s[150]
के माध्यम से s[90]
रिवर्स में। अनमॉडिफाइड विधि 3 के साथ, आपको प्राप्त करने के लिए 50 गणना करने की आवश्यकता होगी s[150]
और फिर प्राप्त करने के लिए 49 और अधिक गणना करनी होगी s[149]
। लेकिन जब से आप पहले से ही s[149]
प्राप्त करने के लिए गणना करते हैं s[150]
, s[100]...s[150]
तब आप s[150]
पहली बार गणना करने के साथ कैश बना सकते हैं और तब आप पहले s[149]
से ही कैश में होते हैं जब आपको इसे प्रदर्शित करने की आवश्यकता होती है।
आप केवल कैश हर बार जब आप की गणना करनी है पुनर्जीवित करने के लिए की जरूरत है s[j]
, के लिए j==(k*Q)-1
किसी भी के लिए k
। इस बार, बढ़ने Q
का परिणाम छोटे आकार (सिर्फ कैश के लिए) होगा, लेकिन अधिक समय (बस कैश को पुनः प्राप्त करने के लिए) होगा। Q
यदि आप राज्यों और कार्यों की गणना करने के लिए आवश्यक आकारों और समय को जानते हैं, तो इसके लिए एक इष्टतम मूल्य की गणना की जा सकती है।
शतरंज के लिए, यह हर चाल को पूरा करने के साथ-साथ प्रत्येक 10 बोर्डों (के लिए Q==10
) में एक पूरा किया जाएगा , लेकिन इसके अलावा, इसे कागज के एक अलग टुकड़े में ड्रा करना होगा, पिछले 10 बोर्ड जिनकी आपने गणना की है।
विधि 5:
यदि राज्य केवल बहुत अधिक स्थान का उपभोग करते हैं, या फ़ंक्शन बहुत अधिक समय लेते हैं, तो आप एक समाधान बना सकते हैं जो वास्तव में लागू होता है (नकली नहीं) उल्टा दोहराता है। ऐसा करने के लिए, आपको प्रत्येक फ़ंक्शन के लिए रिवर्स फ़ंक्शन बनाने होंगे। हालाँकि, इसके लिए आवश्यक है कि आपका प्रत्येक कार्य एक इंजेक्शन हो। यदि यह उल्लेखनीय है, तो f'
फ़ंक्शन के व्युत्क्रम को निरूपित करने के लिए f
, गणना s[j-1]
करना उतना ही सरल है
s[j-1] = f'[j-1](s[j], x[j-1])
ध्यान दें कि यहां, फ़ंक्शन और इनपुट दोनों हैं j-1
, नहीं j
। यदि आप गणना कर रहे थे तो यह वही फ़ंक्शन और इनपुट होगा जिसका आपने उपयोग किया होगा
s[j] = f[j-1](s[j-1], x[j-1])
इन कार्यों का उलटा बनाना मुश्किल हिस्सा है। हालाँकि, आप आमतौर पर नहीं कर सकते हैं, क्योंकि कुछ राज्य डेटा आमतौर पर एक गेम में प्रत्येक फ़ंक्शन के बाद खो जाता है।
यह विधि, जैसा है, गणना को उल्टा कर सकता है s[j-1]
, लेकिन केवल अगर आपके पास है s[j]
। इसका मतलब यह है कि आप केवल रिप्ले को पीछे की तरफ देख सकते हैं, उस बिंदु से शुरू कर सकते हैं जिस पर आपने पीछे की ओर फिर से खेलना का फैसला किया था। यदि आप एक मनमाना बिंदु से पीछे की ओर खेलना चाहते हैं, तो आपको इसे विधि 4 के साथ मिलाना होगा।
शतरंज के लिए, इसे लागू नहीं किया जा सकता है, क्योंकि किसी दिए गए बोर्ड और पिछले कदम के साथ, आप जान सकते हैं कि कौन सा टुकड़ा स्थानांतरित किया गया था, लेकिन जहां से इसे स्थानांतरित नहीं किया गया था।
विधि 6:
अंत में, यदि आप गारंटी नहीं दे सकते कि आपके सभी कार्य इंजेक्शन हैं, तो आप ऐसा करने के लिए एक छोटी सी चाल बना सकते हैं। प्रत्येक फ़ंक्शन को केवल एक नया, राज्य वापस करने के बजाय, आप इसे छोड़ दिए गए डेटा को भी वापस कर सकते हैं, जैसे:
s[j+1], r[j] = f[j](s[j], x[j])
कहाँ r[j]
खारिज डाटा नहीं है। और फिर अपने उलटा कार्य करें ताकि वे डेटा को छोड़ दें, जैसे:
s[j] = f'[j](s[j+1], x[j], r[j])
के अलावा f[j]
और x[j]
, आप भी स्टोर चाहिए r[j]
प्रत्येक कार्य के लिए। एक बार फिर, यदि आप तलाश करना चाहते हैं, तो आपको बुकमार्क स्टोर करना होगा, जैसे कि विधि 4।
शतरंज के लिए, यह विधि 2 के समान ही होगा, लेकिन विधि 2 के विपरीत, जो केवल कहता है कि कौन सा टुकड़ा कहां जाता है, आपको यह भी संग्रहीत करने की आवश्यकता है कि प्रत्येक टुकड़ा कहां से आया है।
कार्यान्वयन:
चूंकि यह सभी प्रकार के राज्यों के लिए काम करता है, सभी प्रकार के कार्यों के साथ, एक विशिष्ट खेल के लिए, आप कई धारणाएं बना सकते हैं, जिससे इसे लागू करना आसान हो जाएगा। वास्तव में, यदि आप पूरे खेल राज्य के साथ विधि 6 को लागू करते हैं, तो न केवल आप डेटा को फिर से खेलना कर पाएंगे, बल्कि समय पर वापस भी जाएंगे और किसी भी क्षण से खेलना फिर से शुरू करेंगे। यह बहुत बढ़िया होगा।
सभी खेल राज्य को संग्रहीत करने के बजाय, आप बस उस न्यूनतम न्यूनतम स्टोर कर सकते हैं जिसे आपको किसी दिए गए राज्य को खींचने की आवश्यकता है, और इस डेटा को हर निश्चित समय पर क्रमबद्ध करें। आपके राज्य ये क्रमबद्धताएँ होंगे, और आपका इनपुट अब दो क्रमिकताओं के बीच का अंतर होगा। वे इस काम के लिए महत्वपूर्ण हैं कि अगर दुनिया की स्थिति में थोड़ा भी बदलाव आता है तो धारावाहिक परिवर्तन होना चाहिए। यह अंतर पूरी तरह से व्युत्क्रम है, इसलिए बुकमार्क के साथ विधि 5 को लागू करना बहुत संभव है।
मैंने इसे कुछ प्रमुख खेलों में लागू किया है, ज्यादातर हाल ही में डेटा के पुनरावृत्ति के लिए जब एक घटना (एफपीएस में एक टुकड़ा, या खेल के खेल में एक स्कोर) होती है।
मुझे आशा है कि यह स्पष्टीकरण बहुत उबाऊ नहीं था।
Some इसका मतलब यह नहीं है कि कुछ कार्यक्रम गैर-नियतात्मक हैं (जैसे एमएस विंडोज ^ ^)। अब गंभीरता से, यदि आप एक निर्धारक कंप्यूटर पर एक गैर-नियतात्मक कार्यक्रम बना सकते हैं, तो आप बहुत आश्वस्त हो सकते हैं कि आप एक साथ फील्ड्स मेडल, ट्यूरिंग पुरस्कार और शायद सभी के लिए ऑस्कर और ग्रैमी भी जीत लेंगे।