Rolling hash

Aslında yazı arama algoritmalarında devam etmek istiyordum ama önce sıradaki algoritmada kullanılan bir teknikle ilgili yazmaya karar verdim. Bu tekniğin adı rolling hash. Rolling hash aslında bir tür hash değeri hesaplama algoritmasıdır. Hash nedir ve yazı aramada hash değeri nasıl işimize yarayabilir?

Hash fonksiyonu, değişken uzunluklu veri kümelerini, sabit uzunluklu veri kümelerine haritalayan algoritma veya alt programdır. Vikipedide verilen tanım bu. Bunu basitçe bir alt metni kullanarak hesapladığımız bir sayı olarak düşünebiliriz.

Bir sonraki metin algoritmasında kısaca metin içinde aradığımız parçanın harflerini tek tek kaydırarak karşılaştırmak yerine ana metinde aradığım alt metinle aynı uzunluktaki parçaların hash değerlerini aradığımız metnin hash değerleriyle karşılaştırmayı deneyeceğim.

Önce metinlerde kullanabileceğim basit bir hash fonksiyonu tanımlamaya çalışayım. Örneğin aradığım metnin harf değerlerini toplamakla başlayabilirim.

Aradığım metin ABC ise harflerin ASCII değerlerini toplamayı düşünebilirim. A = 65, B = 66 ve C = 67 olduğuna göre hash(ABC) = 65 + 66 + 67 = 198 olur. Oldukça kolay olan bu algoritmanın bir dezavantajı var ama. hash(ABC) = hash(CBA) olacaktır. Daha doğrusu basitçe harf değerlerini toplamak aradığım harflerin sırası değiştiğinde de aynı hash değerini hesağlayacağından arama işlemlerinde çok faydalı olmayabilir. Aslında tanıma dikkatli baktığımızda hash değerlerinin farklı harflerden oluşan diziler için de aynı olabileceğini görebiliriz, çünkü bu hash fonksiyonu asla birebir olmayacaktır. Harf dizisi sayısı hesapladığımız sayılardan fazladır, demek ki bazı diziler ne yaparsak yapalım aynı hash değerlerine sahip olacaktır. Yine de elimizden geldiğince bu çakışmaları azaltmakta fayda var.

Harflerin pozisyonlarına göre değişik değerler üretebilmeleri için bu harflerin değerlerini harfin konumuna göre değişik sayılarla çarpıp toplayacağım. Çarptığım sayıları da bir tabanın kuvvetleri olarak seçeceğim. Bu seçim bu yazının konusu olan rolling hash hesabında oldukça faydalı olacak. Bu yazıda bu iş için en uygun sayıların nasıl bulunacağına girmeyeceğim. Sadece kabaca algoritmanın bir simulasyonunu vereceğim. Yazıda ve simulasyonda taban olarak 7 sayısını kullanacağım.

Bu durumda \(hash(ABC) = 65\cdot {7^0} + 66\cdot{7^1} + 67\cdot{7^2} = 65 + 66\cdot{7} + 67\cdot{49} = 65 + 462 + 3283 = 3810 \) olur. Harflerin yerlerini değiştirdiğimde de \(hash(CBA) = 67\cdot {7^0} + 66\cdot{7^1} + 65\cdot{7^2} = 67 + 66\cdot{7} + 65\cdot{49} = 65 + 462 + 3185 = 3714 \) sonucu çıkıyor. Demek ki bu yöntem harf sıralamasındaki değişikliklerde daha iyi bir performans sağlıyor. Tabii ki buna rağmen çakışmalar olabilir ama önemli olan bu ihtimalin azalması.

Ana metin içinde aramayı yaparken aradığımız metin uzunluğundaki parçaların hash değerlerini hesaplamamız gerekecek. İyi de bu hash değerleri metni bir kaydırıp bütün harfleri tek tek karşılaştırmaktan nasıl daha iyi olabilir ki? Her kaydırmadan sonra daha çok çarpma ve toplama yapmamız gerekiyor ve sonuçta zaten hash değerleri aynı çıksa bile çakışma riski nedeniyle iki diziyi yine harf harf karşılaştırmamız gerekecek. Bu yöntemin daha iyi olabilmesi için hash değeri hesaplamayı çok daha kolay bir hale getirmem gerekecek.

Metnimiz ABCD olsun ve aradığımız metin de üç harf uzunluğunda olsun. Kontrol etmemiz gereken iki tane alt dizi olacak. ABC ve BCD. Şimdi bunların hash değerlerine bakalım.

\(hash(ABC) = 65\cdot {7^0} + 66\cdot{7^1} + 67\cdot{7^2} = 65 + 66\cdot{7} + 67\cdot{49} = 65 + 462 + 3283 = 3810 \)

\(hash(BCD) = 66\cdot {7^0} + 67\cdot{7^1} + 68\cdot{7^2} = 66 + 67\cdot{7} + 68\cdot{49} = 66 + 469 + 3332 = 3867 \)

Kaydırma adımına bakarsak ilk diziden A harfi çıkarılıyor ve yerine D harfi ekleniyor. Bu adımı ilk hesaplana hash değeri ile beraber kullanırsak şöyle bir hesaplama çıkarabiliriz. Önce çıkarılan harfin değerini önceki hash değerinden çıkaralım:

\(3810 – 65 = 3745 \)

ABC dizisindeki harfler bir sonraki dizide BC şeklinde bir harf sola kaydığına göre basamak değerleri de ona göre kayacak. İlk hesapta B’nin basamak değeri \(7^1 = 7 \) iken ikinci hesapta basamak değeri \(1 \) olacak. C’nin basamak değeri de ilk hesapta \(7^2 = 49\) iken ikinci hesapta \(7 \) olmakta. Yani kaydırma sırasında düşen harfi çıkardıktan sonra kalan harflerin değerleri öncekinin yedide biri oluyor, yani kalan sayısı 7’ye böleceğim.

\(3745 : 7 = 535 \)

Şimdi yeni hash değerini bulmak için sadece kaydırma sonunda diziye eklenen harfin değerini toplamak kaldı. Yeni eklenen harfin basamak değeri her zaman \(7^2=49 \) olduğundan son işlemimiz

\(535 + 68\cdot49 = 535 + 3332 = 3867\) olur. Bu da normal hesapladığımızda çıkan sonuca eşittir.

Simulasyon linkine geçmeden önce bu algoritmanın istediğimiz performansı vermesi için tabii ki aradığımız metin parçasının uzun olması gerektiğini ekleyeyim. Çünkü her durumda yapılması gereken işlem sayısı aynı. Bir çıkarma, bir bölme, bir çarpma ve bir toplama ve bir kuvvet alma. Bu işlemlerin toplamdaki yükü aranan dizinin boyu uzadıkça azalacaktır. Simulasyona geçmeden önce bir de tanımdaki sabit uzunluklu kısmına dikkat çekmek istiyorum. Buraya kadar anlattığım yöntemde hash değeri sonuçta keyfi uzunlukta bir harf dizisinin oluşturduğu polinomun değeri olacağından bu haliyle sabit bir uzunluğa sahip olmayacaktır. Bu sorunu gidermek için sonucu seçtiğimiz bir sayıya göre modulo işlemi yaparak bulabiliriz. Böylece hash değerimiz her zaman sınırlı olacaktır. Simulasyonda şimdilik bu modulo işlemini kullanmadım ama ileride bunu da ekleyebilirim.

Simulasyon

Simulasyonda her kaydırma işleminden sonra diziden çıkarılan harf kırmızı ile diziye yeni eklenen harf ise yeşil renkle gösterilmiştir.

Perceptron (Yapay sinir ağları)

Yapay sinir ağları, yapay zeka sayesinde bir süredir yine oldukça popüler konulardan biri oldu. Yaklaşık çeyrek asır önce üniversitede bu dersi almıştım ve hoşuma gitmişti. Sanki yeterince hobim yokmuş gibi bu alandaki yeniliklere göz atmaya karar verdim. Yapay zeka uygulamalarını programlamak için olası en kolay yolların matlab ya da tensorflow tabanlı kütüphaneler olduğunu gördüm. Bu arada biraz python da öğrenebilirim belki dedim ve tensorflow kendimi akımına bıraktım.

Bu ikinci öğrenme aşamasında yaptıklarım üzerine yazılar yazmayı düşünüyorum. Sistem olarak Ubuntu 19.04 altında python 3.7 ve pip3 kullanıyorum. Editör olarak eclipse ve PyDev eklentisini (7.3 versiyonu) kullanıyorum. Bu sistemlerin kurulumu için internette bir sürü kaynak olduğundan bunlara şimdi girmeyeceğim.

İlk yazımda yapay sinir ağlarının temel taşlarından olan perceptron modeli üzerine bir animasyon göstermek istedim. Animasyonları mümkün olduğunca HTML 5 ile programlamak istiyorum. İlk animasyonda perceptron modelinin en basit halini programladım. Sadece bir girdisi ve tek bir ağırlık değeri var. Dolayısıyla hesaplamaları da oldukça kolay. Umarım anlaşılması da kolaydır. Bir sonraki animasyonda birden fazla girdisi olan perceptron programlayacağım.

Perceptron için basit bir blok diyagram

Perceptron kabaca birden fazla girdisi ve bir çıktısı olan bir nöron modelidir. Perceptrona gelen girdiler önce her girdiye ait olan ağırlık değerleriyle çarpılır ve sonra bu çarpımlar toplanır. Bu toplamlar belli bir değerin üzerindeyse bu perceptron aktifleşir, değilse aktifleşmez.

Şimdi animasyonla biraz oynayalım. Girdi değeri bu animasyon için -1 ile 1 aralığında seçilebiliyor. Ağırlık değeri de -10 ile 10 arasında seçilebiliyor. Ardından başlat düğmesine basıldığında yapılan hesaplamalar ekranda gösteriliyor. En sonunda perceptron etkinleşmişse yeşil, etkinleşmemişse kırmızı oluyor. Etkinleşme için bu animasyonda signum fonksiyonunu kullandım. Yani toplamın sonucu sıfırdan büyükse bu fonksiyon 1 değerini veriyor. Diğer her durumda da 0 değerini.

Animasyonun altında bir sayı doğrusu üzerinde seçilmiş ağırlık değeri için hangi girdilerde perceptronun etkinleşeceğini (yeşil renkli kısım) ve hangi girdi değerleri için etkinleşmeyeceğini (kırmızı renkli bölge) çizdirdim. Bu gösterim için JSXGraph kütüphanesini kullandım. Bu şekilden de anlaşıldığı gibi eğer ağırlık değeri pozitif ise, pozitif girdiler için etkinleşme olacak, negatif değerlerde perceptronun çıktısı 0 olacak. Eğer ağırlık değeri negatif ise bu sefer perceptron negatif girdiler için etkinleşecek ve pozitif girdiler için 0 çıktısını verecek. Bunu matematiksel olarak da görmek kolay. Yukarıdaki diyagramda sadece bir tek girdi ve tek ağırlık olduğunu var sayalım. Animasyonda kullandığım f fonksiyonu şu şekildedir.

math-sgn-function-in-cpp How to Implement The Sgn Function in C++? c / c++ math programming languages

O zaman çıktı fonksiyonunu şu şekilde yazabiliriz:

\(o = sign(i\cdot{w}) \)

Eğer girdi (i) sıfırsa ya da ağırlık (w) sıfırsa, çıktı 0 olacaktır ( o = sign(0) ). Bunun dışındaki durumlar için ise aşağıdaki şekilde olacaktır.

\(o = sign((w > 0) \cdot{( i < 0)}) = sign(< 0) = -1 \)

\(o = sign((w > 0) \cdot{( i > 0)}) = sign(> 0) = 1 \)

\(o = sign((w < 0) \cdot{( i < 0)}) = sign(> 0) = 1 \)

\(o = sign((w < 0) \cdot{( i > 0)}) = sign(< 0) = -1 \)

Yukarıda w > 0, pozitif ağırlık değerleri, i > 0 da pozitif girdi değerleri anlamına geliyor. sign(>0) da sign fonksiyonunun girdisinin pozitif olduğu anlamına geliyor. Aynı şekilde < işaretini de bu değerlerin negatif olduğu durumlar için kullandım.

Yani bu basit perceptron ağırlığın sıfır olmadığı durumda sayı doğrusunu hep sıfır noktasında ikiye bölüyor. Sıfırın bir tarafı için -1 değerini üretirken, diğer tarafı için de 1 çıktısını üretiyor. Bu şekliyle oldukça sıkıcı bir zeka birimine benziyor ama ileride bu aksaklıkların üstesinden gelmenin yollarına bakacağız.

Basit vektör işlemleriyle ilgili bir oyun (Toplama)

Bu seferki test oyunumuz da vektör işlemleri üzerine. İlk olarak toplama işlemini ele aldım. Koordinat sisteminde verilen iki vektörün toplamını bulmaya dayalı bir oyun. Cevap, toplam vektörünün bitiş ucunu seçerek veriliyor, vektörün başlangıcı (0,0) noktası olarak kabul ediliyor.

Eğer verilen cevap doğruysa seçilen vektör yeşil renkle gösteriliyor, yanlışsa kırmızıyla. Bu durumda doğru cevap tabii ki yeşil bir vektörle gösteriliyor. Her doğru cevap 100 puan. Belki ileride doğru cevapla beraber toplanan vektörlerin oluşturduğu paralelkenarı da çizdirebilirim, ya da vektörlerden birini diğer vektörün ucuna kaydırıp toplamı gösterebilirim.

 

Oyun

 

Doğru denklemleri oyunu – 2

Bu oyunda da geçen oyunun tersi yapılıyor. Her soruda değişik renklerde dört doğru grafiği veriliyor ve altta verilen denklemin hangi grafiğe ait olduğu soruluyor.

Tablet ve cep telefonları için tuşları ve ekran büyüklüklerini bir aksilik çıkmazsa bu hafta iyileştirmeyi düşünüyorum.

Oyun

Bir doğru denklemi bulma oyunu

Geçen yıl bir veli toplantısında bir velinin sorduğu şu soru beni hayretlere düşürmüştü:

– Çocuklar matematik çalışmak için ders kitabından başka nereden soru bulabilir? Ders kitabında çok az soru var.

Ders kitabında çocuğun öğrenmesi beklenen her fikir ya da yöntem için normalde en fazla on tane soru oluyor. Bunların da çoğu derste yapılıyor ya da ev ödevi olarak veriliyor. Sınava hazırlanmak için kitaptaki soruları çöz deyince de çocuklar genelde biz onları zaten yaptık diyorlar. Anlaşılan bu veli de böyle bir cevap almıştı ve daha başka soru kaynağı arıyordu. Oysa sonsuz sayıda sayı olduğuna göre yeni soru üretmek çocuk oyuncağıdır. Kitaptaki örnek sorular alınır ve değişik sayılarla sonsuz adet soru yapılır. Tabii ebeveynler bu iş için zaman harcamak istemez. Ne de olsa sorunun kolay çözülebilmesi için sayıları doğru seçmek biraz enerji gerektiren bir işlemdir.

Geçenlerde çocuklar eve gelince bana bir android uygulaması gösterdi. Verilen bir tamkare sayının kare kökünü bulmaya dayanan bir oyun. Nedense çocuklar bunu sevmişti. Ben de matematik soru üretme işini böyle denemeye karar verdim. İlk programımda x-y koordinat sisteminde verilen bir doğru grafiğinin y = mx + n şeklindeki denklemini seçeneklerden bulma şeklinde bir test oyunu yaptım. Her doğru cevaba 100 puan veriliyor. Bakalım çocukların ilgisini hiç çekecek mi?

Oyun

Evrim ve genetik algoritmalara küçük bir giriş

Richard Dawkins, Kör Saatçi adlı kitabında bir programdan bahseder. Bu program rastgele değişimler ve rastgele olmayan seçimler sayesinde nesiller boyu işleyen bir algoritmanın tamamen rastgele şekilde işleyen bir mekanizmadan çok daha çabuk hedefe ulaşacağını gösteren bir deneydir.

Bu deneyde Dawkins ‘METHINKS IT IS LIKE A WEASEL’ cümlesini kullanır. Eğer bir maymun rastgele İngilizce alfabedeki 26 harfi ve boşluk karakterlerini kullanarak bu cümleyi yazmaya çalışırsa çok çok uzun zaman bu işle meşgul olurdu.

Dawkins, bunun yerine maymunun çalışma prensibinde hafif bir değişiklik yapılırsa çok ilginç bir sonuç çıkacağını söyler kitabında. Diyelim ki maymun yine rastgele 28 harflik (cümle 28 harf uzunluğunda) bir şey yazsın. Daha sonra bu cümleyi kopyalamaya başlasın ama bir farkla. Kopyalarken arada rastgele hatalar yapsın, yani bazı harfler kopyalarda değişsin (mutasyon). Daha sonra maymun o yazdığı ve kopyaladığı cümleler grubunda hedef cümleye en yakın cümleyi seçsin ve o ana kadar yaptığı adımları tekrarlasın. Böylece nesiller sonra maymun hedef cümleyi bulacaktır ve bu iş için gereken nesil sayısı tamamen rastgele seçim olan algoritmadan çok daha az olacaktır.

Bunu denemek için bir javascript simulasyonu programladım. Her nesildeki birey sayısını ve mutasyon oranını girdikten sonra ya animasyonlu ya da animasyonsuz çalıştırılabilir. Öncelikle animasyonsuz çalıştırılmasını öneririm. Böylece daha hızlı çalışacaktır ve daha kısa sürede bütün işlemlerin yaklaşık kaç nesil süreceği görülebilir. Bu esnada yukarıda nesil numaraları ve o nesildeki hedefe en yakın cümleyi görebilirsiniz.

Eğer animasyonla çalıştırılırsa maymunun yaptığı işlemleri ‘ağır çekimde’ görülebilir. Cümlelerdeki mutasyonlar, yani hatalı kopyalanan harfler kırmızı gösteriliyor. Ardından maymunun seçimi yeşil arkaplan rengiyle gösteriliyor. Bundan sonra o nesil komple siliniyor ve yerine maymunun seçtiği cümlenin tam kopyaları koyuluyor. Animasyon bu adımların tekrarlanmalarıyla devam ediyor. Küçük bir uyarı yapayım, bu adımlar çok yavaş gösterildiğinden bütün simulasyonu seyretmek çok zaman alacaktır.

Hedefe çabucak ulaşmak için kalabalık popülasyonlar seçmek daha iyi olacaktır. Animasyon kullanılmayacaksa 100 iyi bir popülasyon büyüklüğüdür. Animasyon için ise ne kadar küçükse o kadar iyi ama bu durumda da bütün simulasyon çok uzun sürecektir. Mutasyon değerini küçük tutmak iyidir. Örneğin 0.05 (Her harf yüzde beş ihtimalle değişebilir) yeterli bir değer. Aşağıdaki linkten simulasyon sayfasına ulaşabilirsiniz.

Gelincik programı

Renkler ve beyin

Stroop etkisini basit bir şekilde gözlemlemek için küçük bir program yazdım.


(Wikipedia'dan alıntı) Stroop etkisi. John Ridley Stroop'un 1935 yılında geliştirdiği 
üç kısımdan oluşan bir bilişsel kontrol testi. 
Bir rengin adı (örneğin, "mavi," "yeşil," ya da "kırmızı") 
farklı bir renkle yazıldığında (örneğin "kırmızı" kelimesi kırmızı renkle değil 
mavi kalemle/renkle yazıldığında) kelimenin rengini saptama isleminin daha fazla 
süre aldığını ve aynı renkle yazılması durumuyla karşılaştırıldığında daha fazla 
hata yapıldığını belirtmektedir. Bu okuma ve okuma sonucundaki anlama isleminin 
otomatik ve daha hizli olarak gerceklesmesinden kaynaklanmaktadir. Renk saptama islemi 
ise okuma kadar otomatiklesmis bir islem degildir.

Aşağıdaki linke basılarak oynanan oyunda amaç basit: Büyük kutudaki yazının rengini aşağıdaki seçeneklerden mümkün olduğunca çabuk seçmek. Oyun iki değişik soru seçiyor. Birinde kutudaki rengin adıyla rengin kendisi aynı. Diğerinde ise bu ikisi de farklı. Stroop etkisine göre ikisinin farklı olduğu durumda beynimizin doğru rengi bulması biraz daha uzun sürmeli.

Kutunun üstündeki kutularda o ana kadarki bazı istatistiki bilgiler var. Sol tarafta renkle yazının aynı olduğu soruların bilgileri, sağ tarafta da farklı olduğu durumdaki sonuçlar gösteriliyor. Doğru ve yanlış cevaplar ayrı ayrı sayılıyor. Toplam ve ortalama süre de sadece o kısımda verilen doğru cevaplar üzerinden hesaplanıyor.

Program

Bir Kelime

Sonunda JavaScript öğrenme programım altında bir zamanlar televizyon ekranı başında oynadığımız “Bir Kelime Bir İşlem” yarışmasının “Bir Kelime” kısmını da bitirdim. Aşağıdaki linkten oyunu oynayabilirsiniz.

Sayfa ilk yüklendiğinde bütün imla kılavuzu da beraber yükleniyor. Bu şimdilik yaklaşık 1.5 MB yer tutuyor. Bundan sonra sayfa kapatılana kadar bir daha böyle bir yüklemeye gerek yok, yani oyun çevrimdışı da oynanabilir.

Oyun için önce rastgele yedi harf seçmek gerekiyor. Bu seçimi oyuncu ünlü ya da ünsüz olacak şekilde yapıyor. Bu tuşlar solda. Yedi harf de seçildiğinde oyun başlıyor. Oyuncu harflerin üzerine basarak kelimesini renkli alanda oluşturabiliyor. Bu sırada bir tane de joker harf kullanma hakkına sahip. Bu harfi joker tuşuna (ortadaki) bastıktan sonra aşağıda çıkan klavyeden seçerek yapıyor. Oyuncu en iyi kelimeyi bulduğunu düşündüğünde kabul tuşuna basarak çözümünü kontrol ettiriyor. Eğer kelime imla kılavuzunda mevcutsa puan alıyor, değilse alamıyor. Oyunun her anında programa o harflerle yazılabilecek en uzun kelimeler sorulabiliyor. Çözüm tuşuna basıldığında program bulunabilecek en uzun kelimeleri alttaki alanda gösteriyor.

Kullandığım çözüm bulma algoritması da basit bir şey. Önce her harf için bir map oluşturuyorum. Bu map içinde o harfin bulunma adedine göre kelimeleri grupluyorum. Yani bir grup içinde bir adet a harfi bulunan kelimelerden oluşuyor, bir başka grup içinde iki adet a harfi bulunduran kelimelerden. Bu şekilde bütün imla kılavuzunu hazırlıyorum. Oyunda çözüm istendiğinde seçilmiş harflerin N’li (N maksimum harf sayısı olan 7’den 2’ye kadar) kombinasyonlarını oluşturuyorum ve içinde bu harfleri seçildikleri adet kadar barındıran kelime gruplarının kesişimlerini buluyorum. Sonra bu kesişim kümesindeki kelimelerin uzunluklarına bakıyorum. Eğer kelimenin uzunluğu kombinasyondaki harf adedi kadarsa jokersiz, harf adedinden bir fazlaysa bir jokerli çözüm bulunmuş oluyor. Bu çözümlerin hepsini de çözüm kümesine ekliyorum.

 Bir Kelime

Bir İşlem

Yurt dışında “Countdown”, Türkiye’de ise “Bir Kelime Bir İşlem” adıyla bilinen yarışma programının işlem kısmını sonunda bir Web uygulaması olarak bitirmiş bulunuyorum. Sayfa düzeni şimdilik mobil cihazlar göz önünde tutularak hazırlanmış durumda.

Oynanış: Oyunda hedef verilen altı adet sayıyyla dört işlem yaparak hedef sayıya mümkün olduğunca yaklaşmak. Bir kullanılan sayı bir daha kullanılamıyor. Bu sayılar kırmızı kenarlarla gösteriliyor. Sarı kenarlı sayılar kullanılabilecek sayıları gösterirken, seçilmiş sayı da yeşil kenarla gösteriliyor. İşlemin ilk sayısını seçtikten sonra bir işlem seçiliyor. Ardından da bu işlem için gereken ikinci sayı seçiliyor. Bu aşamada program işlemin sonucunu ilk seçilen sayının yerine yazıyor ve ikinci sayıyı kullanılmayacak şekilde işaretliyor. Bir sonraki adımda işlemin sonucu hemen kullanılabilsin diye bu sayı otomatik olarak seçiliyor. Eğer başka bir sayı ile işlem yapılmak istenirse kullanıcı sarı sayılardan birini seçebilir. Bu durumda seçilen sayı değişecektir.

İşlemlerin altındaki sırada ise oyunla ilgili tuşlar bulunmakta. En soldaki tuş o ana kadar bulunmuş en yakın sonucu çözüm olarak değerlendirmeye sokuyor. Bu tuşa basılınca kalan zamana ve hedefe ne kadar yaklaşıldığına göre bir skor hesaplanıyor. Onun yanında çözüm tuşuna basılınca program hedefe olası en yakın çözümü hesaplıyor ve bu tuşların altındaki alana bu çözümü yazıyor. Geri al tuşuna basınca son yapılan işlem geri alınıyor ve kullanıcı başka bir işlem yapabiliyor. Bu şekilde oyunun en başına dönmek mümkün. En sağdaki tuşla da yeni bir oyun başlatılıyor.

Programla ilgili biraz da bilgi vereyim. Oyun HTML, CSS ve Javascript kodlarından oluşuyor. Çözüm algoritması verilen sayılarla olası bütün işlemleri yapıyor ve her işlemden sonra sonuçla karşılaştırıyor. Eğer ciddi bir hata yapmadıysam çözüm tuşuna (ampule) basınca program en iyi çözümü gösterecektir. Bu en iyi çözüm sırasında bazen gereksiz işlemler de oluyor ama sonucu etkileyen bir durum değil bu. Henüz bu gereksiz işlemleri çözümden çıkaracak kısmı programlamadım.

Program mobil cihazlarda CSS viewport birimleri destekleyen tarayıcılarda doğru gösteriliyor. Şimdilik sadece Chrome (51 ve sonrası) ve Firefox (48) versiyonlarıyla test edebildim. Android standard tarayıcıda doğru çalışmadığına dair ekran görüntülerini de gördüm.

Programın geliştirilmesi aşamasında fikirlerinden (Kullanıcı ara birimi ve oynanış) faydalandığım Hatice Savaş’a da teşekkürlerimi sunarım.

Bir İşlem

Mandelbrot kümesi

Sonunda daha önce Julia kümeleri üzerine yazdığım bir yazıda da kısaca bahsettiğim Mandelbrot kümesi programını da hallettim. Aslında sonuçlar Julia kümesindeki kadar ilginç olmadığı için (Meşhur Mandelbrot şeklini kim bilmez ki?) programlara zoomlama eklerini de daha sonra eklemeyi düşünüyorum.

Bu programda Julia kümesinden tek fark \(z_{n+1} = z_n^2 + c \) dönüşümünde \(z_{0} = 0 \) başlangıç durumunu almak ve grafiğin noktalarına göre c sabitini belirlemek. Yeni algoritma bu durumda aşağıdaki gibi olacaktır:

Algoritma:

  1. \(z=0 \) olacak şekilde kompleks değişkenimize ilk değer atanır.
  2. Çizim yapılacak ekranın her noktası için: Seçilen nokta bir \(c \) kompleks sayısına dönüştürülür.
  3. Her adımda elde edilen kompleks sayı yarı çapı 2 olan dairenin dışına düşmediği ve maksimum adım sayısına erişilmediği sürece dönüşüm uygulanır.
  4. Seçilmiş nokta için elde edilen adım sayısına göre bir renk üretilir.
  5. Seçilmiş nokta ekran üzerinde bu renge boyanır.

Program Julia kümesindeki programa çok benzediğinden daha fazla açıklama yapmayacağım. Programa aşağıdaki bağlantı üzerinden açılan sayfada erişebilirsiniz. Sağ fare tuşuyla sayfa kodunu ve sayfa içindeki javascript programını indirebilirsiniz.

yilmazaksoy.com/apps/Mandelbrot.html