paint-brush
কিভাবে Alpine.js এবং Deck of Cards API দিয়ে একটি Blackjack গেম তৈরি করবেনদ্বারা@raymondcamden
1,176 পড়া
1,176 পড়া

কিভাবে Alpine.js এবং Deck of Cards API দিয়ে একটি Blackjack গেম তৈরি করবেন

দ্বারা Raymond Camden6m2023/07/20
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

Deck of Cards API কার্ডের ডেকের সাথে কাজ করার সাথে সম্পর্কিত কল্পনাযোগ্য সবকিছু পরিচালনা করে। এটি কার্ডের একটি এলোমেলো সেট তৈরি (এক বা একাধিক ডেক ধারণকারী), একটি কার্ড (বা কার্ড) ডিল করা এবং এমনকি রিসাফলিং পরিচালনা করে। এটি একটি অবিশ্বাস্যভাবে বৈশিষ্ট্য-পূর্ণ API, এবং সর্বোপরি, এটি সম্পূর্ণ বিনামূল্যে।
featured image - কিভাবে Alpine.js এবং Deck of Cards API দিয়ে একটি Blackjack গেম তৈরি করবেন
Raymond Camden HackerNoon profile picture

কিছু সময় আগে, আমি একটি চমত্কার চিত্তাকর্ষক পরিষেবা জুড়ে দৌড়েছিলাম, ডেক অফ কার্ডস এপিআই ৷ এই API কার্ডের ডেকের সাথে কাজ করার সাথে সম্পর্কিত কল্পনাযোগ্য সবকিছু পরিচালনা করে। এটি কার্ডের একটি এলোমেলো সেট তৈরি (এক বা একাধিক ডেক ধারণকারী), একটি কার্ড (বা কার্ড), এমনকি রদবদল করা পরিচালনা করে।


আরও ভাল, এতে কার্ডের ছবিগুলি অন্তর্ভুক্ত রয়েছে যা আপনি ব্যবহার করতে পারেন যদি আপনি নিজের সন্ধান করতে না চান:


এটি একটি অবিশ্বাস্যভাবে বৈশিষ্ট্য-পূর্ণ API, এবং সর্বোপরি, এটি সম্পূর্ণ বিনামূল্যে। এমনকি চাবিরও দরকার নেই। আমি কিছু সময়ের জন্য এই API সম্পর্কে জেনেছি এবং এটির সাথে একটি কার্ড গেম তৈরি করার চিন্তা করেছি, কিন্তু বুঝতে পেরেছি যে গেমগুলি দ্রুত সহজ থেকে মোটামুটি জটিল হতে পারে।


প্রকৃতপক্ষে, আমার বন্ধুরা আমাকে দৃঢ়ভাবে এই বিষয়ে সময় ব্যয় না করার জন্য অনুরোধ করেছিল, এবং সত্যই, তারা সম্ভবত সঠিক ছিল, কিন্তু আমি বিল্ডিং কোড ডেমোগুলির একটি দীর্ঘ ইতিহাস পেয়েছি যা অর্থহীন। ;)


আমার ডেমোর জন্য, আমি নিম্নলিখিত নিয়মগুলির সাথে গিয়েছিলাম:


  • স্পষ্টতই, মৌলিক ব্ল্যাকজ্যাক নিয়ম, যতটা সম্ভব না গিয়ে 21-এর কাছাকাছি যাওয়ার চেষ্টা করুন।


  • কোনো পণ নেই, একবারে এক হাতে।


  • ডাউন ডাউন বা স্প্লিটিং নেই।


  • ডিলার একটি "নরম 17" নিয়ম আছে. (আমি বেশিরভাগই নিশ্চিত যে আমি এটি ঠিক করেছি।)


  • গেমটি ছয়টি ডেক ব্যবহার করে (আমি কোথাও পড়েছি যে এটি মানক ছিল)।

গেম সেটআপ

প্রাথমিকভাবে, প্লেয়ার এবং কম্পিউটার উভয়েরই তাদের হাতের প্রতিনিধিত্ব করে একটি অ্যারে থাকে।


 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";

খেলা যুক্তিবিদ্যা

সুতরাং, এই মুহুর্তে, আমি অ্যাপটি আঘাত করতে পারি এবং একটি ব্ল্যাকজ্যাক হাত পেতে পারি:


কার্ডের ডেমো প্রদর্শিত হয়েছে


নীচে, আমি বর্তমান অবস্থা প্রদর্শন করতে একটি ডিভ ব্যবহার করেছি:


সাদা স্ট্যাটাস বক্স খেলোয়াড়কে জিজ্ঞেস করে তারা কি করতে চায়।


আমার যুক্তি ছিল এরকম:


  • প্লেয়ার দিয়ে শুরু করুন এবং তাদের আঘাত করতে বা দাঁড়াতে দিন।


  • যদি তারা আঘাত করে, একটি নতুন কার্ড যোগ করুন, এবং দেখুন যে তারা ভাঙ্গা হয়েছে কিনা।


  • যদি তারা দাঁড়ায়, ডিলার প্লেয়ার যাক.


প্রথমে প্লেয়ারের উপর ফোকাস করা যাক। আঘাত করতে, আমরা কেবল একটি কার্ড যোগ করি:


 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; },


বক্ষ চেকিং একটু জটিল ছিল। আমি হাতের জন্য 'গণনা' পেতে একটি ফাংশন তৈরি করেছি, কিন্তু ব্ল্যাকজ্যাকে, Aces 1 বা 11 হতে পারে।


আমি বুঝতে পেরেছি (এবং আশা করি আমি ঠিকই বলেছি), আপনার কখনই দুটি 'উচ্চ' টেপ থাকতে পারে না, তাই আমার ফাংশন একটি lowCount এবং highCount মান প্রদান করে যেখানে উচ্চ সংস্করণের জন্য, যদি একটি Ace বিদ্যমান থাকে তবে এটি 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; } } }


FYI, pcText সাদা স্ট্যাটাস এলাকায় গেম মেসেজ সেট করার উপায় হিসেবে ব্যবহার করা হয়।


এবং মূলত - এটাই। আপনি যদি এটি নিজে খেলতে চান, নীচের কোডপেনটি দেখুন এবং নির্দ্বিধায় এটিকে কাঁটাচামচ করতে এবং উন্নতিগুলি যোগ করুন: