Cuma, Kasım 27, 2009

Oyunlarda Basit AI(Yapay Zeka) Uygulamaları

İnternette oyun programlama ile ilgili araştırma yaparken bulduğum basit ama faydalı iki AI algoritmasından bahsedeceğim. Bunlar Dikdörtgen Çarpışma(rectangle collision)ve Dolaşan(Roaming) AI türlerinden Kovalama algoritmaları. Eğer ki -ben kod inceleyerek daha iyi anlarım diyorsanız yazının sonuda bu algoritmaları kullanarak Allegroda hazırladığım ufak bir uygulamayı bulabilirsiniz.

1-Dikdörtgen Çarpışma(Rectangle Collision) Algoritması

Olay son derece basit. İki boyutlu düşünecek olursak çarpışma ne demektir. İki farklı nesnenin sağından - solundan veya altından-üstünden acıcıkta olsa iç içe geçmeleri değil midir. Bu mantıktan yola çıkarak nesnelerin etrafında dikdörtgenden bir çerçeve varmış gibi düşünüp ayrı ayrı koordinat eksenindeki 4 noktasını öğrenip bunları bir birleri ile karşılaştırdığımızda sonuca gitmiş oluruz. Aşağıdaki kod uygulamadaki dikdörtgen çarpışma algoritmatsına ait olan kısım.

bool carpismaKontrol(Kahraman *pKahraman, Dusman *pDusman)
{
int dusmanLeft,dusmanRight,dusmanTop,dusmanBottom;
int kahramanLeft,kahramanRight,kahramanTop,kahramanBottom;
bool durum=true;

dusmanLeft = pDusman->getLeft(); // (x)
dusmanRight = pDusman->getRight(); // (x + resim->w)
dusmanTop = pDusman->getTop(); // (y)
dusmanBottom = pDusman->getBottom(); // (y + resim->h)

kahramanLeft = pKahraman->getLeft(); // (x)
kahramanRight = pKahraman->getRight(); // (x + resim->w)
kahramanTop = pKahraman->getTop(); // (y)
kahramanBottom = pKahraman->getBottom(); // (y + resim->h)

if (kahramanLeft>dusmanRight)
durum = false;
else if (kahramanRight<dusmanLeft)
durum = false;
else if (kahramanTop>dusmanBottom)
durum = false;
else if (kahramanBottom<dusmanTop)
durum = false;

return durum;
}




2- Kovalama Algoritması

Oyundaki bir nesnenin başka bir nesneyi takip etmesidir. Buradaki mantık ise kovalayanın X ve Y değerlerinin kovalananın X ve Y sine göre azaltılması veya arttırlmasına dayanır. Aşağıdaki kod benim hazırladığım uygulamadaki kovalama AI sine ait olan kısımdır.

void
Dusman::yakala(Kahraman *pKahraman)
{
int dusmanX = getX();
int dusmanY = getY();

sayac++;
if (sayac % hiz ==0)
{
if (rand() % zekaPuani == 0)
{
if (pKahraman->getX()>dusmanX)
dusmanX++;
else if (pKahraman->getX()<dusmanX)
dusmanX--;

if (pKahraman->getY()>dusmanY)
dusmanY++;
else if (pKahraman->getY()<dusmanY)
dusmanY--;

sayac = 0;
}
}
setXY(dusmanX,dusmanY);
}



Yukarıdaki kodda ilk iki if bloğu (if (sayac % hiz ==0) ve if (rand() % zekaPuani == 0)) olaya biraz rasgelelik katmak içindir. Bir nevi kovalayanın zeka seviyesi veya hızı olarak düşünülebilir.

Ekran Görüntüsü


Öncelikle çizimler için kusura bakmayın aceleye geldi yoksa o kadarda beceriksiz sayılmam :P. Uygulama Code::Blocks IDE si kullanılarak MinGW ile derlenmiştir buradan indirebilirsiniz.

Bir sonraki yazıda netten hazır olarak bulduğum spriteları kullanarak karakterimizin resmini doğrultusuna göre değişecek ve çarpışma anında müzik çalacak hale getirmeyi düşünüyorum.

Pazar, Kasım 22, 2009

C++ ile XML parse etme

Eğer ki bu blog'da bu yazıyı okuyorsanız iki ihtimal var ya bloğumu sürekli takip ediyorsunuz -kendimizi kandırmaya gerek yok bu düşük bir ihtimal :)) yada c++ ile xml de bir şeyler yapma gereği duydunuz ve google sayesinde bu blog ile karşılaştınız. Ben ikinci ihtimal daha olası olduğunu düşündüğüm için XML nedir ne işe yarar gibisinden bilgi vermeyeceğim (ki zaten buda kolayıma geliyor:D) çünkü ne olduğunu biliyorsunuz demektir. Ama yinede XML nedir diye merak ederseniz yeni eğitim sisteminin de temel dayanağı olan araştırmacı, öğrenmeyi bilen öğrenen (öğrenci değil!!!) yetiştirme politikasına hizmet açısından sizi bu adrese yönlendireceğim.

Evet sosyal mesajımızı da verdikten sonra bu laf kalabalığına son verip mevzuya giriş yapalım.

C++ da XML dosyalarını parse etmek için herşeyi bizim yapmamıza gerek yok sağolsun elin adamı bizler için vakti zamanında bir kütüphane yazmış. Bize düşen sadece kütüphanenin fonksiyonlarını doğru bir şekilde kullanmak. Bu kütüphanemizin adı libxml2. Öncelikle bağımlılıkları ile beraber bunu bilgisayarımıza kurup IDE ayarlarımızı yapacağız.

1- Bu adresten libxml2 nin Igor Zlatkovic adlı kişi tarafından windows için derlenmiş en son sürümünü indirelim(Kendisine de teşekkür ederiz). İndirdiğimiz dosyayı ileride bu yolu tekrar kullanacağımızı da göz önünde bulundurarak bir yere unzip edelim. (Ben C:\libxml2 yoluna unzip ettim anlatıma da buna göre devam edeceğim).

2- 1.adımda verdiğim linkten yine windows için derlenmiş iconv kütüphanesinin en son sürümünü indirelim -bu kütüphanenin ne işe yaradığını bende daha önceden bilmiyordum. İnternette kısa bir araştırmadan sonra karakter dönüştürme kütüphanesi olduğunu öğrendim. İleride işimize yarayabilecek bir bilgi ;). Aynı şekilde dosyaları yine bir yere unzip edin. (Ben C:\libiconv yoluna unzip ettim).

3- Şimdi sıra IDE ayarlarını yapmaya geldi. Ben her zamanki gibi Code::Blocks üzerinden anlatacağım. Diğer IDE'ler ile de yaklaşık olarak aynı mantıkla yapılan bir işlem. Codeblocksu açıp Settings menüsünden Compiler and debugger bölümüne giriyoruz. Ve aşağıda belirttiğim yerlere gerekli eklemeleri yapıyoruz.

Linker Settings->Link libraries: C:\libxml2\lib\libxml2.lib
Linker Settings->Link libraries: C:\libiconv\lib\iconv.lib

Search Directories->Compiler: C:\libxml2\include
Search Directories->Compiler: C:\libiconv\include
Search Directories->Linker: C:\libxml2\lib
Search Directories->Linker: C:\libiconv\lib
Search Directories->Resource compiler: C:\libxml2\include
Search Directories->Resource compiler: C:\libiconv\include

4- Kodu yazacağımız .cpp dosyasının yanında bazı dll'lerin bulunması gerekli. Bunları aşağıda belirttim. Biri hariç diğerlerini daha önce indirdiğimiz dosyalarda bulabilirsiniz.
  • libxml2.dll
  • iconv.dll
  • zlib1.dll (Burdan indirebilirsiniz. Tam olarak ne yaptığını bilmemekle beraber sıkıştırma işlemi için gerekli bir dll imiş.)
Kurulum bitti. Şimdi ufak bir program yardımı ile doğru bir şekilde işlemleri yapıp yapmadığımız kontrol edelim. Ben buradaki e-book tan yararlanarak aşağıdaki ufak programı yazdım.

"dosya.xml"
<?xml version="1.0" encoding="utf-8" ?>
<ogrenci>
<bilgi>
<ad>Esat ARSLAN</ad>
<dtarih>27/10/1986</dtarih>
</bilgi>
<bilgi>
<ad>Ali Veli</ad>
<dtarih>01/01/1986</dtarih>
</bilgi>
</ogrenci>



"xmlParse.cpp"
#include <iostream>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

void xmlParse()
{
xmlDocPtr docPtr;
xmlNodePtr rootNodePtr;
xmlNodePtr childNodePtr;


docPtr = xmlParseFile("dosya.xml");
rootNodePtr = xmlDocGetRootElement(docPtr);
rootNodePtr = rootNodePtr->xmlChildrenNode;

while(rootNodePtr != NULL)
{
if ((!xmlStrcmp(rootNodePtr->name,(const xmlChar *) "bilgi")))
{
childNodePtr = rootNodePtr;
childNodePtr = rootNodePtr->xmlChildrenNode;
xmlChar *ad;
while(childNodePtr != NULL)
{

if ((!xmlStrcmp(childNodePtr->name,(const xmlChar *)"ad")))
{
ad = xmlNodeListGetString(docPtr,childNodePtr->xmlChildrenNode,1);
std::cout<<ad<<std::endl;
}
childNodePtr=childNodePtr->next;
}
}

rootNodePtr=rootNodePtr->next;
}

}

int main()
{
xmlParse();
return 0;
}

Cumartesi, Kasım 14, 2009

PHP ile Pascal Üçgeni (Binom açılımı)

PHP yi alttan alan sınıf arkadaşlarımın isteği üzerine yazdım. Biraz çarpık çurpuk oldu idare edin:)). Zaten vaktimin çoğunu binom açılımının formülünü anlamaya çalışmakla geçirdim. Matematik konusunda iyice hamlamışım :(.

<?php
function faktoriyel($sayi)
{
$fak=1;
for ($i = $sayi;$i>=1;$i--)
$fak =$fak * $i;

return $fak;
}

function kombinasyon ($a,$b )
{
return faktoriyel( $a ) / ( faktoriyel( $b ) * faktoriyel( $a - $b ) );
}

function binomHesapla($sayi)
{
for ($i =0 ;$i<$sayi;$i++)
{
$binom .= " ".kombinasyon($sayi,$i);
}
$binom .= " 1";

return $binom;
}

function binomCiz($sayi)
{
echo "<table border=1>";
echo "<tr><td align=center>1</td><tr>";
for ($i =1;$i<= $sayi;$i++)
{
echo "<tr><td align=center>".binomHesapla($i)."</td></tr>";
}
echo "<table>";
}

binomCiz(4);
?>

Perşembe, Kasım 05, 2009

Allegro Örnek Program-2

Allegro örneklerine devam ediyoruz. Bu seferki programımız ileride yapacaklarımız için bir başlangıç olması açısından son derece önem teşkil etmekte. Hemen programdan bahsetmeye başlayalım.

Bazı noktalara değinmek istiyorum önce. Allegro da "set_gfx_mode (GFX_AUTODETECT, 640,480,0,0);" kodu ekranı yatayda 640 dikeyde 480 pixel olacak şekilde böler. Bu sayede çok hassas hareketler yapma şansımız olur. Ancak çok fazla hassaslık delikanlıyı bozar :P deyip ben ekranı 20*20 lik karelere böldüm. Programı çalıştırdığınızda ekranda göreceğiniz kare bu sayede her hareketinde 20 pixellik ilerler.

24x32 lik bir dizi oluşturdum ve bunu harita olarak kullandım. Buradaki 24 ve 32 rasgele seçilmiş rakamlar değildir dikkatinizi çekerim. 480 ve 640 ın 20 ye bölümünden elde edilen sonuçlardır bunlar.

Dikkatiniz çekmek istediğim diğer noktada diziyi oluştururken 32x24 değilde 24x32 şeklinde oluşturmuş olmam. 640 yatay ekseni 480 ise dikey ekseni temsil eder. Yani 640 sutun 480 satır şeklinde aklımızda tutabiliriz bunu. Bu yüzden diziyi 24 satır 32 sutun olacak şekilde oluşturdum.

#include <allegro.h>

BITMAP *buffer;
int x=10,y=10;
int tutX=10,tutY=10;

int harita[24][32]={{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};

void haritaCiz()
{
for (int i =0;i<24;i++)
{
for (int k = 0; k<32;k++)
{
if (harita[i][k] == 0)
rectfill(buffer,k*20,i*20,(k+1)*20,(i+1)*20,makecol(255,0,0));
if (harita[i][k] == 1)
rectfill(buffer,k*20,i*20,(k+1)*20,(i+1)*20,makecol(0,0,255));
}
}
}
void hareketEt()
{
tutX = x;
tutY = y;
clear_keybuf();

if (key[KEY_UP])
{
if ((y*20)>0 && harita[y-1][x]!=0)
y--;
}
else if(key[KEY_DOWN])
{
if ((y*20)<460 && harita[y+1][x]!=0)
y++;
}
else if (key[KEY_LEFT])
{
if ((x*20)>0 && harita[y][x-1]!=0)
x--;
}
else if(key[KEY_RIGHT])
{
if ((x*20)<620 && harita[y][x+1]!=0)
x++;
}

acquire_screen();
rectfill(buffer,tutX*20,tutY*20,(tutX+1)*20,(tutY+1)*20,makecol(0,0,255));
rectfill(buffer,x*20,y*20,(x+1)*20,(y+1)*20,makecol(0,255,0));
draw_sprite(screen,buffer,0,0);
release_screen();
rest(100);
}

int main()
{
allegro_init();
install_keyboard();
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT,640,480,0,0);

buffer = create_bitmap(640,480);

haritaCiz();

while(!key[KEY_ESC])
{
hareketEt();
}
return 0;
}

END_OF_MAIN();

Çarşamba, Kasım 04, 2009

Dong dong dong!!! Zil çaldı haydi çocuklar sınıfa.


Üniversite de 4.yılımdayım, diğer bir ifade ile yolun sonundayım. Her son yeni bir başlangıçtır denir lakin yinede her son insanda bir burukluk hissi yaratıyor.Her neyse konuya dönecek olursak son sınıf olmanın gerektirdiklerinden biri olan staj eğitimime başladım. Okul deneyimi dersinde hocamız her hafta staj ile ilgili belirleyeceğimiz bir konu hakkında yazı yazıp bloğumuz da paylaşmamızı istedi. Bu haftaki konuyu tekbir başlık altında toplamak zor olsada genel olarak "İlk Gözlemlerimiz" diyebilirim. (Resim staj okulum olan Ali Hikmet Paşa İlköğretim Okulunun karlı bir havada çekilmiş güzel bir fotoğrafıdır.)

Pavlovun Köpekleri!!!

Stajda ilk farkettiğim tenefüs zili oldu. Öğrencilerle beraber derste hocaya dinliyordum birazcıkta sıkılmıştım :)). Aniden zil çaldı ve içimde garip bir sevinç belirdi. Evet tam 6 yıl aradan sonra tenefüse çıkmanın verdiği rahatlığı tekrardan hatırlamıştım. 6 yıldır sönmüş durumda olan bu duygu staj okulumdaki ilk tenefüs zili ile beraber tekrar canlandı ki aklıma ilk gelende Pavlov abimizin köpeklerinin zile karşı verdiği tepki oldu. Staj hocama çaktırmadan bir süre kendime güldüm:)).

Bu Yeni Nesil Çok Fena :)

Tenefüs den sonra dersi staj arkadaşımla beraber biz anlatmaya başladık. 4.sınıf öğrencilerine bilgisayarın temel donanım bileşenlerini anlatacaktık.Artık tribünden sahaya inmiştim. Sahada olmayı daha çok sevdim çünkü dersi anlatmak dinlemekten daha kolay gelmişti. Kontrolün bende olması açıkcası hoşuma gitmişti. Karşımda da ortalamanın üstünde bir öğrenci grubu olunca dersi anlatmak çok daha zevkli hale gelmişti. Gerçekten öğrenciler zehir gibiydiler bizden çok daha bilgili olacakları kesin lakin bunun yanında yaramazlardı da. Dersi kaynatma potansiyelleri çok yüksekti. Bu yüzden dersi anlatırken mümkün olduğunca konudan sapmamaya çalıştım. Bazı şeyler için biraz daha tecrübeye ihtiyaç var o da zamanla olur inşallah.

Birileri Bir şeyler Yapmalı

Okul iki ayrı binadan oluşmakta. Yaklaşık olarak 2300 öğrenci varmış. Bir hayli yüksek bir rakam. Ama gelin görün ki okulun 3 laboratuarından sadece 1 tanesindeki bilgisayarlar çalışabilir durumda. Bir tanesinde sadece öğretmen bilgisayarı çalışmakta (bizde dersi bu laboratuar da anlattık). Diğerinden laboratuar dan henüz haberim yok. Bizim dersi anlattığımız laboratuar projeksiyon ile duvara öğretmen bilgisayarının görüntüsü veriliyor komiktir ki görüntünün üç te biri tavana yansımakta bu yüzden ekrandakiler tam olarak görülemiyor. En azından önümüzdeki haftalarda bununla ilgili bir şeyler yapabilirim.

İlk hafta böyle geçti. Bakalım önümüzdeki haftalar neler getirecek...