C# ile MasterMind oyununu bilgisayara karşı oynamak!

Title : Playing mastermind game against computer with C#

MasterMind nedir? Nasıl oynanır?

Kaynak kodları için burayı tıklayın lütfen (source codes).

Grafik 1. MasterMind oyunu

MasterMind iki kişiyle oynanan bir kod-kırma oyundur. Oyunculardan birisi kod-oluşturucu diğeri ise kod-kırıcıdır. Kod-oluşturucu 6 farklı renkteki mandalı kullanarak 4 adet seçer ve bir kod oluşturur (aynı renk birden fazla kullanılabilr). Kod-kırıcı ise kod-oluşturucunun verdiği ipuçlarını kullanarak bu kodu bulmaya çalışır. Kod-oluşturucu kod-kırıcının doğru yerde ve doğru renkteki her tahmini için tahtada tahminin yapıldığı yerin sağına siyah bir mandal (yukarıdaki resimde turuncu), doğru renkte ancak farklı yerde yer alan her bir tahmin için ise beyaz bir mandal yerleştirir. Mesela, kod-oluşturucunun seçtiği renk kombinasyonu şöyle olsun,

Beyaz | Mavi | Sarı | Kırmızı

Kod-kırıcı ise şöyle bir tahminde bulunsun.

Beyaz | Kırmızı | Pembe | Yeşil

Bu durumda kod-oluşturucu, 1 siyah 1 beyaz mandal ile kod-kırıcıya, yapılan tahminde bir mandalın yerinin de renginin de doğru (Beyaz), bir mandalın ise renginin doğru ancak yerinin yanlış (Kırmızı) olduğu bilgisini verecektir.

MasterMind oyununda  farklı varyasyonlar kullanılabilir elbette. Mesela

–          Aynı renk birden fazla kullanılamaz (bütün mandallar farklı renkte)

–          Aynı renk en fazla iki defa kullanılabilir

–          Aynı renk en fazla 3 defa kullanılabilir

gibi…Bizim burada ele alacağımız MasterMind oyunu sayıların temel alındığı (aynı zamanda, temelde sayılar kullanılarak farklı nesnelerin de yer alabileceği) bir oyun olacak. Ve bütün kod oluşturmak için kullanılan rakamlar en fazla bir defa kullanılabilecektir (sayıların rakamları birbirlerinden farklı).

Kısaca MasterMind oyunu hakkında bilgi verdikten sonra asıl konumuza gelebiliriz.

Biliyorsunuz arkadaşlar bir süredir C# ile kombinasyon, permütasyon hesapları yapmakla meşguldüm. Nedeni ise MasterMind oyununu klasik biçiminden (bilgisayar sayı üretir kullanıcı tahmin etmeye çalışır) daha farklı bir şekilde C# ile yeniden yazmaktı. Farklı olmasını planladığım kısmı, kullanıcıların da bilgisayara karşı bu oyunu oynayabilmelerini sağlamaktı. Yani kullanıcı kafasından bir sayı seçecekti ve bilgisayar da kullanıcının verdiği bilgiler doğrultusunda bu sayıyı bulmaya çalışacaktı. Seneler önce üniversitede iken Pascal programlama dili ile başarmıştım bunu. Çok aradım ama bulamadım yıllar evvel yazdığım bu programcığı, sizinle paylaşmayı çok isterdim.

Pascal ile yazdığım programcık yalnızca 4 basamaklı sayılar için çalışıyordu yani 5, 6, 7 ve daha fazla sayıda basamağı olan sayılar için geçerli değildi. Ve aynı zamanda seçilen sayılar, 0-9 arasındaki rakamlardan oluşuyordu yani sayıların oluşturulduğu rakam havuzu her zaman sabitti. Yazılım dünyasında sabit olan şeyleri pek sevmiyorum, dinamik yapılardan daha fazla keyif alıyorum. Bu nedenle de C# ile yazmayı planladığım MasterMind oyununu da dinamik yapılar üzerine inşa etmeyi planladım hep. Yani sayıların oluşturulacağı rakam havuzu sabit olmayacaktı ve aynı zamanda sayıların basamak sayısı da dinamik olacaktı. Yani isterseniz şöyle diyebilecektiniz, ben 5 basamaklı ve aynı zamanda 0, 7 ve 6 rakamlarının olmadığı sayılarla bu oyunu oynamak istiyorum.  Bu aynı zamanda bana şu esnekliği de sağlıyor olacaktı: oyunu yalnızca sayılarla oynamak zorunda olmayacaktım, istersem rakamları başka nesnelerle ilişkilendirebilir (renk, şekil vs.) böylece oyuna oynanabilirlik adına esneklik kazandırabilecektim. Emin olun bunu başarmak biraz zor! Bu nedenle de yukarıda bahsettiğim gibi son zamanlarda olasılık, permütasyon ve kombinasyon  hesapları ile dolu kafam. Ama sonunda bitirdim…İşte sonuç,

Grafik 2. MasterMind oyunu uygulama ara yüzü

Uygulama İngilizce, uzun süredir bütün uygulamalarımı İngilizce olarak yazdığım için -kodlar dahil-  böyle bir alışkanlık oluştu bende. Türkçe olsa belki benim için bile daha anlaşılır olacak ancak İngilizce yazmaya alışmışım ve sanırım işin doğasının da bu olması gerektiğini düşünüyorum. Ama Türkçe versiyonunun olmasını isterseniz – yorumlarınızda bu konuyu bildirmeniz yeterli- onu da hemen hazırlar paylaşırım.

Sol üstte yer alan “Game Properties – Oyun Özellikleri” bölümü, oyunun temel özelliklerini belirleyebileceğiniz bölümü. En üstte yer alan rakamlar, sayıların oluşturulmasını istediğiniz rakamları gösteriyor. Bu örnekte 0-9 arasındaki bütün rakamlar kullanılabilir durumda gösterilmiş. Kullanılmasını istemediğiniz rakamların işaretlerini kaldırmanız yeterli olacaktır. Aynı şekilde kullanılmasını istediğiniz rakamları da işaretlemeniz gerekecektir. Burada dikkat edilmesi gereken nokta, en az seçilen sayı basamağı kadar rakamın seçilmiş olması. Demek istediğim 4 basamaklı ve rakamları birbirlerinden farklı bir sayıyı 3 adet rakamı kullanarak oluşturamazsınız, bu durumda en az 4 adet rakama ihtiyacınız olacaktır. Merak etmeyin böyle bir ihtimal olduğunda program sizi uyaracaktır.

Yine “Game Properties – Oyun Özellikleri” bölümde yer alan “Length – Uzunluk” seçeneği ile oyunda kullanılacak sayının kaç basamaklı olduğunu belirleyebilirsiniz. “Number – Sayı” bölümü ise, eğer bilgisayar kod-üretici rolünde ise, bilgisayarın ürettiği sayıyı gösteriyor (şifreli şekilde, her bir basamağı * işaretli). Yine bu bölümde yer alan “Com vs Human” seçeneği, kullanıcının kod-oluşturucu, bilgisayarın kod-kırıcı olduğu oyun şeklini (siz kafanızda bir sayı tutarsınız ve bilgisayar sayıyı bulmaya çalışır), “Human vs Com” seçeneği ise bilgisayarın kod-oluşturucu, kullanıcının ise kod-kırıcı olduğu oyun şeklini (bilgisayar bir sayı üretir siz sayıyı tahmin etmeye çalışırsınız) seçmenizi sağlar. Yani oyun tipleri arasında geçiş yapmanıza olanak verir.

Sol altta yer alan “Game Activity- Oyun Faaliyeti” bölümü, oyunun gidişatını gösterir. Oyunun tipi ne olursa olsun bütün tahminler ve yapılan tahminler üzerindeki ip uçlarının tamamı burada kullanıcıya gösterilir. Sol kutucuk tahmin edilen sayıları gösterir. Kod-kırıcının bilgisayar olduğu oyun tipinde bilgisayar her yeni tahmin yaptığında, yeni tahmin otomatik olarak burada yer alacaktır. Kod-kırıcının kullanıcı olduğu oyun tipinde ise, yeni bir tahminde bulunmak için bu kutucuğun üzerinde sağ tıklamanız ve açılan menüden “New Guess” seçeneğini seçerek (ya da basitçe bu kutucuk üzerinde çift tıklayarak) tahmininizi açılan kutuya yazmanız gerekecektir. Sağ taraftaki diğerine göre daha küçük olan kutucuk ise yapılan tahminler ile ilgili doğru ve yanlış bilgilerini verir. Bu bilgiler ışığında da yeni sayı tahminleri yapılır. Oyunda kullanıcının kod-kırıcı olduğu durumlarda (bilgisayara karşı oynanırken), yine bu kısımda (“Game Activity- Oyun Faaliyeti”) yer alan “True – Doğru” ve “False – Yanlış” kutucukları ile bilgisayarın ürettiği tahminlerde yer alan doğru ve yanlış sayılarını bilgisayara bildirmenizi sağlar.

Uygulamada sağ tarafta yer alan 3 kutucuk ise verilen bilgiler doğrultusunda bilgisayar tarafından hesaplanan ihtimaller doğrultusunda üretilen (dolayısıyla bilgisayara karşı oynan oyunlarda) sayıları göstermektedir. En soldaki kutucuk olası sayıları göstermektedir, yani kullanıcı tarafından tutulan sayı mutlaka bu ihtimaller içerisinde yer almaktadır. Ortada yer alan kutucuk, bir önceki tahminde yer alan olası sayıları, en sağdaki kutucuk ise en son verilen bilgiler doğrultusunda üretilen olası sayıları göstermektedir. Basitçe, soldaki kutucuk, sağda yer alan iki kutucuğun kesişimidir aslında -ki bu yöntem bilgisayar tarafından sayının bulunması için kullanılan çok akıllıca bir yapay zeka yöntemidir- böylece bilgisayar verilen bilgileri birbirleri ile ilişkilendirir. Daha açık bir ifade ile, bilgisayar yeni bir tahminde bulunurken yalnızca son tahminde kendisine verilen ip uçlarını değil, o ana kadar verilen bütün ip uçlarını değerlendirir. Üretilen sayıları bir öncekilerle kesiştirmek bunu yapmanın en iyi yoludur.

Gel gelelim MasterMind oyununu bilgisayar karşı oynayabilmenin, daha doğrusu bilgisayarın düşünmesini sağlamanın zorluğuna…İşin zorluğu ihtimalleri hesaplayabilmekte…Matematiksel olarak hesaplamak çok kolay ancak bunu bilgisayara da yaptırabilmek zorlu bir iş. Bu uygulama ile ben bu işi yapabildiğimi düşünüyorum ve bunu da sizinle paylaşmak istedim.

O halde biraz kombinasyon, permütasyon ve olasılık çalışalım…

4 basamaklı bir sayı için, rakamları birbirinden farklı sayılar :

9 * 9 * 8 * 7 = 4.536 adet

ihtimalin olduğunu görürüz. Basamak sayısı arttıkça ihtimaller de artıyor elbette,

5 basamaklı sayılar = 9 * 9 * 8 * 7 * 6 = 27.216 adet

6 basamaklı sayılar = 9 * 9 * 8 * 7 * 6 * 5 = 136.080 adet

7 basamaklı sayılar = 9 * 9 * 8 * 7 * 6 * 5 = 544.320 adet

İhtimalin söz konusu. Bu ihtimaller permütasyon ile basitçe hesaplanabiliyor ancak bizim buradaki durumumuz biraz farklı. Burada doğru ve yanlış bilgilerini de hesaba katmamız gerekiyor. Yani bilgisayar bir sayı tahmin ederken, kullanıcının ona verdiği “tahmin ettiğin sayı içerisinde 2 doğru 1 adet yanlış var” bilgisini de göz önünde bulundurması lazım. Peki bunu nasıl yaptıracağız bilgisayara? Konuyu anlayabilmek için detaylarına inmemiz lazım, inceleyelim….

Örneğin bilgisayarın tahmini

1234

olsun. Kullanıcı da tahminde 2 doğru 1 yanlış olduğunu belirtmiş olsun. İhtimalleri hesaplayalım :

Grafik 3. Seçim ihtimalleri ve olası sayılar

Görüldüğü üzere toplam 12 adet seçim ihtimali var, yani şu rakam doğru yerde-şu rakam yanlış yerde  olursa deme ihtimalimiz 12. Her bir seçim ihtimali sonucunda oluşturulabilecek sayılar da seçimlerin karşısında yer alıyor. Bu sayılar elbette yapılan seçimin sonucunda oluşturuluyorlar. Gelelim bu sonuçların matematiksel ifadesine…

Yapılan tahminde 2 adet doğru rakamımız varsa eğer, bu rakamların ihtimallerini bulmak için kombinasyon almamız yeterli olacaktır. Yani 4’ün (sayımız 4 basamaklı) 2’li kombinasyonu,

4! / (4-2)! * 2! = 6

Yani şu rakam ve şu rakam doğru yerde olsa diyebileceğimiz toplam 6 adet ihtimal var. Buraya kadar sorun yok. Şimdi yanlış yerde olan rakam ihtimalini de hesaba katmamız lazım.

4 basamaklı sayımızda iki rakamı çıkartırsak -çünkü bu iki rakamı doğru olarak işaretledik yukarıda- geriye 2 basamak kalıyor. 2 basamak içerisinden de 1 rakamımız doğru ancak yanlış yerde, bu durumdaki ihtimalleri de bulabilmek için 2’nin 1’li kombinasyonunu hesaplamamız yeterli.

2! / (2-1)! * 1! = 2

Yani yukarıdaki 2 basamağın doğru olması durumunda ortaya çıkan her bir 6 ihtimal için, 2 adet de 1 rakamın yanlış yerde olma ihtimali söz konusu. Dolayısıyla toplam seçim ihtimalimiz,

6 * 2 = 12

adet ihtimalimiz söz konusu. Bu seçim ihtimallerini de zaten yukarıda görüyorsunuz. Aynı sonuca tersten de ulaşmamız mümkün. Yani önce yanlış olan ihtimalleri sonra da doru olabilecek ihtimalleri hesaplayarak (yukarıdaki resimde olduğu gibi). Görelim :

4 basamaklı bir sayıda 1 basamağın yanlış olması durumunda oluşabilecek ihtimaller :

4! / (4-1)! * 1! = 4

4 basamaklı bir sayıdan yanlış olabileceğini düşündüğümüz 1 rakamı çıkardığımızda geriye 3 basamak kalıyor. 3 basamak içerisinden de doğru olabileceğini düşündüğümüz 2 adet rakamı seçmeliyiz. Seçelim :

3! / (3-2)! * 2! = 3

ve toplam seçim ihtimali yine aynı :

4 * 3 = 12

Peki seçim ihtimallerini bulduk. Ve biliyoruz ki bu ihtimallere uyan sayılardan birisi kullanıcının sayısı. Peki ama bu seçim ihtimallerine uyan sayıları nasıl bulacağız? Bunun için bize verilen bilgiler doğrultusunda sayı üreten bir yapı lazım. Büyük resmi yavaş yavaş görmeye başladık, yani uygulamamız şu yapıya uygun bir şekilde çalışmalı –ki emin olun bu şekilde çalışıyor-.

Grafik 4. Uygulamanın çalışma prensibi (sayı : 1234; 2 Doğru, 1 Yanlış)

Sayı üreticisine geçmeden önce şu konu üzerinde durmamız lazım. Yerleri doğru olan rakamlarla ilgili çok sıkıntımız yok, ufak bir kombinasyon hesabı ile işimizi hallettik. Ancak yerleri yanlış olan rakamlar için basit bir kombinasyon almak yetmiyor. Neden? Çünkü kombinasyon ile bu rakam ya da rakamların bulunabileceği yerleri buluyoruz kombinasyonla ancak bize bu rakamların bulunabilecekleri yerler değil, BULUNAMAYACAKLARI yerler gerekli. Çünkü bu rakamların yerleri bize yanlış olarak bildirilmiş zaten yani kombinasyon ile bulduğumuz yerlerde bulunamazlar! Yani bilgisayarın kendisine yanlış olarak bildirilen rakamların olası yanlış yerlerini hesaplayabiliyor olması lazım. Bunun için bulduğum yöntem şöyle, öncelikle rakamların bulunabilecekleri tüm yerleri hesaplıyorum, daha sonra da bu kümeden, rakamların bulunamayacakları ihtimalleri çıkartıyorum. Matematiksel olarak ifade edelim.

Yukarıda Excel tablosunda (Grafik 3) belirtilen ilk seçimi ele alalım, yani 1 rakamı yanlış yerde, 3 ve 4 rakamları doğru yerde olursa,

Öncelikle doğru olan rakamları hesaba katmamız gerekli!  İki rakam (3 ve 4) doğru yerde ise, geriye 2 basamak kalıyor.  Yanlış olan basamağın hangisi (ya da hangileri) olduğu ihtimalleri, 2’nin 1’li kombinasyonudur, yani :

2! / (2-1)! * 1! = 2

Yani yanlış olarak kabul edeceğimiz sayımız ya ilk basamakta ya da ikinci basamakta (3. ve 4. basamaktaki rakamları doğru yerde olarak işaretlemiştik) yer alabilir. Yani ya 1 rakamı yanlış yerdedir, ya da 2 rakamı. 1 rakamının yanlış olması durumunda oluşturulabileceğimiz sayıları,

X134

şeklinde ifade edebiliriz. Burada X olarak işaretlediğimiz basamağa ise 5,6,7,8,9 rakamları gelebilir Sayının basamakları birbirlerinden farklı olmak zorunda olduğu için X basamağına 1,2 ve 3 rakamlarını yerleştiremeyiz ve aynı zamanda bu basamak ilk basamak olduğu için buraya 0 rakamını da yerleştiremeyiz. Sonuçta elde edilen rakamlar,

5134, 6134, 7134, 8134, 9134

olacaktır. Benzer şekilde yanlış rakamın 2 olması durumunda da oluşturabileceğimiz rakamlar,

2X34 = 2034, 2534, 2634, 2734, 2834, 2934

sayıları olacaktır. Burada yukarıdakinden farklı olarak X basamağı ilk basamak olmadığı için buraya 0 rakamını da yerleştirebiliriz. Dolayısıyla üretilebilen sayılar bir öncekinden bir adet fazla yani 6 adettir.

Sonuç olarak bilgisayara doğru olarak bildirilen her bir rakam bir kombinasyon işlemi, yanlış olarak bildirilen her bir rakam ise bir kombinasyon ve her bir kombinasyon için bir permütasyon işlemi gerektirecektir. Bu bilgiler doğrultusunda uygulamamız, 4 basamaklı bir sayı için, 2 doğru ve 1 yanlışın olduğu tüm sayılar,

Grafik 5. Üretilen olası sayılar (Sayı : 9264; 2 doğru, 1 yanlış)

Üretilen sayıların adedini veren bir formül olduğunu düşünmüyorum çünkü üretilen sayılar yapılan seçime göre değişiyorlar ayrıca ilk basmakta 0 rakamının bulunmaması gibi ayrı bir detay da söz konusu. Bunun bir formülü varsa da ben bulamadım henüz. Bu noktada sizin de paylaşımlarınız olursa bana bildirirseniz çok sevinirim gerçekten.

Şimdi de uygulamayı test edelim. Önce 4 basamaklı bir sayı tutalım ve bilgisayar sayımızı bulmaya çalışsın. Sayımız 3589 olsun.

Grafik 6. 3589 sayısı için bilgisayarın tahminleri ve sonucu

Toplam 4 tahminde sayımızı buldu. Ve dikkat ederseniz son verilen bilgi doğrultusunda bilgisayar ihtimaller arasında verilen bilgilere uyan yalnızca bir sayı olması gerektiğine karar vermiş. Ve doğru da vermiş kararını 🙂

Son olarak 5 basamaklı bir sayı deneyelim. Sayımız 48207 olsun.

Grafik 6. 48207 sayısı için bilgisayarın tahminleri ve sonucu

Toplam 5 tahmin sonucunda sonuca ulaştı bilgisayar. Gördüğünüz üzere gayet akıllı bilgisayarımız J Ancak şunu da söylemem lazım basamak sayısı arttıkça ve rakamların tümü (0-9 arasında) kullanıldığında yavaş çalışmaya başlıyor. En azından ilk ihtimalleri hesaplarken çünkü çok fazla ihtimal var. 7 basamaklı bir sayı için 2 milyonun üzerinde rakamları birbirinden farklı sayımız söz konusu ve her bir permütasyon ve kombinasyon işleminde bu kadar fazla sayıda ihtimali göz önünde bulundurmak biraz zaman alıyor. Şu an için zaten 7, 8 ve 9 basamaklı sayıları kullanıma kapattım. Hızlı bir yöntem bulursam bu basamakları da kullanıma açacağım.

Bu yazımı da burada noktalamak istiyorum izninizle, saat 02:00’ye yaklaşıyor ve uykum geldi, yazmaktan yoruldum 🙂

Buraya kadar eminim merak ettiğiniz bir nokta vardır uygulama ile ilgili! O da ihtimallere uyan sayıları nasıl ürettiğim? Bu da başka bir yazımın konusu olsun. Ama bir ipucu vereyim, sayaçlar…

“MasterMind with C#”

Kaynak kodları için burayı tıklayın lütfen (source codes).

, , ,

One Response to C# ile MasterMind oyununu bilgisayara karşı oynamak!

  1. Ahmet BÜTÜN 23 Eylül 2011 at 9:53 PM #

    Bu yazım güzel olmuş, tebrikler bana 🙂

Bir Cevap Yazın

Font Resize