June 12, 2011

Çok güzel gerçekten de :)

Özellikle ızgaralı oyunlarda tile based games kullanılabilir gibi geliyor. C++'de mesajlaşma işini state tasarım örüntüsü kullanan pek de güvenli olmadığını bilmediğimiz singleton sınıflar yapıyordu. Yaptığı da bir mesajı numarası bilinen bir oyun nesnesine herhangi bir gecikmeyle göndermek, ya da mesajı mesaj kuyruğunda saklamak.

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

June 11, 2011

std.concurrency modülünün olanaklarını "Eş Zamanlı Programlama" başlığı altında anlatmaya başladım. Bunun koşut işlemlerden farkı, iş parçacıklarının birbirlerine bağlı olmaları ve bir şekilde bilgi alışverişinde bulunuyor olmaları. Zaten aralarında bir bağlantı olmasa kolayca std.parallelism kullanılır...

std.concurrency bunu mesajlaşma ile hallediyor. Aşağıdaki programdaki gezdirici() isimli işlev, bir robotun rasgele yer değiştirmesini sağlıyor. Robot için belirlediği yeni yeri de kendisini başlatmış olan sahip iş parçacığına 'HareketMesajı' türünde gönderiyor.

İlginç işlevler:

  • spawn: iş parçacığı başlatır

  • send: mesaj gönderir

  • receiveOnly: mesaj bekler

Programda pek ilginç bir şey yok: Ana iş parçacığının yaptığı tek şey, robot hareket bilgilerini ekrana yazdırmak:

'A(600) -2,8 -> -1,7
A(600) -1,7 -> 0,8
A(600) 0,8 -> 1,9
B(2000) 6,-10 -> 7,-11
A(600) 1,9 -> 2,10
A(600) 2,10 -> 1,11
A(600) 1,11 -> 2,10
B(2000) 7,-11 (durgun)
A(600) 2,10 -> 3,11
A(600) 3,11 -> 2,10
C(5000) -1,5 -> -2,4
A(600) 2,10 -> 3,9
..
'

Bunun Erdem'den öğrendiğim oyun programlama mantığına tam uymadığını biliyorum: Burada her robotun yavaşlığına bağlı olarak ayrık zamanlarda hareket bilgisi üretiliyor. Yine de herhalde ana iş parçacığı bu bilgileri kendisi toparlayabilir ve oyun işlevlerini kullanarak oyunun ilerlemesini sağlayabilir.

Tabii burada robotların birbirlerinden hiç haberleri yok. Onun da çözümleri bulunur ama şimdilik bu kadar olsun.

import std.stdio;
import std.random;
import std.string;
import std.concurrency;
import core.thread;

struct Yer
{
   int satır;
   int sütun;

   string toString()
   {
       return format("%s,%s", satır, sütun);
   }
}

struct Hareket
{
   Yer nereden;
   Yer nereye;

   string toString()
   {
       return ((nereden == nereye)
               ? format("%s (durgun)", nereden)
               : format("%s -> %s", nereden, nereye));
   }
}

class Robot
{
   string görünüm;
   int yavaşlık;     /* milisaniye */

   this(string görünüm, int yavaşlık)
   {
       this.görünüm = görünüm;
       this.yavaşlık = yavaşlık;
   }

   override string toString()
   {
       return format("%s(%s)", görünüm, yavaşlık);
   }
}

/* 0,0 noktası etrafında rasgele bir yer döndürür */
Yer rasgeleYer()
{
   return Yer(uniform!"[]"(-10, 10), uniform!"[]"(-10, 10));
}

/* Verilen değerin en fazla bir adım ötesinde bir değer döndürür */
int rasgeleAdım(int şimdiki)
{
   return şimdiki + uniform!"[]"(-1, 1);
}

/* Verilen Yer'in komşusu olan bir Yer döndürür; çapraz
* komşusu olabileceği gibi tesadüfen aynı yer de olabilir. */
Yer rasgeleKomşu(Yer yer)
{
   return Yer(rasgeleAdım(yer.satır), rasgeleAdım(yer.sütun));
}

struct GörevBilgisi
{
   int robotNumarası;
   Yer başlangıç;
   int yavaşlık;
}

struct HareketMesajı
{
   int robotNumarası;
   Hareket hareket;
}

void gezdirici(Tid sahip, GörevBilgisi görevBilgisi)
{
   Yer nereden = görevBilgisi.başlangıç;

   while (true) {
       Thread.sleep(dur!"msecs"(görevBilgisi.yavaşlık));

       Yer nereye = rasgeleKomşu(nereden);
       Hareket hareket = Hareket(nereden, nereye);
       nereden = nereye;

       sahip.send(HareketMesajı(görevBilgisi.robotNumarası, hareket));
   }
}

void main()
{
   /* Farklı hızlardaki robotlar */
   Robot[] robotlar = [ new Robot("A",  600),
                        new Robot("B", 2000),
                        new Robot("C", 5000) ];

   /* Her birisi için bir iş parçacığı başlatılıyor */
   foreach (int robotNumarası, robot; robotlar) {
       spawn(&gezdirici, thisTid, GörevBilgisi(robotNumarası, rasgeleYer(), robot.yavaşlık));
   }

   /* Artık hareket bilgilerini işçilerden toplamaya başlayabiliriz */
   while (true) {
       /* Beklenen türün (veya türlerin) gönderilen mesajdaki türlere uyması şarttır. */
       auto mesaj = receiveOnly!HareketMesajı();

       /* Bu robotla ilgili yeni bilgiyi çıkışa yazdırıyoruz */
       writefln("%s %s", robotlar[mesaj.robotNumarası], mesaj.hareket);
   }
}

Ali

Düzeltme: receiveOnly'nin açıklamasını düzelttim. (Eski açıklamada geçen çokuzlu burada bulunmuyor.)

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