Forum: SDL RSS
Tuş Önbellekleme Algoritması
Key Buffer Stack
Sayfa:  1  2  sonraki 
Avatar
Salih Dinçer #1
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Tuş Önbellekleme Algoritması
Merhaba,

"Textbox" niteliğinde bir nesne düşünün, örneğin:
class MetinKutusu { ... }
Buna öyle nitelikli üyeler verelim ki ekranda etkin olduğu zaman (üzerine tıklanıp fare imleçi yanıp söndüğünde), klavyenin basılan her tuşunu wchar[] metin; dizisinde depolasın. Tabi basılan tuşları yakalama, kodunu varsayılan klavye düzenine göre UTF harfle eşleştirme, imleçin yanıp sönmesi ve harflerin sırayla metin kutusu sınırları içerisinde görünmesi, alt satıra kayması gibi görsel nitelikli işlemlerin halihazırda olduğunu varsayıyoruz...

İşimiz kolay görünüyor...:)

Peki standart, olması gereken üye değişkenleri aşağıdaki gibiyse, sizce başka nelere ihtiyaç var? Örneğin bir kaç kB. geçmişi tutan ve baştaki elemandan eksilerek azalan bir önbellekleme yığınına (buffer stack) duyabiliriz sanki...
size_t kimlik_id;
static kilitlenen_lockId;  // etkin olan
uint soldan_x, yukardan_y;
uint en_w, boy_h;
wchar[] metin;
Sanırım bu kadar basit değil!

Çünkü klavyemiz, bilgisayarımızın fare tuşları gibi basılıp bırakılana kadar (herhangi bir süre) tekrar yapmadan beklemez. O yüzden akıllıca çalışan bir zamanlayıcı ve önbellek yığınına ihtiyaç var. Belli bir sürede (type rate and delay) karakter tekrarı olduğu için, yığının başından (FIFO) ve zamanlayıcının denetiminde klavye karakterleri nesneye yazılmalı.

Meğer çatı yazmak ne zormuş! O yüzden hala mütevazi bir aşamadayım (sdlMİNİ) ve belki bir gün eksiksiz GUI çatısı meydana getirebiliriz. Henüz bu konuda bir çözüm bulamadım...:(

Küçük bir deneme yaptım da başlangıç fena değil ama yardıma ihtiyacım var...
import sdlmini2, std.stdio;
 
struct BoşKutu {
  size_t kimlik;
  bool etkin_Mi;
  int x, y, boy;
  static int en = 170;
  clr renk;
  
  this(int solAlttanX, int solAlttanY) {
    this.x = solAlttanX;
    this.y = solAlttanY;
    this.renk = clr.red;
    this.boy = 140;
  }
  
  void durumuEvir() {
    if(etkin_Mi) {
      etkin_Mi = false;
      renk = clr.red;
    } else {
      etkin_Mi = true;
      renk = clr.gray;
    }
  }
 
  bool üstünde_Mi(int mouseX, int mouseY) {
    int en = this.x + this.en;
    int boy = this.y - this.boy;
    
    return (this.x < mouseX && this.y > mouseY &&
                en > mouseX &&    boy < mouseY);
  }
}
 
void main() {
    BoşKutu[3] kutular;
 
    with( new scene(600, 200, "Etkin Kutu Denemesi", clr.white) ) {
      
      // 3 ayrı kutumuz yan yana kurulur...  
   
      foreach(int i, ref kutu; kutular) {
        int ötele = (25 + kutu.en) * i;
        kutu = BoşKutu(20 + ötele, h - 20);
        kutu.kimlik = 100 + i;
      }
 
      do {
 
        SDL_Clear();
 
        foreach(i, ref kutu; kutular) {
 
          /* sırayla tüm kutular, fare imleç ile
           * etkileşip etkileşmediği denetlenir:
           */
              
          if(sonBasılanDüğme == SDL_BUTTON_LEFT
             && kutu.üstünde_Mi(xMouse, yMouse)
             && !birNesneyeKilitlendi) {
             
            birNesneyeKilitlendi = true// sdl2mini.scene üyesi
           
          /* etkin olan kutular ekrana yazılır...
           * DİKKAT: Bu yöntemde birden fazla kutu etkin!
           */
          
            kutu.durumuEvir();
            kutu.kimlik.write(". kutu etkin");
            if(!kutu.etkin_Mi) writeln(" değil!");
            else writeln("...");
          }
          
          /* Henüz kutular ekrana yansıtılmadan evvel
           * GPU belleğine son durumları yazılır...
           */
           
          rectangle(kutu.x, kutu.y,
                    kutu.x + kutu.en,
                    kutu.y - kutu.boy, kutu.renk);
        }
 
        SDL_Flip(scr);
 
      } while( checkEvents() );
    }
    SDL_Quit();
} /* sdlmini2.scene'deki yardımcı işlevler:
  void rectangle(int x0, int y0, 
                 int x1, int y1, clr c=clr.white) {
    line(x0, y0, x1, y0, c);
    line(x1, y0, x1, y1, c);
    line(x1, y1, x0, y1, c);
    line(x0, y1, x0, y0, c);
  }
  
  bool checkEvents() {
    bool continueLoop = true;
    SDL_PollEvent(&event);
 
    if(!keyEventControl() ||
       !mouseEventControl())
    {
      continueLoop = false;
    }
 
    return continueLoop;
  }
//*/
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Çünkü klavyemiz, bilgisayarımızın fare tuşları gibi basılıp bırakılana kadar (herhangi bir süre) tekrar yapmadan beklemez.

Klavyenin basılıp bırakıldığını farede olduğu gibi anlayamıyor muyuz? Ön belleğe yalnızca tuş bırakıldığında yazsa?

Ali
Avatar
Salih Dinçer #3
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Evet, tıpkı "mouse" gibi "keyboard" da UP ve DOWN olayları tanımlanmış:
  enum : ubyte {
    SDL_KEYDOWN = 2,            /* Keys pressed */
    SDL_KEYUP,                  /* Keys released */
    SDL_MOUSEMOTION,            /* Mouse moved */
    SDL_MOUSEBUTTONDOWN,        /* Mouse button pressed */
    SDL_MOUSEBUTTONUP           /* Mouse button released */
  }
Ancak yenilenme (repeat) olayı ve sıklığı (type rate) olayı bozuyor. Ben şu an, bu cümleyi yazarken, kısa aralıklar ile tuşu basıp çekiyorum ya; ammaaaaaaaaaaa <--burada olduğu gibi uzun basarsak sanki otomatik bas bırak olmuş gibi oluyor. SDL'de ise sanırım bunu algılamıyor daha doğrusu algılama işini geliştiriciye bırakıyor; örn. karakterleri sayabilir...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #4
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Merhaba,

Sabah kalktığımda aklımda şöyle bir fikir vardı...:)
"sdl2mini.d içinde":
  auto blinkingTicks(uint bits) {
    // it's recommended to bits > 7
    auto now = SDL_GetTicks();
         now &= 1 << bits;
    return cast(bool)now;
  }
// sahne döngüsü >>
      do {
 
        SDL_Clear();
        // Yaklaşık saniyede 1 yanıp söner (sahneye gelir/gider)
        if(blinkingTicks(9)) circle(30, 20, 10, clr.red);
 
  :  :  :
Burada mantık şu:

SDL'nin basit bir sayaçtan öte ve uint türünde (yeni sürümde ulong oldu) bir işlevi var. Bu sayısal değerin herhangi bir bit'ini true/false olarak öğrenirsem farklı ölçülerde frameRate elde edebilirim. Sonra bunu, klavyeden basılan herhangi bir tuşu, yığına örneklemede (rate pushing) kullanabilirim.

Nasıl fikir?
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Olur ama tam hassas olmaz herhalde. Onun yerine, şuKadarZamanGeçti_mi(1234) gibi bir çağrı da olabilir.

Ali
Avatar
Salih Dinçer #6
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hocam çok düşündüm, olmuyor ama denemedim! Çünkü n'olcağını tahmin edebiliyorum...:)

Hassaslık o kadar önemlli değil, daha ziyade sahnedeki grafik işlemlerini etkileyecek CPU kaynağını ziyan etmemeli. O yüzden olabildiğince basit şekilde ve harici sayaçı (SDL_GetTicks)'i kullandım. Olmamasına gelince; aşağıdaki kare dalgadan hemen tahmin edebilirsiniz:

[Resim: http://www.tamsat.org.tr/tr/wp-content/uploads/2010/04/KareDalgaOrnegi.jpg]

Kısaca maksadımız, numune (örnekleme) almak. Tıpkı deprem dayanıklılık testi yapanların binanın bütün bir katı yerine bir duvarından küçük bir numune alması gibi. Yukarıdaki bana ait olmayan fotoğraftaki gibi katlar (periods) bizim blinkingTicks() işlevinin görüntüsüdür...

Eğe aşağıdaki gibi bir durumu değişen yığın yapmazsak işler karışır gibime geliyor:
struct Stack {
  wchar[] data;
  int index;
  bool status; // true => push to stack
 
  this() {
    this.data.length = 64;
    this.status = true;
  }
 
  void push() {
    auto period = blinkingTicks(8);
    
    if(period && status) {            // 1 AND 1 =>
 
      data[++i] = cast(wchar)event.key.keysym.sym; // UtfConvert() use may be needed...
      status = false;
 
    } else if(!period && !status) {   // 0 AND 0 =>
 
       status = true;
 
    }
 
  }
  :  :  :
}
Kodu denemedim ama çalışır gibi duruyor. Çünü T0 anında preiod ve status'ün 1 olduğunu varsayarsak 1 adet harf alınır. Sonra status, false'a çekildiği artık push yapmaz; ta ki periyot bitip tekrar true dönene kadar. Zaten o zamana kadar status tekrar true yapılmış (else if) yapılmış oluyor.

Denemek lazım, sürprizlere açık...:)

Sevgiler, saygılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #7
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hasta hasta halimle ancak 12 saatte yapabildim... :'(

Oldu galiba, bir test eder misiniz?
module bufferstack;
 
import std.format;
import std.stdio;
import std.string;
 
class BufferStack(T) {
  struct Index {
    int pop, push;
  }
 
  Index index;
  T[] data;
  
  this(size_t length) {
    this.data.length = length;
  }
 
  bool empty() const @property
  {
    // Başlangıçra 0. eleman kullanılmıyor!
    return index.pop == index.push;
  }
 
  auto size() @property {
    return cast(int)data.length - 1;
  }
 
  void popFront() @property {
    if( index.pop < this.size() ) index.pop++;
    else index.pop = 0;
  }
  
  T pop() @property
  {
    popFront();
    
    return data[index.pop];
  }
 
  T front() @property
  {
    return data[index.pop];
  }
 
  void push(T value) @property
  {
    if( index.push < this.size() ) index.push++;
    else index.push = 0;
 
    data[index.push] = value;
  }
 
  override
  string toString() @property
  {
    string result = "\tPOP\tPUSH\n";
    result ~= format("INDEX:\t%s\t%s\n", index.pop, index.push);
    result ~= format("STACK: %s\n", data);
    result ~= format("SIZE OF %s / ", index.push > 0 ?
                   data.length - index.push :
                   data.length);
    result ~= format("%s", data.length);
    return result;
  }
 
}
 
void main() {
  enum {
    TEKRAR_SAYISI = 10,
    POP1 = 3,
    POP2 = 5,
 
  }
  auto stack = new BufferStack!dchar(64);
  string key; 
 
  foreach(tekrar; 1..TEKRAR_SAYISI + 1) {
    stack.writeln;
 
    key = readln().chomp();
    foreach(dchar k; key) {
      stack.push(k);
    }
 
    if(tekrar == POP1 || tekrar == POP2) {
      "POP STACK:".write;
      foreach(s; stack) s.write;
      writeln;
    }
  }
}
C:\DMD>bufferstack
        POP     PUSH
INDEX:  0       0
STACK: ￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿
SIZE OF 64 / 64
111111111111111111
        POP     PUSH
INDEX:  0       18
STACK: ￿111111111111111111￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿
SIZE OF 46 / 64
22222222222222222222222222222
        POP     PUSH
INDEX:  0       47
STACK: ￿11111111111111111122222222222222222222222222222￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿￿
SIZE OF 17 / 64
3333333
POP STACK:￿11111111111111111122222222222222222222222222222333333
        POP     PUSH
INDEX:  54      54
STACK: ￿111111111111111111222222222222222222222222222223333333￿￿￿￿￿￿￿￿￿
SIZE OF 10 / 64
444444444444
        POP     PUSH
INDEX:  54      2
STACK: 4441111111111111111222222222222222222222222222223333333444444444
SIZE OF 62 / 64
55555555555555
POP STACK:34444444444445555555555555
        POP     PUSH
INDEX:  16      16
STACK: 4445555555555555511222222222222222222222222222223333333444444444
SIZE OF 48 / 64

Kırımızı ile işaretlediğim bölüme bakılırsa olmamış galiba. Zaten sorunu empty() içinde dile getirmiştim. Ama sonrada işler rayına girip düzeleceğini zannettim. Ama öyle, düzeliyor; en azından kafamda...:)

Sanırım foreach() aralıkta(range) gezinirken önce empty()'e uğruyor ve onay alırsa devam ediyor. Sonra front()'a uğrayıp güncel index'deki veriyi çekiyor. En son popFront() ile index arttırılıyor. Oysa popFront() daha önce sonra front() olması gerekiyor. Sanırım aralıklarda çalıştıramayacağım...:(

Yatmalıyım, başım çatlıyor ve her dakika hapşırıyorum...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Kırımızı ile işaretlediğim bölüme bakılırsa olmamış galiba.

Ben bu programı denedim ve aynı seninkine benzer sonuçlar aldım. Kırmızılarda ne sorun var?

Ali
Avatar
Salih Dinçer #9
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Başlangıçta index'ler 0'dan başladığı için ve dizilerin 0. elemanı olduğundan hiç bir zaman düzelmeyen (aynı zamanda artmayan) bir kayma meydana geliyor. Bunu 2. döngünün toString() çıktısında görebiliyoruz.

Bunu düzeltmenin bir yolu var; o da index'leri -1'den başlatmak. Ama foreach() içinde aralık özelliklerini kullandığımız zaman döngü şu sırayla çalıştığından Range Overflow hatası alıyoruz:
  • empty() => false ise döngüye devam...
  • front() => index değerine göre veriyi döndür
  • popFront() ile index değerini güncelle

Bu sorunu aşmanın bir yolu da aralık kullanmamak. Yani bir while döngüsü içinde, pekala pop() vasıtasıyla veri istenilen şekilde çekilebiliyor. Ama yine index'ler -1'den başlamak zorunda çünkü pop()'un ilk hamlesi index.pop'u arttırmak olacak. Fakat hem aralık hem de geleneksel yöntemler ile erişmek istersek ne yapabiliriz?

Cevabı şu düzeltmede buldum:
  void popFront(){}        // foreach() içinde, aralıklarda
  T front(){return pop();} // kullanabilmek içindir...
  
  T pop() @property
  {
    if( index.pop < this.size() ) index.pop++;
    else index.pop = 0;
    
    return data[index.pop];
  }
Burada tek yaptığım popFront() aralık olanağını foreach() içinde hata vermeyecek şekilde @disable yapmak. Tabi dil olanakları etkinsizleştirince hata aldığımız için boş şekilde tanımlamaktan başka yol bulamadım. Zaten çok önemli değil çünkü çalışıyor...:)

Özetle, özelleştirilmiş bu yığın uygulamasında 2 dizin (index) değeri olduğu için farklı muamele gerekiyor.
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2013-05-07, 13:50.
acehreli (Moderatör) #10
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
front() her çağrıldığında eleman kaybedilmesi yanlış olmuş. front() her zaman için en baştaki elemanı vermeli ve istediğimiz kadar çağrılabilmeli. Eleman yalnızca popFront() çağrıldığında kaybedilmeli.

Ali
Avatar
Salih Dinçer #11
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ali hocam aralık kuralını bozduğum için haklısınız ama o kurallar çalışma sistemini etkilediğinden buna mecburdum...

Bu yapıda çift index var. Yani okuma ve yazma kafaları birbirinden bağımsız. Ayrıca yazma kafası her zaman önde olmak zorunda. Eğer okuma kafası öne geçerse bu sorun düzelir.

Ama...

Bu seferde henüz veri yazılmamış bir yeri veya eskisini (daha önce okuduğunu) göreceği için işler karışır. Zaten aralık (range) gibi kullanmaktan çok foreach() ile pratik bir şekilde kullanabilmek için bu yöntemi uyguladım. Sonuç: Çalışıyor...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #12
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
yazma kafası her zaman önde olmak zorunda.

Tamam. Bir biçimde denetlenebilir herhalde.

Zaten aralık (range) gibi kullanmaktan çok foreach() ile pratik bir şekilde kullanabilmek için bu yöntemi uyguladım. Sonuç: Çalışıyor...:)

Çalıştığına sevindim ama foreach de aralık olarak kullandığına göre "aralık gibi kullanmaktan çok" sözünde bir tutarsızlık var. Örneğin, garip bir davranış olsa da, foreach'in içindeyken front()'u çağırsam işler yine karışır helhalde.

Ama önemli olan işine yaramış olması. :)

Ali
Avatar
Salih Dinçer #13
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
foreach'in içindeyken front()'u çağırsam işler yine karışır helhalde.

Karışmaması lazım çünkü pop() gibi çalışıyor. Yani amacım top() gibi çalışması değil. Sanırım bu durumda tek döngüde 2 eleman birden çekilmiş olur:
import sdb.stacks;
 
void main() {
  int i;
  auto stack = new BufferStack!int(10);
       stack.push(1);
       stack.push(2);
 
  foreach(a; stack) {
    auto b = stack.front();
    assert(a != b);
    i++;
  }
  assert(i == 1);
}
Yukarıdaki kod gerçek bir aralık ile kullanıldığında her iki satırda da hata almalıydık. Çünkü a ve b aynı elemanları gösterecekti ve döngü 2 defa çalışması gerekecekti. N'apalım, bu sınıfın başına "non-range algorithm" yazarız...:)

Sevgiler, saygılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2013-05-08, 12:22.
Değişiklik nedeni: Koda b değişkeni eklendi...
acehreli (Moderatör) #14
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4396 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Karışmaması lazım çünkü pop() gibi çalışıyor.

Karışıklı da o işte! :) Ben baştaki elemana eriştiğimi sanıyorum ama bir yandan eleman kaybediyorum.

Sanırım bu durumda tek döngüde 2 eleman birden çekilmiş olur:

Evet ve o yüzden de kafa karıştırıcı bir durum olmuş.

bu sınıfın başına "non-range algorithm" yazarız...:)

Ne yazık ki o gibi çözümler pek etkin olmuyorlar; hele türün arayüzü pek bir InputRange gibi de olunca. Örneğin, herhalde bu tür isInputRange!R denetiminde true oluşturur ama bu gerçeğe güvenen algoritmalar doğru çalışmayabilirler. (front()'un yan etkisini bilemeyecekleri için.)

Ali
Avatar
Salih Dinçer #15
Üye Ock 2012 tarihinden beri · 1881 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Haklısın hocam bu olaya bir çözüm geliyor...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Sayfa:  1  2  sonraki 
Forum: SDL RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-05-27, 12:25:06 (UTC -07:00)