Thread overview
Wartune Astro D
Jan 27, 2013
Salih Dinçer
Jan 27, 2013
Salih Dinçer
Jan 28, 2013
Salih Dinçer
January 27, 2013

Merhaba,

Hafta sonu, oynadığım ve bir süredir kafama takılan oyundaki sistemi kodlamaya başladım. Ancak kafamı toparlayabildiğim; şu ocak ayının son haftasının, ilk gününün, ilk saatlerinde bitirebildim...:)

'http://static.r2games.com/newsimg/wartune_g_wt_g_astro2.jpg'

Aşağıdaki kodda D'nin aralıkları dahil bir çok olanağını kullandım ve mutluyum! Muhtemelen oyunda daha farklı bir kodlama yapılmış olmalı. Zaten kader küresi değeri ve türü gibi kavramlara girmedim. Ama oyunu oynamamışlar için kısaca tarif edersek...

Öncelikle rasgele çıkan 1 + 4 küre var. Bunlardan en zor çıkanı ve de en değerli olanı sarı renkli küre. Zaman zaman şansızlık küreleri ile mücadele ederken, işimize yarayan mavi ve mor küreleri toplayıp sarı üzerine sürükleyerek birleştiriyoruz. Böylece sarının değeri artıyor. Aslında Şansızlık hariç tüm kürelerin bir değeri (EXP) ve de türü var. Ama yeşilleri satmak ve elde edilen altın ile şansı arttırmak kısmen mantıklı görünüyor. Çünkü seviye arttıkça her küreyi açma masrafı biner biner (başlangıç 4000 altın) artıyor!

İşte olasılıkları analiz etmeye yarayan ve rakamların ötesine geçen sistem aşağıda. Her şey enum'u yazmak ile başladı ve görünüşe göre çok güzel çalışıyor...:D

/*
* Kader Küresi v1 - 28 Ocak 2013
*
* Legend Online* oyununda yer alan ve
* karakter gelişimini sağlayan sistemden**
* esinlenilmiştir...
*
*   (*): http://lotr.oasgames.com
*  (**): http://wartune.wikia.com/wiki/Astral
*
* Yazan: salihdb@gmail.com
*/
import std.stdio,
      std.random,
      std.range : replicate;

enum Küreler : int { Şansızlık, Yeşil, Mavi, Mor, Sarı }

class Rulet (T) {
 int[T] küreAdeti;
 int adet, seviye = 1;

 public:
   this(uint adet) {
     this.adet = adet;
     temizleKüre();
   }

   bool empty() {
     return !adet;
   }

   void popFront() {
     adet--;
     temizleKüre();
   }

   int[2] front() {

   /* Herhangi bir kürenin, seviyeye göre değerini arttır */

     int sayaç = seviye; // seviye arttıkça şans oranı artabilir!
     do {
       küreAdeti[rasgeleKüre(cast(T)seviye)]++;
     } while(--sayaç);

   /* Küreleri değerlendir ve en yüksek olanını seç */

     int küre = seçKüre(küreAdeti);

   /* Sonraki seviyeyi 0/1 şansına göre belirle */

     scope(exit) {
       int arttırayım_mı = uniform(0, int.max) % 2;
       if(arttırayım_mı) { // seviye sınıra ulaşmadıysa arttır,
         if(seviye < T.max) {
           seviye++;
          } else seviye = T.max;
       } else seviye = 1;  // veya başa dön...
     }
     return [ seviye, küre ];
   }

 private:
   int seçKüre(int[T] olasılıklar) {
     int sonuç;

     with(Küreler) {
       alias olasılıklar O;
       if( !O[Şansızlık] ) {
         if( O[Sarı] > O[Mor] ) sonuç = Sarı;
         else if( O[Mor] > O[Mavi] ) sonuç = Mor;
         else if( O[Mavi] > O[Yeşil] ) sonuç = Mavi;
         else sonuç = Yeşil;
       }
     }
     return sonuç;
   }

   T rasgeleKüre(T sınır = T.max) {
     auto sayı = uniform(0, sınır + 1);
     return cast(Küreler)sayı;
   }

   void temizleKüre() @safe {
     auto xSay = Küreler.max;
     do küreAdeti[xSay] = 0; while(xSay--);
   }
}

void main () {
 auto tıklamaAdeti = 10;

 foreach(r; new Rulet!Küreler(tıklamaAdeti)) {
   foreach(s; replicate("#", r[0])) s.write();
   "\t: ".writeln(cast(Küreler)r[1]);
 }
}/* Çıktısı:
[atelyeweb@sdb Belgeler]$ d.sh kaderküresi.d
#      : Yeşil
#      : Şansızlık
##     : Mavi
#      : Yeşil
#      : Şansızlık
#      : Yeşil
##     : Şansızlık
###    : Mavi
####   : Mor
####   : Sarı
*/

Dip Not: Oyun, ülkemizde ve Portekiz'de Legend Online olarak tanınıyor. Orijinal ismi Wartune ve konu olan kader küreleri hakkında şurada (http://lotr.oasgames.com/legend_online/?a=sq&m=content&id=97) Türkçe bilgi mevcut. İngilizcesi ise burada (http://wartune.r2games.com/guide/view?id=196) (DİKKAT: official site ama Google Plus'dan dolayı JS hatası var, en azından Firefox'da) ve şurada (http://blackrabbit2999.blogspot.com/2012/10/wartune-optimizing-your-astral-guide.html)...:)

Sevgiler, saygılar...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 28, 2013

Ekleme için teşekkürler hocam...

Ben de bunu düzgün nasıl yazarım diye, beyin faaliyeti esnasında bir kaç nöronu harcamak zorunda kaldım. Ama sonra, emekliye düşme mevzusunda da hatıralarımı saklayan nöronlara kızar gibi oldum...:)

Çünkü, eskiden basiti olan 'repeat()' kullanırdık ama ileride 'replicate()' ile anlamı genişletildi diye hatırlıyordum. Sonra, Mert ağabeyin 2009 yılında yazdığı şu düzeltmeyi görünce yanlış hatırlamadığımı fark ettim:

http://ddili.org/forum/post/7798

İşin ilginci neyin emekliye ayrıldığı konusunda sık sık kafa karışıklığı yaşamamız. Elbette derleyici ne diyorsa o ama, sık sık yapılan bu değişikliklerden büyük rahatsızlık duyuyorum! Tamam, kütüphanede hangi nesne deprecated olarak işaretlendiyse kodumuzu düzenleriz de; yine de can sıkıcı işte...

İşin bir başka ilginç yanı da std.string'de başlayan bu işlev, std.array ve oradan (sanırım aynı anda!) std.range'e sıçraması. İşte bütün bunlar kafa karışıklıklarını arttırıyor. Ama aslında sözün özü sitede yer alıyor:

Belki de aralık ile dizi arasındaki karışmayı engellemek için isim değişikliğine gidildi, öyle mi? Sanırım yakında std.string'den bir şey kalmayacak gibi. Yine de tüm rahatsız ediciliğe rağmen bu değişikliğe şahit olmak da güzel. Bir gün yaşlanıp da ömrümüzü devam ettirme fırsatı bulursak gençlere anlatırız; bir dilin gelişim hikayesini... :cool:

Veee hocama bir kaç soru:

Bu uygulamada, elbette tembel olduğu için (yanılıyor muyum?) değerler hazır değil ama sınıfa 'int max() @property' ekleyebilir miydik? Aslında std.algorithm : 'max()' ile ilgili bir şeyler yapmaya çalıştım ama beceremedim. Bu tür değer üreten sınıf ve yapıları belki tembellikten çıkartıp en küçük ve en büyük değerleri döndürebilen yapıya çevirmek mümkün olabilir mi?

Teşekkürler...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 28, 2013

Bir kaç güncelleme (v1.1) yaptım:

  • replicate() yerine repeat() ile seviye gösterildi
  • scope(exit) kümesi popFront() içine alındı (aynı şey!)
  • with(Küreler) yerine with(T) kullanıldı

Sonuncusu da aynı şey ama koşullar içinde kullandığım eleman isimlerine tam otomatik bir çözüm bulabileceğimi zannetmiyorum. O yüzden gereksiz bir şey! Yani enum Küreler { ... } içeriği değişirse kod hata verecektir...

Kodun güncel haline gelince:

/*
* Kader Küresi v1.1 - 28 Ocak 2013
*
* Legend Online* oyununda yer alan ve
* karakter gelişimini sağlayan sistemden**
* esinlenilmiştir...
*
*   (*): http://lotr.oasgames.com
*  (**): http://wartune.wikia.com/wiki/Astral
*
* Yazan: salihdb@gmail.com
* Katkı: acehreli@yahoo.com
*/
import std.stdio,
      std.random,
      std.range : repeat;

enum Küreler : int { Şansızlık, Yeşil, Mavi, Mor, Sarı }

class Rulet (T) {
 int[T] küreAdeti;
 int adet, seviye = 1;

 public:
   this(uint adet) {
     this.adet = adet;
     temizleKüre();
   }

   bool empty() {
     return !adet;
   }

   void popFront() {
     adet--;

   /* Önceki olasılıkları temizle ama dizi elemanlarını bırak */

     temizleKüre();

   /* Sonraki seviyeyi 0/1 şansına göre belirle */

     int arttırayım_mı = uniform(0, int.max) % 2;
     if(arttırayım_mı) { // seviye sınıra ulaşmadıysa arttır,
       if(seviye < T.max) {
         seviye++;
        } else seviye = T.max;
     } else seviye = 1;  // veya başa dön...

   }

   int[2] front() {

   /* Herhangi bir kürenin, seviyeye göre değerini arttır */

     int sayaç = seviye; // seviye arttıkça şans oranı artabilir!
     do {
       küreAdeti[rasgeleKüre(cast(T)seviye)]++;
     } while(--sayaç);

   /* Küreleri değerlendir ve en yüksek olanını seç */

     int küre = seçKüre(küreAdeti);

     return [ seviye, küre ];
   }

 private:
   int seçKüre(int[T] olasılıklar) {
     int sonuç;

     with(T) {
       alias olasılıklar O;
       if( !O[Şansızlık] ) {
         if( O[Sarı] > O[Mor] ) sonuç = Sarı;
         else if( O[Mor] > O[Mavi] ) sonuç = Mor;
         else if( O[Mavi] > O[Yeşil] ) sonuç = Mavi;
         else sonuç = Yeşil;
       }
     }
     return sonuç;
   }

   T rasgeleKüre(T sınır = T.max) {
     auto sayı = uniform(0, sınır + 1);
     return cast(T)sayı;
   }

   void temizleKüre() @safe {
     auto xSay = T.max;
     do küreAdeti[xSay] = 0; while(xSay--);
   }
}

void main () {
 auto tıklamaAdeti = 10;

 foreach(r; new Rulet!Küreler(tıklamaAdeti)) {
   repeat('#', r[0]).write();
   "\t: ".writeln(cast(Küreler)r[1]);
 }
}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

January 27, 2013

Çok güzel! :)

Bir not:

karakterlerini yazdırmak için foreach kullanmak zorunda kalmanın nedeni, olaya "#" dizgisi ile başlamış olman. Eğer '#' karakteri kullansaydın daha kısa yazılabilirdi:

   write('#'.replicate(r[0]))

Ama derleyicinin uyarısına bakılırsa std.range.replicate emekliye ayrılmış. Onun yerine std.range.repeat kullanılmalıymış:

   write('#'.repeat(r[0]));

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]