21 Kart Oyununu Mvc, WebApi ve Jquery ile Yazıp Azure’a Publish Etme

Selamlar,

Bugünkü makalede  BlacJack yani 21 kart oyununu Mvc ile, ilgili servislerini WebApi ile ve finansal transection işlemlerini CodeFirst kullanarak baştan sona kodlayıp, Azure’a publish edip oynayacağız. Amaç size algoritma mantığını aşılamak, basit bir oyunu bile yazarken nasıl zorluklar ile karşılaşacağınızı göstermektir. Ayrıca yazdığınız bir şey ile oynayıp keyif almakta ayrı bir mutluluk olacaktır. Gelin isterseniz lafı fazla uzatmadan kodlara başlıyalım.

Bir de son olarak front tarafda tamamen Jquery kullanıcam. Amaç modern javascript frameworklerinin kıymetini bilmek:)

Azure üzerinde remote debuging:

Öncelikle DB katmanında EntityFramework/CodeFirst kullanılmıştır.

DAL:

PlayLog.cs: Oynuyan oyuncuların oyun içerisindeki logları bu tabloda tutulur.

BlackJackContext.cs: İlgili DBContext “BlackJackContext” olarak aşağıdaki gibi tanımlanmıştır.

App.config: Yukarıdaki DB context’e ait Azure connection strings’i, aşağıdaki gibi tanımlanmıştır.

Şimdi gelin hep beraber WebApi servisini tanımlayalım.

WebApiServices: Client’ın finansal anlamda hesabındaki paranın,en son işlem adımının durumunu ve zamanını sessionID bazında kaydeder. Örnek ekran çıktısı aşağıdaki gibidir.

BankController.cs: Aşağıda görüldüğü gibi:

  • Client’ın SessionID’sine göre parametre alıp “PlayLog” tablosundan data çeken “Get(string session)” methodu geriye PlayLog model tipinde değer döner. Kısaca client bazında uniqe olarak tutulan alan sessionID’dir.
  • Eğer ilgili sessionID’ye ait hiçbir kayıt yok ise yani siteye ilk kez girilmiş ise, default “Cash” olarak 500 para birimi atanır. Ve sayfaya ilk gelinen zaman atanır.
  • Post()” methodu “Data” tipinde parametre beklemektedir. Bu methodunda “sessionID” bazında ilgili client bulunarak, hesabında kalan para, kazanıp kazanmadığı ve en son işlem zamanı güncellenir. Kaybederse ortaya konan “putCache” miktarı client’ın parası olan “model.cache“‘den çıkarılır. Kazanma durumunda ilgili para eklenir. Güvenlik amaçlı 2 kontrol vardır. 1-) “[HttpPost]” sadece post işleminde bu method çağrılabilinir. 2-) Hem kazanma hem de kaybetme durumunda “if (_data.putCache <= model.Cash)” kontrolü yapılmakta böylece, front tarafta elle müdahale durumunda mevcut paradan daha çok para kazanılması engellenmektedir. Eğer bu gerçek bir proje olsa idi 3-) Kontrol olarak her ortaya para konulduğunda, ilgili işlem adımı servis yolu ile loglarda saklanmalı ve en son oyunun sonuçlanması durumunda, toplam kazanılan veya kaybedilen miktarın front’dan gelen data yerine bu oyun anında tutulan log değerlerine göre backend tarafında mevcut bakiye güncellenmelidir. Bu performance kaybını sağlasa da her zaman log tutmak çok önemlidir. Son olarak Post işlemlerinde “Token Based Authentication” kullanılmalıdır. Güvenlik bu makalenin esas konusu olmadığı için yazılmamıştır..
  • “[EnableCors(origins: “*”, headers: “*”, methods: “*”)]” özelliği ile ilgili servisin farklı bir domainden client side taraftan çağrılması sağlanmıştır.

Bilindiği gibi bir destede 52 kağıt vardır. Herbirinin resmini ayrı ayrı yüklemek yerine “Css Sprite” kullanılarak tek bir image üzerinden belli kordinatlar verilerek istenen kart ekrana basılır. Böylece büyük bir performans sağlanmış olunur.

Ben “Css Sprite” kodlarını çıkarmak için online uygulama http://www.spritecow.com/ ‘dan faydalandım. İlgili resim upload edilip, her bir kart seçilerek, ilgili Css Sprit code’u alınabilir. Örnek ekran görüntüsü yukarıdaki gibidir.

cards.css: Aşağıda yukarıda görülen tek bir resme ait tüm kartların Sprite Css‘leri tanımlanmıştır. Top,Left kordinatları ve genişlik ile yükseklik değerleri her bir kart için tanımlanmıştır. Ayrıca isimlendirmeler de ilgili karta göre yapılmıştır.

Gelin şimdi isterseniz bilmiyenler için 21 oyunun kurallarını öğrenmeye:

Bu oyunda bir canlı oyuncu bir de bilgisayar olmak üzere 2 player bulunacaktır. Kısaca kişi bilgisayar karşı oynayacaktır.

  1. Oyuna girmek için ortaya sanal para konulması gerekmektedir. Para fisler dediğimiz 1-5-10-25-50 ve 100lük ler olmak üzere 6 farklı şekilde seçilebilir.
  2. Ortaya para konulabilmesi için yeterli bakiyenin olması gerekmektedir. Başlangıçta herkesin 500tl si olmaktadır. Para 0 landıktan sonra oyuna session timeout olana kadar girilemez.
  3. İlgili para ortaya konulduktan sonra “Oyuna Gir” buttonuna tıklanır. Ve kart çekme işlemine başlanır.
  4. Player, yani oyuna katılan kişiye random 2 kart verilir. Ve toplamı ekrana yazılır.
  5. Computer’e de yani masaya da 1 kart verilir. O da ekrana yazılır.
  6. Amaç 21’e en yakın sayıya ulaşmaktır. 21 geçilirse oyun kaybedilir.
  7. 21’e gelene kadar 2 kartdan sonra “Yeni Kart Çek” buttonuna basılarak istenildiği kadar kart çekilebilir.
  8. Daha fazla kart çekilmek istenmez ise  “Kal” buttonuna tıklanır. Bu sefer masa palyer’ı geçene kadar kart çekmeye başlar. 21’i aşar ise player kazanır.
  9. Bazen de aynı score’a gelinip berabere kalınabilir.
  10. Son olarak   “A” kartı özel bir karttır. Duruma göre 1 veya 11 olarak sayılabilir.21’i geçmiyor ise 11 geçiyor ise 1 score olarak sayılır.

İşte oyunun bütün kuralları bu kadar. Şimdi buna göre öncelikle front tarafı yazmaya başlıyalım. Aşağıdaki resimde index sayfasında ilgili yerlere karşılık gelen html kodlar gözükmektedir.

Index.cshtml:

  • Aşağıda görüldüğü gibi kartları çekeceğimiz kısım “cardContainer” id’li div içerisine. Pc’nin kartlarının dizileceği kısım “cardContainer2” divinin altına konmaktadır.
  • firstcolumn” altına “enterbutton” id’li div’in altına, “Oyuna Gir” ve “İptal” buttonları konulmuştur. Tıklama durumunda yapılacak ilşlemler ileride tanımlanacaktır.
  • newCardButton” id’li divde “Yeni Kart Çek” ve “Kal” buttonlarının konulduğu yerdir.
  • moneycontainer” para seçmek amacı ile fişlerin konulduğu alandır (“divToken“). Herbir fişin value değeri sayısal olarak atanmıştır. Ayrıca ortaya konan paranın ve kasadaki paranın gösterildiği table alanıdır.
  • Bunların altında ortaya konan resim bulunmaktadır.
  • Enson satırda masnın Score’unun gösterildiği kısımdır.

Ortaya para amaçlı konan fişlerin Css Sprite’ı aşağıdaki gibidir. Yani fişler için de tek resim kullanılmış ve belirlenen kordinatlara göre ekrana basılmıştır.

Jquery Scriptler: Gelin tüm functionları tek tek inceleyelim.

1-) $(document).ready():

  • “.money” css li para fislerinin üzerine gelinince  mouse’un el işaretine gelmesi sağlanır.
  • İlgili fislerin tıklanması durumunda, kasadaki paranın “#cash”‘in 0’dan büyük olmasına ve  ortya konan para “#perCache”‘den fazla olup olmamasına bakılır. Kısaca oyanancak yeterince para olup olmadığına bakılır.
  • Kasadaki paradan, ortaya konan para çıkarılır ve ortaya konan paranın yeni değeri tıklanan paranın değeri kadar eklenir.
  • Son olarak “Oyuna Gir” (#enter) buttonu gizlenir.

2-) PostData(_isWin): 

  • Gönderilecek data paketi “_data” tanımlanır. İlgili kazanılan ya da kaybedilen para “putCache“, client’ın unique sessionID’si “session” ve son olarak kazanıp kazanamadığına ait bilgi “isWin“.
  • Yukarıda tanımlı webapi servisine azure tarafında yandaki link ile “http://*********.azurewebsites.net/api/bank/” “ajax.Post” sayesinde erişilir. İlgili paket json formatında gönderilir.
  • Başarılı işlem sonucunda “_isWin” ile kazanılma veya kaybedilme durumu “alert()” ile belirtilir. Ve sayfa refresh olarak ilk konumuna getirilir. “location.href = location.href;

3-) GetNewCard(player):

  • $.post(“/Home/GetRandomCardHtml”) ile player parametresine göre ya oyuna yeni girişte (player==1)ya da yeni kart çekilişinde (player==3)  player için servisden random kart getirilmesini sağlar. İlgili servise kodun ilerleyen kısımlarında bakılacaktır.
  • Ortaya para konduktan sonra Oyuna Girişte (player==1) durumunda “Oyuna Gir” buttonu gizlenir. “Yeni Kart Çek” buttonu gösterilir. Ayrıca para fislerinin tıklanması kapatılır. Son olarak serviden dönen data yani çekilen kağıtlar “cardContainer” divinin içine Append ile eklenir.

  • player==1” durumunda yeni girişte toplam 2 kağıt çekilir. Yani player1 için 2 defe servise gidilir.
  • *Eğer çekilen kart tipi  “A” ise yani value’su 1 ise genel toplamın “$(‘#score’).val()” 21’i geçmemesi durumunda 11 değerini, genel toplamın 21 geçmesi durumunda 1 değerini alması sağlanır.
  • Eğer ilk gelen kart “As” değil ise çekilen kart değeri “parseInt($(this).attr(‘value’))” ile bulunup toplam score ekranına yazılır “$(‘#score’).val()”
  • Eğer “player==3” yani “Yeni Kart Çekin” button’una basılınca ilgili servisden tek bir kar çekilir. Ve ilk kart “As” için gene yukarıda yazılan case adımları gerçekleştirilir.
  • Her iki durum için “$(‘#score’).val()” score’un 21 olması durumunda “PostData(true)” şeklinde ilgili webapi servisine değer gönderilir. Yani oyun kazanılır. Score’un 21’den büyük olması durumunda “PostData(false)” şeklinde ilgili webapi servisine değer döndürülür. Yani oyun kaybedilir.
  • Son olarak eğer “player==2” ise, bu da pc yani masa için random bir kart çekilmesi anlamına gelmektedir. Yukarıda tanımlı tüm kurallar burda da aynen geçerlidir.

4-) Stay() : İlk kez ortaya para konup kart açıldıktan sonra, basılabilen Kal button’unda çağrılan functiondır. Bir diğer çağrıldığı yer ise bilgisayar yani masa tarafında, client “Kal” buttonuna tıkladığı zaman, client’ın score’undan yüksek – 21’den fazla olmamak kaydı ile sürekli kart çekmesini recursive olarak sağlandığı yerdir. Yani Stay() function ‘ı koşul sağlandığı sürece kendini tekrar tekrar çağaracak ve Masa için çekilen random kartları ekrana basacaktır.

  • İlk koşul olarak gelen kart  ise yine belirlenen koşula göre toplam score 21’den büyük ise 1 değil ise 11 ile toplanır.
  • Masa için toplam sonucu 21’den büyük olur ise “PostData(true)” şeklinde gönderilip Player1 yani client’ın kazandığı duyurulur.
  • Eğer 21 veya player1 score’dan büyük ise “PostData(false)” şeklinde Player’in kaybedip, masanın kazandığı duyurulur.
  • Eğer Score1 ve Score2 eşit ise “Oyun Ortada” yazılır.
  • Eğer Score2 21’den ve Score1’den küçük ise “Stay()” function’ı yine çağrılır ve Masa için random yeni bir kart çekilir.

İlgili javascript kodları aşağıdaki gibidir :)

Backend tarafında neler yapılıyor, gelin hep beraber inceleyelim:

HomeController:

  • Öncelikle rastgele card seçimi yapılacağı için Random() nesnesi üretilir.
  • Client’ın SessionID değeri çekilir.
  • Bu sessionID değerine göre “BankRestServices” WebApi servisi ile ilgili client’ın para bilgisi çekilir. Çekilen data, model olarak “Index.cshtml“‘e gönderilir.
  • GetRandomCardHtml()“: Bu method’da “Player” parametresi ile client’mi yoksa bilgisayar mı için kart çekileceği belirlenir.
  • AllCards()” Tüm kartların Value değeri ve Code Snippet‘e ait css leri ile tanıtıldığı “List<Card> CardList” şeklinde bir dizinin dönüldüğü methoddur.
  • “GetRandomCardHtml()” methodu ile ilgili AllCards() methodundan random bir Card çekilir.
  • CheckBeforeCards()” Methodu ile ilgili client’ın bu oyun boyunca çektiği kartlar “Session[“Player_” + Player]” sessionda saklanır. Eğer önceden bu kart çekilmiş ise bir daha çekilmemesi için geriye false dönülür. “while(result)” ile eğer aynı kart çekilmiş ise recursive olarak yeni bir kartın çekilmesi sağlanır.
  • Card” sınıfı Css ve Value propertyleri ile aşağıdaki gibi tanımlanmıştır.

Azure publish için birçok yöntem mevcuttur. Ben öncelikle ilgili web site’ı Azure tarafında oluşturdum. Daha sonra ilgili Web site’a ait https://portal.azure.com adresinden yukarıda görülen publish profile’ı indirdim. Daha sonra ilgili profile’ı aşağıda görüldüğü gibi import edip, Azure’a publish işlemini yaptım. Ayrıca ilgili DB de gene Azure tarafında yaratılıp,  cloud’a ait connection strings alınmış ve Sql serverda Azure tarafına bağlanılıp ilgili tablolar yaratılmıştır.

Bu makalede farklı teknolojiler ve kullanıcı etkileşimi ile basit bir oyun nasıl yazılır, hep beraber inceledik. Performans için, yapılması gerekenleri hem front hem de backend tarafında detaylıca kodladık. Azure tarafında Debuging ve Publish olaylarını inceledik.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Source Code: https://github.com/borakasmer/BlackJack

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

2 Cevaplar

  1. nck dedi ki:

    Çok güzel olmuş elinize sağlık hocam

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.