कुछ समय पहले, मेरी नज़र एक बहुत ही आकर्षक सेवा, डेक ऑफ़ कार्ड्स एपीआई पर पड़ी। यह एपीआई कार्ड के डेक के साथ काम करने से संबंधित हर कल्पना को संभालता है। यह कार्डों का एक फेरबदल किया हुआ सेट (एक या अधिक डेक वाले) बनाने, एक कार्ड (या कार्ड) को निपटाने और यहां तक कि फेरबदल करने का काम भी संभालता है।
इससे भी बेहतर, इसमें कार्ड छवियां शामिल हैं जिनका उपयोग आप कर सकते हैं यदि आप अपना खुद का नहीं ढूंढना चाहते हैं:
यह एक अविश्वसनीय रूप से सुविधाओं से भरपूर एपीआई है, और सबसे अच्छी बात यह है कि यह पूरी तरह से मुफ़्त है। चाबी की भी जरूरत नहीं. मैं इस एपीआई के बारे में कुछ समय से जानता हूं और मैंने इसके साथ एक कार्ड गेम बनाने पर विचार किया है, लेकिन मुझे एहसास हुआ कि गेम जल्दी ही सरल से काफी जटिल तक जा सकते हैं।
वास्तव में, मेरे दोस्तों ने मुझसे दृढ़तापूर्वक इस पर समय बर्बाद न करने का आग्रह किया, और ईमानदारी से कहूं तो, वे शायद सही थे, लेकिन मेरे पास बिल्डिंग कोड डेमो का एक लंबा इतिहास है जिसका कोई मतलब नहीं है। ;)
अपने डेमो के लिए, मैं निम्नलिखित नियमों के साथ गया:
प्रारंभ में, प्लेयर और कंप्यूटर दोनों के पास उनके हाथों का प्रतिनिधित्व करने वाली एक सरणी होती है।
playerCards:[], pcCards:[],
deal
पद्धति दोनों खिलाड़ियों के लिए हाथ सेट करने को संभालती है:
async deal() { // first to player, then PC, then player, then PC this.playerCards.push(await this.drawCard()); // for the dealer, the first card is turned over let newcard = await this.drawCard(); newcard.showback = true; this.pcCards.push(newcard); this.playerCards.push(await this.drawCard()); this.pcCards.push(await this.drawCard()); },
दो बातें इंगित करने योग्य हैं। सबसे पहले, मैं खिलाड़ी से डील करता हूं, फिर पीसी से (या डीलर से, नाम के हिसाब से मैं आगे-पीछे जाता हूं), और फिर वापस आता हूं। मैं showback
सेट के लिए कार्ड परिणाम ऑब्जेक्ट को भी संशोधित करता हूं ताकि मैं डीलर के लिए कार्ड का पिछला भाग प्रस्तुत कर सकूं।
HTML में यह इस प्रकार किया जाता है:
<div id="pcArea" class="cardArea"> <h3>Dealer</h3> <template x-for="card in pcCards"> <!-- todo: don't like the logic in template --> <img :src="card.showback?BACK_CARD:card.image" :title="card.showback?'':card.title"> </template> </div> <div id="playerArea" class="cardArea"> <h3>Player</h3> <template x-for="card in playerCards"> <img :src="card.image" :title="card.title"> </template> </div>
BACK_CARD
बस एक स्थिरांक है:
const BACK_CARD = "https://deckofcardsapi.com/static/img/back.png";
तो, इस बिंदु पर, मैं ऐप पर क्लिक कर सकता हूं और ब्लैकजैक हाथ प्राप्त कर सकता हूं:
नीचे, मैंने वर्तमान स्थिति प्रदर्शित करने के लिए एक div का उपयोग किया:
मेरा तर्क इस प्रकार था:
आइए पहले खिलाड़ी पर ध्यान दें। हिट करने के लिए, हम बस एक कार्ड जोड़ते हैं:
async hitMe() { this.hitMeDisabled = true; this.playerCards.push(await this.drawCard()); let count = this.getCount(this.playerCards); if(count.lowCount >= 22) { this.playerTurn = false; this.playerBusted = true; } this.hitMeDisabled = false; },
बस्ट जाँच करना थोड़ा जटिल था। मैंने हाथ की 'गिनती' प्राप्त करने के लिए एक फ़ंक्शन बनाया, लेकिन ब्लैकजैक में, इक्के 1 या 11 हो सकते हैं।
मुझे पता चला (और आशा है कि मैं सही हूं), कि आपके पास कभी भी दो 'उच्च' इक्के नहीं हो सकते हैं, इसलिए मेरा फ़ंक्शन एक lowCount
और highCount
मान लौटाता है, जहां उच्च संस्करण के लिए, यदि एक ऐस मौजूद है, तो इसे 11 के रूप में गिना जाता है, लेकिन केवल एक। यहाँ वह तर्क है:
getCount(hand) { /* For a hand, I return 2 values, a low value, where aces are considered 1s, and a high value, where aces are 11. Note that this fails to properly handle a case where I have 3 aces and could have a mix... although thinking about it, you can only have ONE ace at 11, so maybe the logic is: low == all aces at 1. high = ONE ace at 11. fixed! */ let result = {}; // first we will do low, all 1s let lowCount = 0; for(card of hand) { if(card.value === 'JACK' || card.value === 'KING' || card.value === 'QUEEN') lowCount+=10; else if(card.value === 'ACE') lowCount += 1; else lowCount += Number(card.value); //console.log(card); } //console.log('lowCount', lowCount); let highCount = 0; let oneAce = false; for(card of hand) { if(card.value === 'JACK' || card.value === 'KING' || card.value === 'QUEEN') highCount+=10; else if(card.value === 'ACE') { if(oneAce) highCount += 1; else { highCount += 10; oneAce = true; } } else highCount += Number(card.value); } //console.log('highCount', highCount); return { lowCount, highCount }; },
यदि खिलाड़ी विफल हो जाता है, तो हम खेल समाप्त कर देते हैं और उपयोगकर्ता को फिर से शुरू करने देते हैं। यदि वे खड़े रहते हैं, तो डीलर के लिए कार्यभार संभालने का समय आ गया है। वह तर्क सरल था - 17 से नीचे हिट करें और या तो बस्ट करें या खड़े रहें।
इसे थोड़ा और रोमांचक बनाने के लिए, मैंने डीलर के कार्यों को धीमा करने के लिए एक वेरिएबल और एसिंक फ़ंक्शन, delay
उपयोग किया, ताकि आप उन्हें (थोड़े) वास्तविक समय में खेलते हुए देख सकें। यहाँ डीलर का तर्क है:
async startDealer() { /* Idea is - I take a card everytime I'm < 17. so i check my hand, and do it, see if im going to stay or hit. if hit, i do a delay though so the game isn't instant. */ // really first, initial text this.pcText = 'The dealer begins their turn...'; await delay(DEALER_PAUSE); // first, a pause while we talk this.pcText = 'Let me show my hand...'; await delay(DEALER_PAUSE); // reveal my second card this.pcCards[0].showback = false; // what does the player have, we need the best under 22 let playerCount = this.getCount(this.playerCards); let playerScore = playerCount.lowCount; if(playerCount.highCount < 22) playerScore = playerCount.highCount; //console.log('dealer needs to beat', playerScore); // ok, now we're going to loop until i bust/win let dealerLoop = true; while(dealerLoop) { let count = this.getCount(this.pcCards); /* We are NOT doing 'soft 17', so 1 ace always count as 11 */ if(count.highCount <= 16) { this.pcText = 'Dealer draws a card...'; await delay(DEALER_PAUSE); this.pcCards.push(await this.drawCard()); } else if(count.highCount <= 21) { this.pcText = 'Dealer stays...'; await delay(DEALER_PAUSE); dealerLoop = false; this.pcTurn = false; if(count.highCount >= playerScore) this.pcWon = true; else this.playerWon = true; } else { dealerLoop = false; this.pcTurn = false; this.pcBusted = true; } } }
आपकी जानकारी के लिए, गेम संदेशों को सेट करने के तरीके के रूप में pcText
उपयोग सफेद स्थिति क्षेत्र में किया जाता है।
और मूलतः - बस इतना ही. यदि आप इसे स्वयं खेलना चाहते हैं, तो नीचे दिए गए कोडपेन को देखें, और बेझिझक इसे फोर्क करें और सुधार जोड़ें: