"Dostlar Alışverişte Görsün" Design Pattern

Diyelim ki bir işi framework kullanıcılarına sunuyoruz. Bu iş de mesela, byte matrisini alıp belirli resim formatlarına çevirmek olsun (örneği sallıyorum tamamen). Bu DLL'i kullanacak insanları düşünerek, kodun da daha 2. kod geliştirmede çöpe dönmesini istemeyen insanlar olarak basitçe aşağıdaki gibi bir yapı veriyoruz;

Sonrasında da istediğimiz kadar formatı bu interface'ten türetebiliriz

Artık bunları da factory mi kullanırsın, ne yaparsın oradan türeterek insanlara dönersin, insanlar da interface üzerinden kullanır değil mi?

Ne güzel mis gibi oldu değil mi? Ha AbstractImageEncoder  falan da eklersin de genel yaklaşımın bu olması gerekiyor en azından.

Peki Türk yazılım standartlarına göre bu sorunu nasıl çözüyoruz? Diyelim ki sizden önceki yazılımcı (ben) bu interface'i yazmış ve örnek olacak şekilde bir alt sınıfını da yazmış. Siz buna uyuyor musunuz? Tabii ki hayır! Önce gidip, bu işi yapan eşşek kadar DLL olmasına rağmen yeni format için yeni bir DLL oluşturuyor, aşağıdaki gibi kendi kodunuzu yazıyorsunuz.

Sonra insan gibi sizi uyarıyoruz, diyoruz ki arkadaş zaten bununla ilgili bir yapı var, kodunu buna entegre et. Sen napıyorsun sonra güzel kardeşim;

...

Üniversitelerde API tasarımı diye bi ders olması lazım yahu.

OracleCommand.BindByName

Diyelim ki C# ile, Oracle veritabanında bulunan aşağıdaki stored procedure'u çalıştırmak istiyoruz.

Yazmamız gereken kod aşağıdaki gibi bir şey olacak;

Burada parametreleri eklerken SP ile aynı sırada verdiğimiz için bir sıkıntı yok ama kodu aşağıdaki gibi yazsaydık SP içerisinde PARAM1  2, PARAM2  ise 1 değerini alacaktı.

Oracle.DataAccess dll'indeki OracleCommand  sınıfı, aksi belirtilmediği sürece parametrelerin isimlerini değil verilme sıralarını dikkate alıyor. Neden default olarak böyle olduğunu anlamadığım bir şekilde bu durum, command  nesnesindeki BindByName  parametresi ile çözülebiliyor.

İşin gücün insana sıkıntı çıkarmak Oracle.

CodeFights

Codefights diye bir site meşhur oldu bu aralar. Diğer yarışma sitelerine göre daha eğlencelik bir formatı var. İki kişi karşılıklı gelip verilen kodda hata bulmaya çalışıyorsunuz. Önce bulan 100 puan diğeri 50 puan alıyor. Bulamayan ya da yanlış cevap verense -25 puan alıyor.

Tek başına oynama gibi bir formatı da var, ben daha çok burada vakit geçirdim şimdiye kadar. Orada da aynı şekildeki görevleri zamanlı olarak yapıyorsun.

Toplamda çok fazla zaman harcayamadım ama güzel bir siteye benziyor. Muhtemelen çok takılınca aynı sorulara denk gelmek sıkıcı olacaktır, ben bile benzer sorulara birkaç kez denk geldim.

ocozalp nickiyle takılıyorum. PES yerine kod atmak isteyen beni bulsun :) .

Screenshot from 2014-12-15 00:55:41

Euler Totient ve Eratosthenes'in Kalburu

Project Euler'deki 72. soruyu çözmek için 2'den n'e kadarki sayıların Euler Totient değerlerini hesaplamak gerekiyor. Düz bir mantıkla, n'den küçük veya eşit tüm asal sayıları hesaplayıp her sayı için Euler formülü ile sonucu hesaplamak mümkün. Aşağıda bu yöntemin kodu var;

Burada asal sayıları ayrı bir listede tutmak gerekli değil. Bunun yerine, sieve  listesini kullanarak totient değerini aşağıdaki gibi hesaplayabiliriz;

Her iki kod da hemen hemen aynı complexity değerlerine sahip ama ikincisi daha kısa :).

Swamp Search

Grid şeklindeki haritalar, yapıları basit olduğundan ve grid üzerinde hareket edecek olan nesnenin (robot, oyun karakteri vs.) hareketi gerçek bir nesneden çok daha basit olduğundan bu haritalar için birçok heuristic yöntemi üretilebilir. Jump Point Search algoritmasında olduğu gibi yeni algoritmaların genelde iyileştirmeye çalıştıkları konu değerlendirilen node sayısı oluyor. Swamp Search algoritması da node sayısını iyileştiren algoritmalardan bir tanesi.

swamp

Algoritma harita içindeki swamp, yani bataklık alanları buluyor. Bataklık alanları şöyle açıklayabiliriz: Elimizde, grid üzerinde bir nokta kümesi olduğunu varsayalım. Bu kümenin dışında kalan tüm nokta çiftlerinin arasındaki en kısa yolları da hesapladığımızı düşünelim. Eğer bu kısayollardan hiçbiri elimizdeki kümeden geçmiyorsa bu alan bataklık olarak adlandırılır (Yukarıdaki resimde \(S = \{S1, S2, S3, S4\}\) kümesi bataklık olarak değerlendirilebilir). Eğer tüm bataklık alanları hesaplayabilirsek, iki nokta arasındaki yolu hesaplarken bu alanları yoksayabiliriz. Bu da çok fazla engelin olduğu bir haritada işimizi epey kolaylaştıracaktır. En azından şimdilik öyle görünüyor. Bakalım :)

Algoritmanın ilk adımında seed (tohum) olarak adlandırılan noktaları bulmak gerekiyor. Bu noktalar için basitçe bataklıkların yetişeceği noktalar denilebilir. Kendisi bir engel olmayan, düşey ve yatay eksende en az birer komşusu engel olan noktalar seed noktalar olarak alınabilir. Örneğin yukarıdaki resimdeki \(S4\) noktası solundaki ve yukarısındaki noktalarda engel olduğu için bir seed noktasıdır.

İkinci adımda \(r=1\) yarıçapı ile başlayarak seed noktayı genişletmek gerekiyor. Her seferinde seed noktadan en fazla r adımda ulaşılabilecek noktaları buluyoruz. Bu bizim bataklık olarak belirlediğimiz bölge oluyor.

Son adımda ise, ikinci adımda belirlediğimiz bataklıktaki noktaların sağlamasını yapmamız gerekiyor (gereksiz yere bir noktayı bataklığa dahil ettiysek çıkarmamız gerekecek). Bunun için bataklık bölgenin sınırındaki noktaları alıyoruz. (Sınırdaki noktalar = Bataklığa komşu olan ve bataklığa dahil olmayan noktalar). Sınırdaki her nokta çifti için en kısa yolu hesaplıyoruz. Eğer yeni bulduğumuz bataklık bu iki nokta arasındaki yolu uzatmışsa, yol üzerinde bulunan ve bataklığa dahil olan tüm noktaları bataklıktan çıkarıyoruz.

2. ve 3. adımları her seed nokta için, \(r\)'yi arttırarak tekrarlayabiliriz. Bataklığı büyütme işi maksimum yarıçap, maksimum bataklık büyüklüğü gibi çeşitli kriterlere göre sınırlanabilir.

Benim bu algoritmada sevmediğim şey çok fazla statik olması. Evet hesaplama bittikten sonra A*'ın çalışmasını epey azaltabiliyor ama asıl sancılı olan da bu hesaplama süresi. Büyük haritalarda \(r\) kısıtını yüksek tutmak gerektiğinden değişken haritalar için kullanılabilir bir yöntem olmayacaktır. Az engelin bulunduğu haritalar içinse A*'ın çalışma zamanına yakınsayacaktır.

Neticede çok kullanışlı bir algoritma olmasa da mantığı ilginç. Detaylı okuma buradan yapılabilir.