Basitten karmaşığa bir kodun hikayesi
mert 2012-10-17, 13:46 #1
Konu adı: Basitten karmaşığa bir kodun hikayesi
Uzun zaman önce D dilini çalışırken, "Bir oyun yazmaya kalksam, tasarım aşamalarını acaba nasıl gerçekleştirebilirdim"? sorusuna şöyle yaklaşmıştım.
"Bir kahraman tasarlarım. Bu kahraman oyuna başlandığında bir bıçakla donatılır. Gelişme kaydettikçe sırasıyla kılıç, tabanca, tüfek, bomba gibi silahlara sahip olur. Devamını getirebilirsem kendisini bisiklet, motosiklet, atv, pikap, tank gibi araçlarla donatırım"
Her ne kadar bu plan tam bir tasarım faciası olsa da dil üzerinde keyif alarak alıştırma yapabilmemi kolaylaştıracak, öğrenme eğrime katkıda bulunacaktı.
Bu oyun alıştırmasını gerçekleştirme fikrine sanırım http://ddili.org/ders/d/islevler.html bu dersin sonunda kapılmıştım. Öyle ya boru değil irisi ufaklısıyla tam otuziki konu üzerinde çalışmış yeterince palazlandığıma iyice ikna olmuştum.
Başlangıçta kahramanımızın bir enerji seviyesi olacaktı. Kendisinin kullanımına sunulan her silah düşmanında da bulunacak birbirleri ile dövüşürlerken vurduğu/aldığı darbeleri kullanılan silahın türüne göre hesaplattıracaktım.
Ne vardı ki bu basit kodu yazamayacak:
double kahramanınEnerjisi = 100_000;
double düşmanınEnerjisi   = 100_000; /// 
double bıçakDarbesi       = 0.1;     /// 
// Kahramanımız beceriksiz çıkıyor ve kendini yaralıyor
double bıçakDarbeliKahraman = kahramanınEnerjisi * bıçakDarbesi;
writeln("Kendini kesen Sakar kahraman : ", bıçakDarbeliKahraman);
// Kendini kesen Sakar kahraman : 10000
Eh acemice de olsa bir başlangıç yapmıştık. Ancak bütün kodlamaları main'in içinde toplamanın kodlamam ilerdikçe bana sıkıntı yaratacağı da aşikârdı.
Buna bir çare bulmalıydım...
 '_' Rakamların kodlama aşamasında kolayca takibi için ayraç
 Hazır değer. Her iki not için ilgi http://ddili.org/ders/d/hazir_degerler.html
Bu mesaj 2 defa değişti; son değiştiren: mert; zaman: 2012-10-17, 14:12.
acehreli (Moderatör) 2012-10-17, 14:29 #2
Bence çok güzel olacak!
Salih Dinçer 2012-10-17, 15:19 #3
Bu konuyla yakından ilgileniyorum çünkü şu günlerde FarmVille2 oynuyorum...
Oradaki her bir nesnenin değeri (para, deneyim, yem, su, gübre, seviye, ürün adetleri vb.) birbirleri ile o kadar ilişkili ki! Eğer yeminiz varsa sahip olduğunuz hayvanı besleyebilirsiniz. Yoksa tarlaya tohum ekip yeme çevirmelisiniz. Tohum da yoksa paranız ile satın almalısınız. Ama sonuçta ekme, biçme, çevirme (pazarda satma) hatta besleme sizin seviye artmanızı sağlıyor. Seviyeniz arttıkça gizli olan ürünleri satın alabiliyor, tarlanızı çevresindeki arsalar satışa çıkıyor ve böylece (her manada!) genişliyorsunuz...
Biliyorum çok aptalca! Çünkü her şey; bir veritabanı içindeki büyük bir tablonun satır/sütunları arasındaki değerlerin birbirine dönüşmesi ve kendinizi iyi bir şey yapıyor hissi vermesinden başka bir şey değil. Gerçek hayatta bu işler o kadar kolay değil...
mert 2012-10-17, 15:30 #4
FarmVille2 'i denemedim de ben Generals hayranı olduğumdan o oyunun tasarımını beğeniyorum. Uçaklar, tanklar vs. vs. Her birinin birimin hem vuruş hem darbe,hem seviye, hem hareket algoritmaları var. Çoğunlukla oradan akıl yürütüyorum. İşte bir barakadan değişik işlevlere sahip askerlerin türemesi, her birinin benzerlikleri farklılıkları falan filan.
Neyse bakalım kodumuzu nereye kadar geliştirebileceğiz
mert 2012-10-17, 16:04 #5
Konu adı: Aşama -1
Sakar kahramanımın ona sağladığım silahları kullanmayı öğrenene kadar kendisinden başka bir düşmana ihtiyacının olmadığını anladıktan sonra 'düşmanım' yordamını bir süreliğine gözardı edebileceğimi düşünüp main() işlevimi toparlamaya karar verdim.
Öyle ya main işlevi programımın başlayıp bittiği yer. Programın bütün tasarımını orada yapacaksam bir süre sonra kodları takip etmekte zorlanacağım. Eh işlevleri de hazır daha yeni öğrenmişim diyerek kahramanımın ve olası düşmanlarının alacağı bıçak darbelerini hesaplatabileceğim bir işlev tasarlayarak bu sorunuma nasılsa çare bulurum diyerek kodlamaya başladım:
void bıçakDarbesiniHesapla(ref double kahramanınEnerjisi) //
kahramanınEnerjisi = kahramanınEnerjisi * 0.1;        // 
writeln("Bıçak darbesi alan kahramanım : ", kahramanınEnerjisi);
// Bıçak darbesi alan kahramanım : 10000
Gayet güzel. Kahramanım elindekini kullanmayı öğrenene kadar bu işlev yetecek gibi...
Madem ki bir işlev tasarladım, bari hakkını vereyim diyerek olası hatalarıma/ eniyileştirme olanaklarına bir kez daha göz atabilmek için http://ddili.org/ders/d/islevler.html dersine yeniden dönüş yaptım.
İyiki de dönüş yapmışım...
 ilgili bağlantıda 'iş yapmak' konusu altında belirtilen yan etki oluşturan işlevimiz
 Halen kullanmakta olduğum hazır değer
Bu mesaj mert tarafından değiştirildi; zaman: 2012-10-17, 16:22.
Salih Dinçer 2012-10-17, 23:37 #6
Bu yorumunda çok derin anlamlar yatıyor...
Peki, güzel olması için ne tür tedbirler almalıyız? Yani karmaşığa gideceğini biliyoruz; örneğin Kahraman sınıfının, ileride üye sayıları artacak. Hatta biz bu sınıfın kopyalarını başka sınıflar ile paylaşıp (miras alma olayı) işte o zaman işler sarpa saracak. Birbirine benzeyen üyeler, override olması gerekenler vb...
Yine de iki şeyi hatırlıyorum:
Ara eniyileştirmelerden (code optimization) kaçın
Bir şeyi hemen sınıfa dönüştürme, önce yapı sonra gerekiyorsa sınıf
En iyisi yapı ve sınıflar ile ilgili dersleri tekrar bir gözden geçirelim...
mert 2012-10-18, 07:15 #7
Onlara gelene kadar olası güzelliğin yerini sıkıntıya bırakacağını düşünüyorum ben. Ama nihayetinde bir yalınlaştırma alıştırması deniyorum. Belki bu çalışmadan sorduğun sorulara yanıtlar bulabilecek aşamaya gelebiliriz, bilemiyorum sonucuna bakmak gerek.
Bu sapma işlevler dersine yeniden referans verebilmek için zorunlu olarak yapıldı. Burada amacım yan etkiler üzerine söylenmiş olanları derleyip toparlamak. Bu aşamada yan etki üreten kod yapılarının tartışılarak daha iyi anlaşılmasını sağlayabilir miyim diye düşünüyorum? Forumda bilgisi çok az. Ali hocam yeterince açıklamış ancak çoğu defa gözden kaçırdığımız bir durum olduğunu düşündüm. Ne dersin Salih, bu biçimde bir açılım sağlasak iyi olur mu?
Bu mesaj mert tarafından değiştirildi; zaman: 2012-10-18, 09:43.
acehreli (Moderatör) 2012-10-18, 10:21 #8
Fazla derine dalarsak şu bile bulunabilir: "Şimdi kötü olmuş. Çoook ileride iyi olacak!" Ama hayır, aklımın ucundan bile geçmedi.
Yazının düzeni kendim program yazarken düşündüklerime benziyor. Amaca götüren en basit kod, gerek duyulduğu için değişiyor.
karmaşığa gideceğini biliyoruz; örneğin Kahraman sınıfının, ileride üye sayıları artacak.
Tabii kodun ne gerektirdiği baştan biliniyorsa gereksizce yetersiz kod yazmak da anlamsız. Bir yazı dizisi olarak yararlı olacak. Yeni başlayanlar bir sürü olanağın birlikte kullanıldığı kodlar görüp neden öyle yazıldığını anlayamıyorlar(dır). Böyle bir gelişim tam o ihtiyacı karşılıyor.
* Bir şeyi hemen sınıfa dönüştürme, önce yapı sonra gerekiyorsa sınıf
Aslında onun kararını tasarımın en başında verebilmek çok daha yararlı oluyor(muş) ve zaten çokşekillilik gerekiyorsa zaten sınıftan başka çare yok.
(Aslında C'de bile kullanışlı olmasa da NYP yapılabildiğini bildiğimize göre D yapılarıyla da işlev göstergeleri filan kullanarak çokşekillilik gerçekleştirilebilir ama gerek yok tabii.)
Bazı türlerin yapı olacakları çok belli: Bir kaç verinin bir araya getirilmesinden oluşan bir tür. En güzel örneklerinden birisi düzlemdeki nokta olabilir: x ve y koordinatlarını bir araya getirir. Aynı noktayı gösteren iki nesnenin kimlik açısından birbirlerinden farkları yoktur. Aynı değeri taşırlar.
Öte yandan davranışı farklı olabilen bir tür ile ilgileniyorsak o zaman sınıf olmalıdır. Bu Hayvan nesnesi o Hayvan nesnesi gibi davranmaz ise o zaman sınıf olmalı.
Tabii bir tasarım yapı ile başlayıp sonra sınıfa da dönüşebilir. Bunun sıkıntılı olacağını düşünüyorum. O türü kullanan ve zaten yazılmış olan kod değer türü düşünülerek yazılmışsa onun yerine referans türü gelince programda hatalar olabilir.
Sınıflarla ilgili bir çok bölüm yeniden gözden geçti ve düzeltildi ama daha siteye koymadım. Bir iki hafta sonra koyarım.
mert 2012-10-18, 10:30 #9
Hislerime tercüman olan yorum:-) Zorlanmıştım başlarda.
Sınıfları ve yapıları henüz yeterince kavrayamamış bir öğrenci deneyiminden yola çıktığımızdan koşullar deneyim sahibini oraya sürükleyecektir muhtemelen. İzlemekte yarar var
Bu yoldan geçilmişti diye hatırlıyorum ilk modelimizde. Burada da hikâye olduğu gibi aktarılacak.
Şu aşamada "Yan etki" konusuna şöyle bir dokunup geçeyim istiyorum. Çünkü değer döndüren bir işlev ile yola devam edilmesinin mantığı açıkta kalmamalı. Ayrıca sarma konusuna da iyi bir referans olur. Katkılar için tam zamanı
Salih Dinçer 2012-10-18, 10:53 #10
Aynı şekilde benim de aklımdan böyle bir şey geçmedi. Ama Ali hocamdan ilginç bir açılım beklediğimi itiraf etmeliyim...
mert 2012-10-19, 04:15 #11
Konu adı: Aşama -2
Bazı oyunları oynarken bir karakter üretirsiniz. Daha başka bir sürü karekter, araç gereç üretmiş ve aktif bir alanda rakiplerinizle karşılaşmaya göndermişsinizdir. İşte bu karakteri ürettirdikten sonra oyunun en hareketli sahnesinde başka bir eyleme odaklanırsınız ve o son ürettirdiğiniz karakter, oyunun en pasif bölgelerinin birinde kendi halinde kalır.
Güzel tasarlanmış oyunların bazılarında bu tür karakterlerle uzun süre etkileşmediğinizde, karakter elindeki araç, gereç, silahla hemhâl olmuş, sizin ilgisizliğinizden sıkıldığını belirten hareketler yapmaya başlar. Yere bağdaş kurar, gereçlerini bırakır, ellerini oğuşturur falan filan...
Bizim Kahramanımızın da ilgisizliğimizden doğan şikayetlerini Ali Hocamıza bildirmesine fırsat vermeden , ihtiyacı olan kodlamalara Önemli bir not düşerek kaldığımız yerden devam edelim.
void bıçakDarbesiniHesapla(ref double kahramanınEnerjisi)
kahramanınEnerjisi = kahramanınEnerjisi * 0.1;
İşlev Parametreleri dersinde gördüğümüz gibi D'de işlev parametreleri normalde işlevlere kopyalanarak geçirilirler.
Benim yukarıda tasarladığım kodda ise işlev parametresinde kullandığımız ref işareti, işlevimize gönderdiğimiz kahramanınEnerjisi parametresinin işlevimize referans olarak geçirilmesini sağlar.
Eğer ben bıçakDarbesiniHesapla() işlevimde bir işlem yapacak ve bunun sonucunda main() içerisindeki kahramanınEnerjisi'ni değiştirerek kullanacaksam, işlevime kullanacağım parametreyi ref olarak işaretleyerek göndermeliyim ki, kahramanım ölümsüzlüğe adım atıp oyunumu tutarsızlaştırmasın.
Ancak bu yaptığım işaretlemenin, benim işlevimin parametresinde değişiklik yapması, onun artık değer üreten bir işlev değil, yan etki oluşturan bir işlev haline gelmesine neden olur. Bu da tasarımımın, işlevsel programlamada pek istenilmeyen bir duruma düşmesine sebep olur. Yan etki üreten işlevlerin kontrol edilebilme yetersizlikleri, ileride programıma yeni özellikler eklemeye kalkıştıkça, programımın güvenilirliği üzerinde tutarsızlıklara sebep olacaktır ki, yeni palazlanmış bir programcı olarak ben, bu duruma düşmemeliyim. Benim kodlarım olağanüstü becerikli ve tutarlı olmak zorundalar, yani değer üretmeliler. "Kahramanım çok yaşa!" nidaları eşliğinde programımda gereken değişiklikleri yapmaya koyuluyorum.
double bıçakDarbesiniHesapla(in double kahramanınEnerjisi) // 
double değerlendir  = kahramanınEnerjisi * 0.1;
double bıçakDarbeliKahraman = bıçakDarbesiniHesapla(kahramanınEnerjisi);
writeln("Hâlâ sakar ama artık canı sıkılmayan kahramanın enerjisi : ", bıçakDarbeliKahraman);
// Hâlâ sakar ama artık canı sıkılmayan kahramanın enerjisi :10000
bıçakDarbesiniHesapla() işlevimizi artık double türünde değer üreten bir işlev haline getirdikten sonra yoluma güvenle devam edebilirim artık...
 in anahtar sözcüğü işlevimize gönderdiğimiz parametrenin yalnızca giriş bilgisi olduğunu bildirir. Yan etki oluşturan önceki işlevimizde ref anahtar kelimesiyle paramateremizi işlev içinde değiştirmek isterken, şimdiki tasarımımızda in anahtar kelimesini kullanarak parametremizin değiştirilmeyeceğini sadece giriş bilgisi olarak kullanılacağını belirtmiş oluyoruz.
İlgi : http://ddili.org/ders/d/islev_parametreleri.html
Bilgi: Bir programda yan etki oluşturmak her zaman istenmeyen ve pek önerilmeyen durumlardan değildir. Tasarladığımız programlardaki işlevlerde yan etki üreten durumlar pek istenmiyor olarak kabul edilebilirken kodlamamızın ilerleyen sahfalarında yapı ve sınıfları kullanırken programımızın bazı bölümlerinin yan etki üretmesini doğallıkla kabul etmek isteriz. Örneğimizin ilerleyen safhalarında sınıfların sarma yeteneklerinden bahsederken bu konuya da değinmeyi umuyorum.
Püf: Bir işlevin yan etki üretip üretmediği, parametresindeki ref işaretinden anlaşılabilir. İşlev parametrelerinizdeki ref işaretlemesi bir anlamda uyarıcı olarak da görülebilir. Dönüş türü void olarak işaretlenmiş bir işlevin parametresinde de ref işareti varsa, işlevinizin yan etki oluşturduğunu düşünebilirsiniz. Bu durumda tasarladığınız işlevi beklentilerinize uygunluğu açısından bir kez daha gözden geçirmek isteyebilirsiniz.
Bu mesaj 6 defa değişti; son değiştiren: mert; zaman: 2012-10-19, 05:52.
Salih Dinçer 2012-10-19, 09:56 #12
Peki in takısı kullanan parametreler ile kullanmayanlar arasında önemli bir farklılık var mı? Tam da bu konuya alt parantez açmam gerekiyor, çünkü yeni kullanmaya başladığımız const ref yerine in ref olayını şurada Ali hocam anlatmıştı: http://ddili.org/forum/thread/970
Son olarak tek başına ref'i bir kenara bırakırsak diğerleri hep kafamı karıştırdığı için kullanmıyorum...
mert 2012-10-19, 10:28 #13
Bir öğrenciyim sadece. Aman diyeyim karışmasın.
Peki in takısı kullanan parametreler ile kullanmayanlar arasında önemli bir farklılık var mı?
in için 'anahtar kelime' demek, ortak bir dil kullanabilmemiz açısından daha uygun sanırım. Şu anda örneğimizde işlevlere kadar ilerleyebilmiş olduğumuzdan, işlevlerde kullanılan in anahtar kelimesinin yazdığımız işlevde nasıl etkili olduğuna değinebildik henüz.
" 'const ref' yerine yeni 'in ref' " başlıklı konuyu inceledim. in anahtar kelimesi kullanmadan da işlevlerimize parametreler geçirebiliriz. Ancak bu şekilde davrandığımızda o parametrenin işlevimizin içinde değişmeyeceği gibi bir garantimiz olamıyor. Başka bir yaklaşım da; eğer sorunumuz sadece parametremizin işlev içinde değişmiyor olduğu garantisini sağlamaksa const, immutable gibi değişmezliği belirli seviyelerde bize sunan anahtar kelimeleri kullanabiliriz. Benim şu aşamada kullandığım in (belirteci) bu örneği oluştururken belirlediğim düzeyin, biraz kodlama alışkanlığımın ve biraz da in anahtar kelimesinin arkasında iş gören farklı yordamların olabileceği önsezisinden kaynaklanmaktaydı ki, senin de referans verdiğin konu başlığında http://ddili.org/forum/thread/970 Ali hocam bu olanağa değinmiş.
Aslında tam aynı anlamda değiller çünkü 'in' ayrıca 'scope' belirtecini de içerir. (scope yukarıdaki bağlantıda geçiyor ama henüz hiçbir derleyici onu desteklemiyor.)
Salih hocam; Sorunu tam olarak kavrayamayıp beklediğin yanıtı verememiş olabilirim. Ama detaylandırmak her zaman mümkün elbet. Bu doğrultuda katkıda bulunmak ister misiniz?
Bu mesaj 2 defa değişti; son değiştiren: mert; zaman: 2012-10-19, 15:37.
acehreli (Moderatör) 2012-10-19, 11:34 #14
Mert, bu yazı çok güzel gelişiyor! En önemli konuları bulup çıkartmışsın. Sonunda makaleler bölümünde mi birleştirelim yoksa basılı kitap olarak mı?
Daha çok bir kişisel tercih ve belki de yazının bu aşamasında göstermek istemedin ama ben atamalı işleçleri yeğliyorum:
kahramanınEnerjisi *= 0.1;
bıçakDarbeliKahraman değişkeninin ismini bıçakDarbeliEnerji diye değiştirmek daha uygun olacak gibi geliyor.
'in' çok yararlı bir anahtar sözcük. (Ben bu gibi anahtar sözcüklere belirteç de diyorum.) Ancak, bazı durumlarda etkisinin olmaması yararına gölge düşürüyor. Örneğin, 'double' ve 'in double' çağıranın açısından aynı anlamdalar çünkü ikisinde de çağıranın değişkeni değiştirilemez. Ama tabii ki 'in double' yeğlenmeli çünkü parametre hakkında daha fazla bilgi taşıyor.
Salih Dinçer 2012-10-19, 11:53 #15
Aynı şekilde ben de dahil çoğumuz öğrenme aşamasındayız ve öğrenmenin hayat boyu sürdüğünü düşünürsek hepimiz öğrenciyiz. Ancak sanırım bu başlık ile sayenizde bir şeyler öğreniyorsak bal gibi de hoca işte...
in için 'anahtar kelime' demek, ortak bir dil kullanabilmemiz açısından daha uygun sanırım.
Sanırım İngilizce'deki "keyword", do, while, for, if dahil her dil olanağının karşılığı oluyor. Bu bağlamda doğru ama bu takıları ayırma taraftarıyım. Belirteç de çok güzel görünüyor çünkü işaretlerden oluşanlarına da işleç diyoruz. Üstelik "abahtar sözcük" iki sözcükten oluştuğu için kullanımı zor görünüyor. Eğer Ali hocam kitapta sıklıkla belirteç kullandıysa bence böyle devam edelim.
Şu an: 2017-11-18, 03:54:49 (UTC -08:00)