paint-brush
Alpine.js ve Kart Destesi API'si ile Blackjack Oyunu Nasıl Oluşturulurile@raymondcamden
1,176 okumalar
1,176 okumalar

Alpine.js ve Kart Destesi API'si ile Blackjack Oyunu Nasıl Oluşturulur

ile Raymond Camden6m2023/07/20
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Kart Destesi API'si, kart desteleriyle çalışmayla ilgili akla gelebilecek her şeyi yönetir. Karıştırılmış bir kart seti (bir veya daha fazla deste içeren) oluşturmayı, bir kartı (veya kartları) dağıtmayı ve hatta yeniden karıştırmayı yönetir. İnanılmaz derecede özelliklerle dolu bir API'dir ve hepsinden önemlisi tamamen ücretsizdir.
featured image - Alpine.js ve Kart Destesi API'si ile Blackjack Oyunu Nasıl Oluşturulur
Raymond Camden HackerNoon profile picture

Bir süre önce oldukça etkileyici bir hizmetle karşılaştım: Kart Destesi API'si . Bu API, kart desteleriyle çalışmayla ilgili akla gelebilecek her şeyi yönetir. Karıştırılmış bir kart seti (bir veya daha fazla deste içeren) oluşturmayı, bir kartı (veya kartları) dağıtmayı ve hatta yeniden karıştırmayı yönetir.


Daha da iyisi, kendi kart görsellerinizi bulmak istemiyorsanız kullanabileceğiniz kart görsellerini içerir:


İnanılmaz derecede özelliklerle dolu bir API'dir ve hepsinden önemlisi tamamen ücretsizdir. Anahtara bile gerek yok. Bu API'yi bir süredir biliyordum ve onunla bir kart oyunu oluşturmayı düşündüm, ancak oyunların basitten oldukça karmaşık hale hızla geçebileceğini fark ettim.


Aslında arkadaşlarım buna zaman harcamamam konusunda beni şiddetle teşvik ettiler ve dürüst olmak gerekirse, muhtemelen haklıydılar, ancak hiçbir anlam ifade etmeyen kod demoları oluşturma konusunda uzun bir geçmişim var. ;)


Demom için aşağıdaki kurallara uydum:


  • Açıkçası, temel Blackjack kuralları, 21'i aşmadan mümkün olduğunca yaklaşmaya çalışın.


  • Bahis yok, her seferinde tek el.


  • İki katına çıkarma veya bölme yok.


  • Dağıtıcının "yumuşak 17" kuralı vardır. (Bunu doğru yaptığımdan çoğunlukla eminim.)


  • Oyun altı deste kullanıyor (bir yerde standart olduğunu okudum).

Oyun Kurulumu

Başlangıçta hem oyuncu hem de bilgisayar, ellerini temsil eden bir diziye sahiptir.


 playerCards:[], pcCards:[],


deal yöntemi her iki oyuncu için de ellerin ayarlanmasını yönetir:


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


Dikkat edilmesi gereken iki şey. Önce oyuncuyla, sonra PC'yle (ya da dağıtıcıyla, isim olarak ileri geri gidiyorum) ve sonra tekrar geri dönüyorum. Ayrıca kart sonuç nesnesini, kartın arkasını krupiyer için oluşturabileceğim şekilde showback sahip olacak şekilde değiştiriyorum.


HTML'de bunun nasıl yapıldığı aşağıda açıklanmıştır:


 <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 basitçe bir sabittir:


 const BACK_CARD = "https://deckofcardsapi.com/static/img/back.png";

Oyun Mantığı

Yani bu noktada uygulamaya tıklayıp Blackjack eli alabilirim:


Görüntülenen kartların demosu


Altta mevcut durumu görüntülemek için bir div kullandım:


Beyaz durum kutusu oyuncuya ne yapmak istediğini sorar.


Benim mantığım şöyleydi:


  • Oyuncuyla başlayın ve vurmalarına veya ayakta durmalarına izin verin.


  • Vururlarsa yeni bir kart ekleyin ve patlayıp patlamadığına bakın.


  • Eğer ayakta dururlarsa krupiyenin oyuncusuna izin verin.


Önce oyuncuya odaklanalım. Vurmak için bir kart eklememiz yeterli:


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


Göğüs kontrolü biraz karmaşıktı. Elin 'sayımını' elde etmek için bir fonksiyon geliştirdim, ancak Blackjack'te Aslar 1 veya 11 olabilir.


Asla iki 'yüksek' asa sahip olamayacağınızı anladım (ve umarım haklıyımdır), bu nedenle işlevim bir lowCount ve highCount değeri döndürür; burada yüksek sürüm için, eğer bir As varsa, 11 olarak sayılır, ancak yalnızca bir. İşte o mantık:


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


Eğer oyuncu bozulursa oyunu sonlandırıyoruz ve kullanıcının baştan başlamasına izin veriyoruz. Eğer ayakta kalırlarsa, krupiyerin görevi devralma zamanı gelmiştir. Bu mantık basitti; 17'nin altındayken vurun ve ya çökün ya da ayakta kalın.


Bunu biraz daha heyecanlı hale getirmek için, dağıtıcının eylemlerini yavaşlatmak için değişken ve eşzamansız bir işlev olan delay kullandım, böylece bunların (bir nevi) gerçek zamanlı olarak oynandığını görebilirsiniz. İşte krupiyenin mantığı:


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


Bilginize, pcText beyaz durum alanında oyun mesajlarını ayarlamanın bir yolu olarak kullanılır.


Ve temelde - işte bu. Kendiniz oynamak istiyorsanız, aşağıdaki CodePen'e göz atın ve onu çatallamaktan ve iyileştirmeler eklemekten çekinmeyin: