Bugün ne öğrendim? 20 OOP 2

Bugünün çoğunluğu Ward crd game ile uğraşmakla geçtiği için bol bol ondan bahsedeceğim. Şimdi oyunun mantığını biraz araştırdım. Bunu sizinle paylaşacağım.

Oyunun amacı tüm kartları kazanmaktır.

Deste, oyuncular arasında eşit olarak bölünmüş ve her birine bir yığın dağıtıyor. Birlikte, her oyuncu destesinin en üst kartını ortaya çıkarır – bu bir “savaş” – ve daha yüksek bir karta sahip olan oyuncu, oynanan her iki kartı da alır ve onları yığına taşır. Aslar yüksektir ve kıyafetler göz ardı edilir.

Eğer oynanan iki kart eşit değerdeyse, o zaman bir “savaş” var. Her iki oyuncu da bir sonraki kartını ön yüzü aşağı bakacak şekilde yerleştirir (bazı modellerde üç yüz aşağı kart vardır) ve sonra başka bir kart yüz yukarı bakar. Daha yüksek yüzlü kartın sahibi savaşı kazanır ve masadaki tüm kartları destelerinin altına ekler. Açık kartlar tekrar eşitse, savaş başka bir açık kart / yukarı kartla tekrarlanır. Bu, bir oyuncunun kapalı kartı rakibinden daha yüksek olana kadar tekrar eder.

Uygulamamın kodları github hesabımda. Şimdi biraz bu kodları inceleyerek neler yaptığımıza bakalım.

Ekran çıktısı
from random import shuffle

# Kartlari tanimlamak icin olusturulan degiskenler
SUITE = 'H D S C'.split()
RANKS = '2 3 4 5 6 7 8 9 10 J Q K A'.split()

class Deck:

    def __init__(self):
        print("Yeni bir deste yaratiliyor.")
        self.allcards = [(s,r) for s in SUITE for r in RANKS ]

    def shuffle(self):
        print("Desteyi karistirma")
        shuffle(self.allcards)

    def split_in_half(self):
        return (self.allcards[:26],self.allcards[26:])

class Hand:
    "Burda elimizde olan kartlari belirliyoruz."
    def __init__(self,cards):
        self.cards = cards

    def __str__(self):
        return "Contains {} cards".format(len(self.cards))

    def add(self,added_cards):
        self.cards.extend(added_cards)

    def remove_card(self):
        return self.cards.pop()

class Player:

    def __init__(self,name,hand):
        self.name = name
        self.hand = hand

    def play_card(self):
        drawn_card = self.hand.remove_card()
        print("{} yerlestirildi: {}".format(self.name,drawn_card))
        print('\n')
        return drawn_card

    def remove_war_cards(self):
        war_cards = []
        if len(self.hand.cards) < 3:
            return war_cards
        else:
            for x in range(3):
                war_cards.append(self.hand.cards.pop(0))
            return war_cards

    def still_has_cards(self):
        """
         Oyuncuda hala kart varsa, True dondurur
         """
        return len(self.hand.cards) != 0



print("Savasa hosgeldin, haydi baslayalim...")


d = Deck()
d.shuffle()
half1,half2 = d.split_in_half()

# Butun kullanicilari olusturmaliyiz
comp = Player("computer",Hand(half1))
name1 = input("Oyuncunun adi ne?")
user = Player(name1,Hand(half2))


total_rounds = 0
war_count = 0

while user.still_has_cards() and comp.still_has_cards():
    total_rounds += 1
    print("Yeni bir raund zamani!")
    print("Iste su anki siralamalar: ")
    print(user.name+" count: "+str(len(user.hand.cards)))
    print(comp.name+" count: "+str(len(comp.hand.cards)))
    print("Iki oyuncu da kart oynuyor!")
    print('\n')

    table_cards = []

    c_card = comp.play_card()
    p_card = user.play_card()

    # table_cards 'a ekliyoruz'
    table_cards.append(c_card)
    table_cards.append(p_card)

    # Check for War!
    if c_card[1] == p_card[1]:
        war_count +=1
        print("We have a match, time for war!")
        print("Each player removes 3 cards 'face down' and then one card face up")
        table_cards.extend(user.remove_war_cards())
        table_cards.extend(comp.remove_war_cards())

        # Play cards
        c_card = comp.play_card()
        p_card = user.play_card()

        #  table_cards'a ekliyoruz
        table_cards.append(c_card)
        table_cards.append(p_card)

        # Kim daha yuksek dereceli
        if RANKS.index(c_card[1]) < RANKS.index(p_card[1]):
            print(user.name+" has the higher card, adding to hand.")
            user.hand.add(table_cards)
        else:
            print(comp.name+" has the higher card, adding to hand.")
            comp.hand.add(table_cards)

    else:
        # Kim daha yuksek dereceli
        if RANKS.index(c_card[1]) < RANKS.index(p_card[1]):
            print(user.name+" has the higher card, adding to hand.")
            user.hand.add(table_cards)
        else:
            print(comp.name+" has the higher card, adding to hand.")
            comp.hand.add(table_cards)

print("Great Game, it lasted: "+str(total_rounds))
print("A war occured "+str(war_count)+" times.")

Bu yazımda bugün videosunu izlediğim Hatalar ve İstisnalar’dan da bahsedeceğim; bunun için videoyu izledikten sonra YazBel‘den bir tekrar yaptım, aşağıdaki parağraflarda onlardan aldığım parçaları kullanacağım.

Hataları üç farklı başlıkta inceleyebiliriz:

  1. Programcı Hataları (Error)
  2. Program Kusurları (Bug)
  3. İstisnalar (Exception)

Öncelikle programcı hatalarından bahsedelim.

Programcıdan kaynaklanan hatalar doğrudan doğruya programı yazan kişinin dikkatsizliğinden ötürü ortaya çıkan bariz hatalardır. Örneğin şu kod bir programcı hatası içerir:

>>> print "Merhaba Python!"

Bu kodu çalıştırdığınızda şöyle bir hata mesajı görürsünüz:

>>> print "Merhaba Python!"

File "<stdin>", line 1
   print "Merhaba Python!"
                         ^
SyntaxError: invalid syntax

Bu hata mesajında bizi ilgilendiren kısım son cümlede yer alıyor: SyntaxError, yani Söz dizimi hatası.

Bu hatalar, programlama diline ilişkin bir özelliğin yanlış kullanımından veya en basit şekilde programcının yaptığı yazım hatalarından kaynaklanır. Programcının hataları genellikle SyntaxError şeklinde ortaya çıkar. Bu hatalar çoğunlukla programcı tarafından farkedilir ve program kullanıcıya ulaşmadan önce programcı tarafından düzeltilir. Bu tür hataların tespiti diğer hatalara kıyasla kolaydır. Çünkü bu tür hatalar programınızın çalışmasını engellediği için bunları farketmemek pek mümkün değildir…

Program kusurları, başka bir deyişle bug‘lar ise çok daha karmaşıktır. Kusurlu programlar çoğu zaman herhangi bir hata vermeden çalışır. Ancak programın ürettiği çıktılar beklediğiniz gibi değildir. Örneğin yazdığınız programda bir formül hatası yapmış olabilirsiniz. Bu durumda programınız hiçbir şey yokmuş gibi çalışır, ancak formül hatalı olduğu için hesaplamaların sonuçları yanlıştır. Örneğin daha önceki derslerimizde yazdığımız şu program yukarıdaki gibi bir kusur içerir:

sayı1 = input("Toplama işlemi için ilk sayıyı girin: ")
sayı2 = input("Toplama işlemi için ikinci sayıyı girin: ")

print(sayı1, "+", sayı2, "=", sayı1 + sayı2)

Bu programda kullanıcı veri girdiği zaman, programımız toplama işlemi değil karakter dizisi birleştirme işlemi yapacaktır. Böyle bir program çalışma sırasında hata vermeyeceği için buradaki sorunu tespit etmek, özellikle büyük programlarda çok güçtür. Yani sizin düzgün çalıştığını zannettiğiniz program aslında gizliden gizliye bir bug barındırıyor olabilir.

Aynı şekilde, mesela eval() fonksiyonunun dikkatsizce kullanıldığı programlar da güvenlik açısından kusurludur. Yani bu tür programlar bir güvenlik kusuru (security bug veya security flaw) barındırır.

Dediğimiz gibi, program kusurları çok boyutlu olup, burada anlattığımızdan çok daha karmaşıktır.

Gelelim üçüncü kategori olan istisnalara (exceptions)…

İstisnalar, adından da az çok anlaşılacağı gibi, bir programın çalışması sırasında ortaya çıkan, normalden farklı, istisnai durumlardır. Örneğin şu programa bakalım:

ilk_sayı = input("ilk sayı: ")
ikinci_sayı = input("ikinci sayı: ")

ilk_sayı = int(ilk_sayı)
ikinci_sayı = int(ikinci_sayı)

print(ilk_sayı, "/", ikinci_sayı, "=", ilk_sayı / ikinci_sayı)

Burada ilk sayıyı ikinci sayıya bölen bir program yazdık. Bu program her türlü bölme işlemini yapabilir. Ama burada hesaba katmamız gereken iki şey var:

  1. Kullanıcı sayı yerine, sayı değerli olmayan bir veri tipi girebilir. Mesela ilk sayıya karşılık 23, ikinci sayıya karşılık ‘fdsfd’ gibi bir şey yazabilir.
  2. Kullanıcı bir sayıyı 0‘a bölmeye çalışabilir. Mesela ilk sayıya karşılık 23, ikinci sayıya karşılık 0 yazabilir.

İlk durumda programımız şöyle bir hata verir:

ilk sayı: 23
ikinci sayı: fdsfd
Traceback (most recent call last):
  File "deneme.py", line 5, in <module>
    ikinci_sayı = int(ikinci_sayı)
ValueError: invalid literal for int() with base 10: 'fdsfd'

Buradaki sorun, sayı değerli olmayan bir verinin, int() fonksiyonu aracılığıyla sayıya çevrilmeye çalışılıyor olması.

İkinci durumda ise programımız şöyle bir hata verir:

ilk sayı: 23
ikinci sayı: 0
Traceback (most recent call last):
  File "deneme.py", line 7, in <module>
    print(ilk_sayı, "/", ikinci_sayı, "=", ilk_sayı / ikinci_sayı)
ZeroDivisionError: division by zero

Buradaki sorun ise, bir sayının 0‘a bölünmeye çalışılıyor olması. Matematikte sayılar 0‘a bölünemez…

İşte bu iki örnekte gördüğümüz ValueError ve ZeroDivisionError birer istisnadır. Yani kullanıcıların, kendilerinden sayı beklenirken sayı değerli olmayan veri girmesi veya bir sayıyı 0’a bölmeye çalışması istisnai birer durumdur ve yazdığımız programların exception (istisna) üretmesine yol açar.

try… except…

Bir önceki bölümde hatalardan ve hataları yakalamaktan söz ettik. Peki bu hataları nasıl yakalayacağız?

Python’da hata yakalama işlemleri için try... except... bloklarından yararlanılır. Hemen bir örnek verelim:

ilk_sayı    = input("ilk sayı: ")
ikinci_sayı = input("ikinci sayı: ")

try:
    sayı1 = int(ilk_sayı)
    sayı2 = int(ikinci_sayı)
    print(sayı1, "/", sayı2, "=", sayı1 / sayı2)
except ValueError:
    print("Lütfen sadece sayı girin!")

Biliyoruz ki, bir veriyi sayıya dönüştürmek istediğimizde eğer kullanıcı sayı değerli bir veri yerine harf değerli bir veri girerse programımız çöker. Dolayısıyla int(ilk_sayı) ve int(ikinci_sayı) kodları, kullanıcının gireceği veri türüne göre hata üretme potansiyeline sahiptir. O yüzden, burada hata vereceğini bildiğimiz o kodları try bloğu içine aldık.

Yine bildiğimiz gibi, veri dönüştürme işlemi sırasında kullanıcının uygun olmayan bir veri girmesi halinde üretilecek hata bir ValueError‘dır. Dolayısıyla except bloğu içine yazacağımız hata türünün adı da ValueError olacaktır. O yüzden ValueError adlı hatayı yakalayabilmek için şu satırları yazdık:

except ValueError:
    print("Lütfen sadece sayı girin!")

Temel işleyişi aşağıdaki gibidir.

try:
    hata verebileceğini bildiğimiz kodlar
except HataAdı:
    hata durumunda yapılacak işlem

try:
    f = open('testfile','r')
    f.write('Test write this')
except IOError:
   # Bu sadece bir IOError istisnasını kontrol edecek ve ardından bu print cümlesini çalıştıracak

   print("Error: Could not find file or read data")
else:
   print("Content written successfully")
   f.close()

Benim bugünlük anlatacaklarım bu kadar, bir sonraki yazıda görüşmek üzere!

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s