1. T.C.
ÇANAKKALE 18 MART ÜNİVERSİTESİ
MÜHENDİSLİK – MİMARLIK FAKÜLTESİ
YAPAY ZEKÂ VE UZMAN SİSTEMLERİ DERSİNİN
PİZZA PROJESİ
BİLGİSAYAR MÜHENDİSLİĞİ
.../.../2010
Proje Danışmanı:
Yrd. Doç. Dr. Cengiz TOĞAY
1
2. ÇANAKKALE
LISANS PIZZA PROJESININ SONUÇ FORMU
Mehmet Ethem SULAN ve Nurullah ERGÜL tarafından Yrd. Doç. Dr. Cengiz
TOĞAY yönetiminde hazırlanan “PIZZA PROJESİ” başlıklı uygulama tarafımızdan
okunmuş, kapsamı ve niteliği açısından bir lisans uygulaması olarak kabul edilmiştir.
………………………………...……
Yönetici
………………………………...…… …………………………………..
Jüri Üyesi Jüri Üyesi
2
3. Sıra No : ……….
Tez Savunma Tarihi : ..... / ….. / ………
………………………………...……
Müdür
Mühendislik – Mimarlık Fakültesi
ÖZET
PİZZA PROJESİ
MEHMET ETHEM SULAN ve NURULLAH ERGÜL
Çanakkale Onsekiz Mart Üniversitesi
3
4. Mühendislik – Mimarlık Fakültesi
Yapay Zekâ ve Uzman Sistemleri Dersi Pizza Projesi
Danışman: Yrd. Doç. Dr. Cengiz TOĞAY
…/…/2010
Problem olarak elimizde birkaç çeşit malzeme ve başlangıç miktarları var.
Bizden bu malzemeleri kullanarak herbirinden kaçar tane menü üretirsek en karlı
durumu bulurum sorusuna cevap bulmaktır.
Biraz açıklayacak olursak bir pizzacı elindeki malzeme ve menülere göre en karlı
olacağı ürün adedini öğrenmek istiyor. Böylece garsonlar günün en iyi ürününü
sorduklarında ben size x ürününü öneriyorum diyebilecekler.
Bizden istenen menü ve malzeme listelerini ve kalan malzemelerin toplam fiyatını
göz önüne alıp hangi üründen kaç adet üretilmeli sorusuna cevap bulmamızdır.
Kısıtlar
1. Arama algoritmalarından birini kullanmalısınız ve raporunuzda hangi neden
kullandığınızı yazmalısınız.
2. Recursive bir algoritma ile çözülecek.
4
5. İÇİNDEKİLER
PROJE ONAY SAYFASI ……………………………………... ii
ÖZET ………………………………………………………………………. iii
BÖLÜM 1-Pizza projesi Hazırlanışı ………………………..………….... 6
1.1 Kullanılan araçlar ……………………………………………... 6
1.2 Kullanılan Sınıflar ve Metodlar ……………… ……………... 6
1.3 Pizza Projesinin Çalışması ……… …………………………... 20
1.4 Pizza Projesi Sınıf Diyagramı ………………………………... 22
BÖLÜM 2- Kullanılan Algoritmalar ……………………………………... 22
2.1 Backtracking Algoritması ……………………………………………... 22
2.2 Benzetimli Tavlama Algoritmas………………………………………… 23
5
6. BÖLÜM 3 – Sonuçlar …………………………………………………….. 24
Şekiller ……………………………………………………………………... 25
BÖLÜM 1: PİZZA PROJESİ HAZIRLANIŞI
1.1 Kullanılan Araçlar
Pizza projesinde bir rekürsif fonksiyon kullandık. Kullandığımız rekürsif fonksiyon
pizza üretimini yapıyor ve pizza üretilip üretilmeyeceğini kontrol ediyor. Projede
kullandığımız programlama dili Java ve ide ise Eclipse dir. Eclipse ile umlet plugini
kullanarak sınıf diagramlarını çıkardık.
1.2 Kullanılan Sınıflar ve Metodlar
Pizza Projesinde kullandığımız sucuklu, mantarlı, vejeteryanlı ve acılı vejeteryan
sınıfları aynı paket içerisindeki Abstract sınıfından türetilmiştir. Bu sınıflarda bir
pizza üretmek için kullanılacak malzemeler ve malzeme miktarları yer alıyor. Pizza
sınıfında ise menuUret(), durumlariKontrolEt(), pizzaYap() , malzemeYetiyormu()
ve pizzayaGeriEkle() metodları yeralıyor. pizzaYap() metodu çağrıldığında pizza
oluşturuluyor ve pizzada kullanılan malzeme miktarları toplam malzeme
6
7. miktarlarından düşürülüyor. malzemeYetiyormu() metodu üretilmek istenen pizza
için kullanılacak malzeme miktarlarını toplam malzeme miktarlarıyla karşılaştırarak
pizzanın oluşturulup oluşturulamayacağının cevabını true ya da false olarak geri
döndürür. pizzayaGeriEkle() metodu eğer rekürsif fonksiyon içerisinde malzeme
bittiğinde ve tam olarak bütün olası pizza üretimleri tamamlanmadığında en son
hangi pizza üretildiyse o pizza da kullanılan malzeme miktarlarını toplam malzeme
miktarlarına geri ekliyor. Sonra bir üst node(soyut olarak) çıkıp diğer durumlar test
ediliyor.
Malzeme sınıfı her bir malzeme için malzemeyle ilgili bilgileri tutuyor. Malzeme
sınıfında miktarDusur() ve miktarEkle() void tipli metodlardır. pizzaYap() metodu
ve pizzaGeriEkle() metodları çağrıldığında her bir malzeme için o malzemenin
pizzada kullanılan malzeme miktarı kadar toplam malzemeye ekliyor ya da toplam
malzeme miktarından çıkarılıyor.
MalzemeListesi sınıfı ise bütün malzemeler bu sınıfta oluşturulan Malzeme sınıfı
tipindeki bir bağlı liste içeriyor.
Proje oluşturduğumuz rekürsif menuUret() metodu ise Test sınıfının içinde void
tipli olarak oluşturduk. Parametre olarak MalzemeListesi tipinde bir parametre alır.
Örneğin Vejeteryan menüsü oluşturabilmek için sogandan 350 gr, mantardan 275
gr, biberden 200 gr ve acidan 50 gr malzeme kullanılır.Vejeteryan sınıfının içeriği
aşağıdaki gibidir. Bütün menüler Pizza abstract sınıfını extends ediyor.
this.ml Pizza sınıfnfa tanımlanan ml dir. protected MalzemeListesi ml = null;
Hepsinde ortak kullanılıyor.
public class Vejeteryan extends Pizza
{
public Vejeteryan(MalzemeListesi ml)
{
7
8. this.ml = ml;
//Vejeteryanli icin kullanilan malzeme miktarlari
gerekliMalzeme.put("Sogan", 350);
gerekliMalzeme.put("Mantar", 275);
gerekliMalzeme.put("Biber", 200);
gerekliMalzeme.put("Aci", 50);
satisFiyati = 50;
}
}
menuUret() metoduyla recursive çağırımı başlatıyoruz. Vejeteryan için gerekli
malzemeler kullanılmadan önce gidip tüm malzemeleri kontrol ediyor. Acaba gerekli
olan bu miktarlar menvcut mu? Bunu malzemeYetiyormu() metoduyla kontrol
ediyoruz. Bu metoddan dönen değer true ise pizzaYap() metodunu çağırıyor.
PizzaYap() metodu içinde tekrar malzemeYetiyormu() metoduyla malzemelerin yetip
yetmeyeceğinin kontrolunu yapıyor. Eğer malzeme yetiyorsa o zaman malzeme
oluşturup kullanılan malzeme mişktari miktarDusur() metoduyla toplam malzemeden
dusuruyor. menuUret() recursive metodun içinde de eğer pizzaUret() metodundan
dönen değer true ise hangi pizzadan menü üretilmişse o menü değerini 1 artırıyor.
Sonra durumlariKontrolEt() metoduna MalzemeListesi tipinde bir nesne ve o anda
uretilen melzeme(yukarda verilen miktarlar Vejeteryan) hangisi ise bir nesne uretip
onu metodu parametre olarak veriyoruz.
durumlariKontrolEt(MalzemeListesi,MenuCesidi) metodun içinde
toplamSatis=vejeteryanToplam*50+sucukluToplam*100+mantarliToplam*90+aciliV
ejeteryanToplam*75; ile oluşturulan menuden satış fiyatını elde ediyor. Vejeteryan
menünün bir adetin fiyatı 50, sucuklunun 100, mantarlarının 90 ve acili vejeteryanın
8
9. da 75 dir. Vejeteryandan kaç adet oluşturulmuşsa adey sayısı*birim fiyatı ve diğerleri
de aynı şekilde toplanarak toplam malzemelerden toplam satış fşyatını buluyor. Bu
fiyatlar sınıfların içinde verilmiş. Vejeteryan.java açarsanız bir adetin satış fiyatı 50
olarak verilmiş. toplamKarimiz =toplamSatis-p.kalanMalzeme(); toplam karı da
toplam satış fiyatından kalan malzemelerin fiyatı yani çöpe giden malzemeler
eklenilerek hesaplanıyor. Malzeme ismi ve fiyatını tutan map: protected Map<String,
Integer> gerekliMalzeme=new HashMap<String, Integer>();
public double kalanMalzeme(){
kalanMalzeme=0;
Iterator it=gerekliMalzeme.keySet().iterator();
while (it.hasNext())
{
Object gecerlimalzeme = it.next();
int miktar=gerekliMalzeme.get(gecerlimalzeme);
String isim=gecerlimalzeme.toString();
Malzeme m = ml.getMalzeme(isim);
kalanMalzeme += (m.getMiktar() / 1000.0) * m.getFiyat();
}
return kalanMalzeme;
}
En karli durumları aşağıdaki gibi birbiriyle karşılaştırıyor ki sonuçta en karlı olan
durumu bulabilsin. Başlangıçta en karlı durumu sıfır alıyor.
if(enKarliDurum<toplamKarimiz){
9
10. enKarliDurum=toplamKarimiz;
vejeteryanSon=vejeteryanToplam;
sucukSon=sucukluToplam;
mantarSon=mantarliToplam;
aciSon=aciliVejeteryanToplam;
zarar=p.kalanMalzeme();
satisFiyati=toplamSatis;
//Bulunan en karli durumu yazdiriyorum.Arama sonunda elimizde en karli durum
olur.Ilk durum sifir atadim
//sonraki durumlarla karsilastir daha karli ise o ana kadar ki en karli durumu
bulmus oluyoruz.
ml.sonDurumuYazdir();
System.out.println("Toplam satis--> "+satisFiyati+"nZarar:
"+zarar);
System.out.println("V:"+vejeteryanSon+"tS:"+sucukSon+"tM:"+mantarSon
+"tAc:"+aciSon+"tAdetle yapilan kar->"+enKarliDurum+"n");
}
Kar durum gelirse onun verilerini yedekliyor.Yani o ana kadar en karlı durumu kaçar
tane menu üreterek bulduğunu yazıyor consola. Arama sonunda en karlı durumu yazar.Son
çıktı en karlı olandır.
Sonra menuUret(ml); kendi kendini tekrar çağırıyor. Bu şekilde soyut olarak bir
ağaç oluşturuyor ve vejeteryandan sonrada diğer durumları test ediyor.Herhangi bir
menü oluşturacak kadar malzeme kalmadıysa pizzaGeriEkle() metodunu çağırıp bir
10
11. üst noda mantıksal olarak çıktıktan sonra bir adet menüyü eksiltiyor.Aşağıdaki kodda
vejeteryantoplamını azaltıyor.
v1.pizzayaGeriEkle();
//Bir ust node cikarken yukarda 3 taneden 2 ye dusuru yani 1 azaltir sayiyi.
if(vejeteryanToplam>0){
vejeteryanToplam-=1;
}
}
Recursive metodun içeriği aşağıdaki gibidir.
public void menuUret(MalzemeListesi ml) {
Vejeteryan v1=new Vejeteryan(ml);
if(v1.malzemeYetiyormu()){
if(v1.pizzaYap()){
vejeteryanToplam+=1;
}
durumlariKontrolEt(ml, v1);
menuUret(ml);
v1.pizzayaGeriEkle();
if(vejeteryanToplam>0){
vejeteryanToplam-=1;
}
11
13. if(mantarliToplam>0){
mantarliToplam-=1;
}
}
AciliVejeteryan ac1=new AciliVejeteryan(ml);
if(ac1.malzemeYetiyormu()){
if(ac1.pizzaYap()){
aciliVejeteryanToplam+=1;
}
durumlariKontrolEt(ml, ac1);
menuUret(ml);
ac1.pizzayaGeriEkle();
if(aciliVejeteryanToplam>0){
aciliVejeteryanToplam-=1;
}
}
}
Recursive yani menuUret() metodun sonu.
Test sınıfı içerisindeki mainde başlangıç değerleri oluşturulmuş ve MalzemeListesi
sınıfının içinde malzeme tipinde bir ArrayList e addMalzeme(Malzeme tipinde başlangıç
malzemeleri) metodu ile eklenmiş ve recursive olan menuUret() metodunu çağırıyor.
//Baslangic degerleri,fiyat ve malzeme isimleri
13
14. Malzeme sogan = new Malzeme("Sogan", 3000, 5);
Malzeme peynir = new Malzeme("Peynir", 1000, 15);
Malzeme mantar = new Malzeme("Mantar", 2000, 20);
Malzeme biber = new Malzeme("Biber", 3000, 10);
Malzeme aci = new Malzeme("Aci", 1000, 25);
Malzeme sucuk = new Malzeme("Sucuk", 1000, 30);
MalzemeListesi ml = new MalzemeListesi();
ml.addMalzeme( sogan );
ml.addMalzeme( peynir );
ml.addMalzeme( mantar );
ml.addMalzeme( biber );
ml.addMalzeme( aci );
ml.addMalzeme( sucuk );
//Recursive olarak cagri yapiyoruz.Sanki node olusturuyormus gibi
MenuUretRecursive menuNes=new MenuUretRecursive();
//Baslangic durumda toplam malzemeleri basar.Eger // kaldirisaniz
menuNes.menuUret(ml);
addMalzeme() metodu parametre olarak verilen malzeme nesnesini listeye
ekliyor.
public void addMalzeme(Malzeme m)
{
14
15. liste.add(m);
}
MalzemeListesi sınınfı ayrıca getMalzeme() ve sonDurumuYazdir() isminde iki
tane metoda sahip.Isimlerinden anlaşıldığı gibi biri gelen isimde mesela sogan
malzemesi varsa geri dönderirken diğeri o anda yani kullanımdan sonra kalian
malzeme miktarlarını consola yazıyor.
//Gelen malzeme ismi listede varsa donderirir.
public Malzeme getMalzeme(String isim)
{
for (Malzeme m : liste) {
if( m.getIsim().equals(isim) )
return m;
}
return null;
}
//O anda kalan malzemeleri yazar.
public void sonDurumuYazdir()
{
for (Malzeme m : liste) {
System.out.println( m.getIsim() + ": " + m.getMiktar() );
}
15
16. }
Malzeme sınıfı malzeme ismi, fiyatı ve miktarı isminde değişkenlere sahip.Yani bu sınıftan
üretilen bir nesne bu değerleri kendi içerisinde barındırıyor. Sınıftaki bu değişkenlere get()
ve set() metodularıyla erişilir.Ayrıca miktarDusur() ve miktarEkle() isminde iki tane de
metodu var. Bu metodlar melzeme kulalnıldığında miktar azaltıp veya geri eklendiğinde
tekrar ekliyorlar. Sınıfı yazacak olursak
public class Malzeme
{
//Mlazemeismi,miktari ve fiyati.Mesela sogan,100 gr ve 1 ytl kilosu
private String isim;
private int miktar=0;
private int fiyat;
public Malzeme(String isim, int miktar, int fiyat) {
this.isim=isim;
this.miktar=miktar;
this.fiyat=fiyat;
}
public String getIsim()
{
return isim;
}
16
17. public int getMiktar() {
return miktar;
}
public int getFiyat() {
return fiyat;
}
//Tek tek miktarlari dusuruyor.Mesela sogan kullanilan miktar kadar toplamdan
dusuluyor.
public void miktarDusur(int miktar)
{
this.miktar -=miktar;
}
public void miktarEkle(int miktar){
this.miktar+=miktar;
}
}
Son olarak menülerde ortak kullanılan abstarct Pizza sınıfını eklemeyi yeterli buluyorum.
Rapora bakıldığında az-çok bilgimiz olsun diye kodları da eklemeyi tercih ettim. Direkt
yazıyla açıklamaktansa kodlara da yer vermek daha iyi olacağını düşündüm.
public class Malzeme
17
18. {
//Mlazemeismi,miktari ve fiyati.Mesela sogan,100 gr ve 1 ytl kilosu
private String isim;
private int miktar=0;
private int fiyat;
public Malzeme(String isim, int miktar, int fiyat) {
this.isim=isim;
this.miktar=miktar;
this.fiyat=fiyat;
}
public String getIsim()
{
return isim;
}
public int getMiktar() {
return miktar;
}
public int getFiyat() {
18
19. return fiyat;
}
//Tek tek miktarlari dusuruyor.Mesela sogan kullanilan miktar kadar toplamdan
dusuluyor.
public void miktarDusur(int miktar)
{
this.miktar -=miktar;
}
public void miktarEkle(int miktar){
this.miktar+=miktar;
}
}
19
20. 1.3 Pizza Projesinin Çalışması
Değerlendirme metodumuz(evulation function) kalan malzemelerden yeni bir
menü oluşturulup oluşturulamayacağını test ediyor. Eğer menü oluşturulabiliyorsa
true değerini dönderir. Yetecek kadar malzeme kalmamışsa false dönderir.
Temel olarak var olan malzemelerden bir menü oluşturulmaya başlanıyor. Önce
herhangi bir pizzadan başlayıp(biz vejeteryandan başlattık) o pizzadan malzemeler
yetene kadar üretilmeye devam edilir. Sonra rekürsif metod içerisinde diğer
pizzaların üretilip üretilmeyeceğinin kontrol yapılır. Eğer pizza üretilebiliyorsa
pizzalar üretilir. Rekürsif fonksiyon tarafından yürütülen bu işlemler kalan
malzemelerden başka hiçbir pizza üretilmeyene kadar devam eder. Eğer hiçbir pizza
üretilmiyorsa mantıksal olarak düşündüğümüz ağaç yapısının yaprak düğümüne
gelmiş bulunuyoruz demektir.
Burada üretilen pizza adetlerinin sayısı ve kalan malzeme miktarları göz önüne
alınarak karşılaştırmalar yapılır(durumlariKontrolEt()) ve en iyi sonuçlar
değişkenler tutulur. Bundan sonra bu işlem yukarı düğüme çıkılarak(son dugumde
harcanan malzeme geri eklenerek bir ust dugume cikiyor) yeni pizza oluşturulur. Bu
şekilde en alttan başlayıp en üste gidene kadar ağac bu şekilde dolaşılır. En sonunda
en iyi sonuç bulunur ve çıktı olarak ekrana yazdırılır.
20
22. 1.4 Pizza projesi Sınıf Diyagramı
Şekil 1.2 Sınıf diyagramı (Umlet plugini kullandık)
BÖLÜM 2 : KULLANILAN ALGORİTMALAR
2.1 Backtracking Algoritması
Projemizde kullandığımız algoritmalardan birisi de Backtracking algoritmasıdır. Bu
algoritmayı işleyiş olarak projemizde kullandık ve bu algoritmaya göre mantıksal olarak
düşündüğümüz ağaç yapısında düğümler arasında dolaşırken en alt düğüme geldiğimizde
daha fazla pizza üretilip üretilemeyeceğinin kontrol yapıyoruz ve eğer pizza üretemiyorsak
22
23. backtracking algoritmasında gibi tekrar üst düğüme çıkıyoruz ve tekrar alt düğümlere inerek
kontrol yapıyoruz. Bu işlem artık bütün pizza oluşturma ihtimalleri bitene kadar devam eder.
2.2 Benzetimli Tavlama Algoritması (Simulated Annealing Search)
Projemizde kullandığımız yapı temel olarak benzetimli tavlama algoritmasına çok yakın.
Kısaca açıklayacak olursak;
“YEREL ARAMA ALGORITMALARI
Birçok optimizasyonprobleminde amaca giden yol önemsizdir, amaç durumu
çözümün kendisidir.
Durum uzayı= Tam düzeneklerin oluşturduğu küme (nasıl oluşturuldukları
önemli değil)
Düzenekleri sağlayan kısıtlar bulunur, Örnek, n-vezir problemi
Bu durumlarda, yerel arama algoritmaları (local search algorithms) kullanılabilir.
Bir adet güncel durum saklanır, bunun üzerinde oynamalar yapılır ve ilerleme
sağlanmaya çalışılır.
BENZETIMLITAVLAMAARAMASI(SIMULATEDANNEALINGSEARCH)
Yaklaşım: Arada bir “kötü” beklenmeyen hareketler yaparak yerel maksimuma
takılmaktan kurtulmak, (azalan sıklıkta)”
Aynı benzetimli tavlama algoritmasındaki gibi arada farklı değerler üreterek yerel
maksimum değerinden kurtulmaya çalışıyoruz. Bu şekilde en iyi pizza üretimi sonucunu
bulmaya çalışıyoruz. Benzetimli tavlama algoritması bir bilgili arama algoritmadır. Bizim
projemizde bilgi olarak malzeme miktarları pizzaları oluşturmak için ne kadar malzeme
gerektiği bilgisi kullanılır. Bu bilgilere yeni pizza üretip üretemeyeceğinin kontrolü yapılır.
Bu bilgilere göre yeni değerler üretilerek en iyi sonuç bulunur.
23
24. SONUÇLAR
Sonuç olarak en iyi pizza üretimi ağaç yapısı oluşturulmadan rekürsif metod
içerisinde gerçekleştirilerek en iyi pizza adetlerinin sonucu bulunmaya çalışılır.
En iyi pizza sonuçlarını en sonunda yazdırarak proje amacına ulaştırılmış oldu.
Bu sayede herhangi bir pizza dükkânı açmak isteyen birisi kendisi için en karlı
olacak pizza üretimlerinin sayısını gün içerisinde herhangi bir zamanda
bulabilecek. Buna göre pizzaların satılmasında müşterilere tavsiye ve
yönlendirmelerde bulunarak en karlı kazanca erişebilecek. Bu uygulamada temel
amaç recursive metodların tam anlamıyla kavrayabilmektir.Çünkü bazı
problemler tabiatı gereği recursive metodlarla çözülmek zorunda kalıyoruz.
Uygulamada tüm durumları kontrol edebilmek için mutlaka recursive metod
kullanmak zorundayız. forlarla tüm durumları kontrol edemeyiz.
24
25. Şekil 3.1 Programın çıktısı
Şekiller
Şekil 1.1 Ağaç Yapısı . ………………………21
Şekil 1.2 Sınıf Diyagramı ……….. ……………..22
Şekil 3.1 Programın Çıktısı ………………………..25
Kodları: http://www.ethemsulan.com/projects linkinde bulabilirsiniz.
25