Transcript Pertemuan 3

Workshop Project 2
Game PacMan & Algoritma AI yang
Digunakan Musuhnya
Mohammad Zikky, S.ST, M.T
Overview
• Pacman adalah sebuah permainan video arkade yang cukup terkenal. Cara
bermainnya mudah yaitu pemain (pacman) diharuskan memakan makanan
(berbentuk titik-titikkecil) dan sebuah bulatan besar (energizer) sampai habis
di dalam labirin yang berliku-liku.
• Pemain juga harus menghindari 4 ‘hantu’ yang berkeliaran secara random
untuk menangkap pemain. Jika pemain bertemu dengan hantu-hantu tersebut
maka pemain dinyatakan gagal dan harus mengulangi dari awal lagi.
• Pergerakan para hantu ini dipengaruhi oleh kecerdasan buatan atau Artificial
intelligence (AI), dimana para hantu diberi kecerdasan untuk menentukan
langkah dan mengambil keputusan akan bergerak kemana dengan menentukan
rute yang paling pendek (minimum), tujuannya adalah menangkap pemain.
Setiap hantu harus memiliki pemikiran berbeda dan memiliki kemampuan
bekerja sama untuk mengejar pemain, sehingga permainan akan tampak lebih
menarik.
• Persoalan mendekati karakter Pacman ini dapat diselesaikan dengan berbagai
macam cara, salah satunya dengan menggunakan Algoritma greedy/dijkstra
Algoritma Dijkstra
• Djikstra(dinamai menurut penemunya, seorang ilmuwan komputer, Edsger Dijkstra), adalah
sebuah algoritma rakus (greedy algorithm) yang dipakai dalam memecahkan permasalahan jarak
terpendek (shortest path problem) untuk sebuah graf berarah (directed graph) dengan bobotbobot sisi (edge weights) yang bernilai tak-negative (wikipedia)
Detil penjelasan tentang Algoritma Dijkstra klik disini:
http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
Cara Kerja Musuh (Hantu) pada PacMan
• Elemen-elemen algoritma greedy pada permasalahan musuh
Pacman adalah sebagai berikut :
• Himpunan Kandidat : himpunan titik-titik (node) yang merupakan posisi
yang dapat dilalui oleh musuh Pacman
• Himpunan Solusi : himpunan titik-titik yang dipilih adalah rute yang berakhir
pada posisi karakter Pacman.
• Fungsi Seleksi : titik (node) yang dipilih semakin mendekati posisi karakter
Pacman.
• Fungsi Layak : titik yang dipilih dapat dilalui (bukan tembok atau karakter
musuh lain)
• Fungsi Objektif : rute yang dipilih adalah rute yang paling optimum (dalam
hal ini, paling pendek)
Cara Kerja Musuh (Hantu) pada PacMan
• Fungsi seleksi pada persoalan ini dapat dijabarkan sebagai berikut:
• Jika karakter Pacman ada di sebelah kanan karakter musuh saat ini, maka
musuh pindah ke kanan, jika tidak pindah ke kiri
• Jika karakter Pacman ada di sebelah atas karakter musuh saat ini, maka
musuh pindah ke atas, jika tidak pindah ke bawah
• Sebelum karakter musuh dipindahkan, terlebih dahulu dicek
apakah langkah pemindahan tersebut sah (layak), dalam artian
tidak ada dinding / tembok atau karakter musuh lain yang
menghalangi
Kode Semu / Pseudo Code Musuh Pacman
• Digunakan dua tipe variabel bernama “musuh” dan “pacman” yang masing-masing
merepresentasikan karakter musuh dan karakter pacman. Masing-masing tipe tersebut
memiliki atribut X dan Y yang menunjukkan posisi absis dan ordinat tipe tersebut pada labirin
permainan pacman
procedure gerakMusuh(m:musuh,p:pacman)
{
if(p.X() >= m.X and isOK(m.X+1, m.Y)) then
pindahKanan(m)
else if(p.Y()>= m.Y and (isOK(m.X, m.Y+1)) then
pindahAtas(m)
else if(isOK(m.X, m.Y - 1) then
pindahBawah(m)
else if(isOK(m.X-1, Y)) then
pindahKiri(m)
}
Kode Semu / Pseudo Code Musuh Pacman
• Fungsi layak : untuk menentukan apakah di posisi x dan y terdapat dinding atau
karakter musuh lain yang menghalangi
function isOK(x, y:integer)-> boolean
{
if(noDinding(x,y) && noMusuh(x,y))
 true
else
 false
}
• Dengan algoritma di atas, karakter musuh pacman digerakkan hingga mencapai
suatu titik dalam labirin yang merupakan percabangan. Jadi fungsi
gerakkanMusuh di atas akan dipanggil berulang-ulang setiap karakter musuh
sampai di suatu percabangan
Contoh Kasus
• Misal fungsi seleksi gerakkanMusuh diterapkan pada
musuh Pacman yang berwarna oranye (pada
gambar terlihat sebagai karakter yang dilingkari
dengan lingkaran berwarna oranye).
• Posisi karakter musuh oranye berada di sebelah kiri
karakter Pacman yang berwarna kuning (m.X <
p.X), maka karakter musuh oranye seharusnya
bergerak ke kanan, namun ternyata ada dinding
yang menghalangi, maka dilakukan pengecekan lagi
terhadap perbandingan posisi Y dan didapati posisi
karakter musuh oranye berada di sebelah atas
karakter Pacman (m.Y > p.Y) dan tidak ada dinding
maupun karakter musuh lain yang menghalangi di
atasnya, maka karakter musuh oranye dipindahkan
ke atas.
Contoh Kasus
• Sehingga hasil pergerakannya
adalah:
• Diterapkan lagi algoritma greedy untuk kali
kedua, posisi karakter oranye sekarang ada
di sebelah kiri karakter Pacman (m.X < p.X)
dan tidak ada yang menghalangi di sebelah
kanannya
Setelah bergerak ke kanan, algoritma greedy diterapkan lagi dan karakter musuh berada di atas Pacman
(m.Y > p.Y), maka karakter musuh digerakkan ke bawah sampai bertemu dengan karakter Pacman
Sekarang coba jalankan source code berikut kemudian Pahami:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <vector>
class entity {
public:
using namespace std;
char tmp_map[18][32];
char map[18][32] = {
"+#############################+",
"|
|",
"|
|",
"|## ########### ## #########|",
"| |
|",
"| | |### | |
| |",
"| |
| | |### | | | |",
"| | #####| | |
## | |",
"| |
|### |
| |",
"| |##### ###
##
|",
"|
###### ####### ###|",
"|
|",
"|# ### ####
### #######|",
"|
|",
"|
|",
"|
|",
"|
|",
"+#############################+"
};
void ShowMap()
{
for(int i = 0; i < 18; i++) {
printf("%s\n",map[i] );
}
}
void gotoxy( short x, short y )
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE) ;
COORD position = { x, y } ;
}
SetConsoleCursorPosition( hStdout, position ) ;
entity( int x, int y ){
this ->x = x;
this ->y = y;
}
void move_x( int p ){
if( map[y][x+p] == ' ' ) x += p;
}
void move_y( int p ){
if( map[y+p][x] == ' ' ) y += p;
}
void move( int p, int q ){
x += p;
y += q;
}
int get_x(){ return x; }
int get_y(){ return y; }
void draw( char p ){
map[x][y] = p;
gotoxy( x, y ); printf( "%c", p );
}
private:
};
struct walk {
};
int x;
int y;
short walk_count;
short x;
short y;
short back;
Jalankan Source Code (lanjutan)
struct target {
};
short x;
short y;
int i = 0;
while( i < BFSArray.size() ){
vector<target> walk_queue;
vector<walk> BFSArray;
void AddArray( int x, int y, int wc , int back ){
if( tmp_map[y][x] == ' ' || tmp_map[y][x] == '.' ){
tmp_map[y][x] = '#';
walk tmp;
tmp.x = x;
tmp.y = y;
tmp.walk_count = wc;
tmp.back = back;
BFSArray.push_back( tmp );
}
}
void FindPath( int sx, int sy, int x, int y ){
memcpy( tmp_map, map, sizeof(map) );
BFSArray.clear();
walk tmp;
tmp.x = sx;
tmp.y = sy;
tmp.walk_count = 0;
tmp.back = -1;
BFSArray.push_back( tmp );
if( BFSArray[i].x == x && BFSArray[i].y == y ){
walk_queue.clear();
target tmp2;
while( BFSArray[i].walk_count != 0 ){
tmp2.x = BFSArray[i].x;
tmp2.y = BFSArray[i].y;
walk_queue.push_back( tmp2 );
}
}
i++;
}
AddArray(
AddArray(
AddArray(
AddArray(
i = BFSArray[i].back;
break;
BFSArray[i].x+1, BFSArray[i].y, BFSArray[i].walk_count+1, i );
BFSArray[i].x-1, BFSArray[i].y, BFSArray[i].walk_count+1, i );
BFSArray[i].x, BFSArray[i].y+1, BFSArray[i].walk_count+1, i );
BFSArray[i].x, BFSArray[i].y-1, BFSArray[i].walk_count+1, i );
}
BFSArray.clear();
Jalankan Source Code (lanjutan 2)
int main()
{
bool running = true;
int x = 15; // hero x
int y = 16; // hero y
int old_x;
int old_y;
int ex = 1;
int ey = 1;
int pts = 0;
printf("Instruksi:\n1. Panah Kanan Kiri Atas Bawah untuk Pergerakan
Aktor Pacman\n2. Makan Titik yang di produksi musih untuk mendapatkan poin\n3.
Jangan sampai ketangkap musuh\n\n");
printf("H -> Hard (Sulit)\nN -> Normal (Biasa)\nE -> Easy
(Mudah)\n\nMasukkan Level : ");
char diffi;
int speedmod = 3;
cin >> diffi;
if( diffi == 'N' ){
speedmod = 2;
}else if( diffi == 'H' ){
speedmod = 1;
}
system("cls");
ShowMap();
gotoxy( x, y ); cout << "T";
int frame = 0;
FindPath( ex,ey,x,y );
while( running ){
gotoxy( x, y ); cout << " ";
old_x = x;
old_y = y;
if ( GetAsyncKeyState( VK_UP ) ){
if( map[y-1][x] == '.' ){ y--; pts++; } else
if( map[y-1][x] == ' ' ) y--;
}
if ( GetAsyncKeyState( VK_DOWN ) ){
if( map[y+1][x] == '.' ){ y++; pts++; } else
if( map[y+1][x] == ' ' ) y++;
}
if ( GetAsyncKeyState( VK_LEFT ) ){
if( map[y][x-1] == '.' ){ x--; pts++; } else
if( map[y][x-1] == ' ' ) x--;
}
if ( GetAsyncKeyState( VK_RIGHT ) ){
if( map[y][x+1] == '.' ){ x++; pts++; } else
if( map[y][x+1] == ' ' ) x++;
}
Jalankan Source Code (lanjutan 3)
if( old_x != x || old_y != y ){
}
FindPath( ex,ey,x,y );
system("cls");
gotoxy( x,y ); cout << "P";
map[ey][ex] = '.';
gotoxy( ex, ey ); cout << ".";
if( frame%speedmod == 0 && walk_queue.size() != 0 ){
ex = walk_queue.back().x;
ey = walk_queue.back().y;
walk_queue.pop_back();
}
gotoxy( ex, ey ); cout << "M";
if( ex == x && ey == y ){
break;
}
}
gotoxy( 32, 18 );
gotoxy( 32, 1 ); cout << pts;
Sleep( 100 );
frame++;
}
printf("Anda Kalah /n Skor Akhir Anda : %i", pts );
cin.get();
cin.get();
cin.get();
cin.get();
cin.get();
cin.get();
cin.get();
cin.get();
return 0;
Percobaan lebih lanjut
• Pahami masing-masing fungsi dan baris program, kemudian beri
keterangan/comment di setiap baris/pokok besar programnya. Lakukan
denga tanda // (untuk 1 baris) atau /* isi comment */ utuk lebih dari 1
baris.
• Ganti posisi start Musuh PacMan dalam 3 keadaan start yang berbeda
• Jika sudah berhasil, coba gandakan musuh pacman menjadi 4,
sebagimana layaknya permainan PacMan. Sebar posisinya saat start.
Amati pergerakannya dalam mengejar actor/PacMan tersebut.
• Analisa dan jelaskan hasil praktikumnya
• Buat laporan
Referensi
1. Birch, Chad (2010), Understanding Pac-Man Ghost Behaviour
(http://gameinternals.com/post/2072558330/understanding-pac-manghost-behavior)
2. Pittman, jamey (2010), Pac-Man Dossier
(http://home.comcast.net/~jpittman2/pacman/pacmandossier.html)
3. Nugroho Chandra, Timotius (2010), Aplikasi Algoritma Greedy untuk
Pergerakan Musuh pada Pac-Man, Institut Teknologi Bandung, Bandung