Wednesday 26 July 2017

Pemodelan dan Simulasi Menuju Istana

Pada entri ini, saya akan berbagi sebuah simulasi.

Simulasi ini tentang sebuah karakter yang berusaha menuju istana, atau tempat harta karun, ya terserah. Jadi karakter ada di seberang sungai, dan istananya ada di daratan seberang. Untuk menuju istana, karakter harus menuju tombol pembuka jembatan, kemudian setelah jembatan terbuka, karakter menyeberang dan harus menuju ke tempat pengambilan kunci istana agar bisa masuk. Tetapi tidak semudah itu, karakter harus menghindari para penjaga, bila perlu harus melawannya agar selamat. Untuk yang ingin melihat video simulasinya dan penjelasan lebih lengkap silakan menuju ke link di bawah ini:


Berikut ini adalah tampilannya:


Simulasi yang saya buat termasuk simulasi yang sangat sederhana. Saya membuatnya menggunakan openGL dengan bahasa C++. Ada beberapa hal yang perlu dikembangkan dalam simulasi ini agar lebih baik, contohnya:
1. Pengejaran oleh penjaga seharusnya berdasarkan range,
2. Prioritas menuju target dapat membuat karakter sewaktu-waktu terjebak dalam pohon-pohon yang posisinya acak. Sehingga perlu aturan khusus agar karakter semakin pintar.

Jika kalian ingin mengembangkan simulasi ini, silakan kalian gunakan kode di bawah ini:

Kode di bawah ini hanya variabel, konstanta, dan fungsi yang berkaitan dengan simulasi ini saja. Jika belum mengerti cara untuk mengimplementasikannya, silakan gabungkan dengan kode dasar implementasi pada link di bawah ini:


const int n2 = 102;
const int n = 100;
const int river_width=13; //axa harus ganjil
const int castle_width=5; //axa harus ganjil
const int sight_range=3; //axa harus ganjil
const double forest_density=0.1; //kerapatan pohon
const int guard_number=11; //jumlah penjaga
const int pembobot=1; //pembobot arah
const int pembobot_hindar=n; //pembobot arah
const double win_rate=0.9; //rate player menang fight

int init=1, in_area=0, gameover=0; //status
int s[n2][n2], s1[n2][n2]; //terrain
int targetpos[4][2];
int playerpos[2], guardpos[guard_number][2]; //posisi
int direction[sight_range][sight_range]; //bobot arah
int guardlive[guard_number]; //guardian yang hidup
int on_bridge[guard_number+1]; //status ada di atas jembatan
int to_target=0;

//warna
GLfloat nothing[3] = {0.5, 0.3, 0.0};
GLfloat river[3] = {0.2, 0.4, 0.8};
GLfloat bridge[3] = {0.3, 0.3, 0.3};
GLfloat tree[3] = {0.0, 0.8, 0.0};
GLfloat castle[3] = {0.8, 0.8, 0.0};
GLfloat player[3] = {1.0, 1.0, 1.0};
GLfloat guard[3] = {1.0, 0.0, 0.0};
GLfloat button[3] = {0.8, 0.8, 0.0};

void resetdir(void){ //pemberian bobot
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            direction[i][j]=pembobot;
        }
    }
}

void measuredir(int a[], int b[]){ //pemberian bobot
    resetdir();
    if(a[0]>b[0]){ //jika sasaran di utara
        direction[2][0]+=pembobot;
        direction[2][1]+=pembobot;
        direction[2][2]+=pembobot;
    }
    else if(a[0]<b[0]){ //jika sasaran di selatan
        direction[0][0]+=pembobot;
        direction[0][1]+=pembobot;
        direction[0][2]+=pembobot;
    }

    if(a[1]>b[1]){ //jika sasaran di timur
        direction[0][2]+=pembobot;
        direction[1][2]+=pembobot;
        direction[2][2]+=pembobot;
    }
    else if(a[1]<b[1]){ //jika sasaran di barat
        direction[0][0]+=pembobot;
        direction[1][0]+=pembobot;
        direction[2][0]+=pembobot;
    }

    //jika ada penjaga lebih baik menghindar
    if(s[b[0]-1][b[1]+1]==6||s[b[0]][b[1]+1]==6||s[b[0]+1][b[1]+1]==6){
        direction[0][0]+=pembobot_hindar;
        direction[1][0]+=pembobot_hindar;
        direction[2][0]+=pembobot_hindar;
    }
    if(s[b[0]-1][b[1]-1]==6||s[b[0]][b[1]-1]==6||s[b[0]+1][b[1]-1]==6){
        direction[0][2]+=pembobot_hindar;
        direction[1][2]+=pembobot_hindar;
        direction[2][2]+=pembobot_hindar;
    }
    if(s[b[0]+1][b[1]-1]==6||s[b[0]+1][b[1]]==6||s[b[0]+1][b[1]+1]==6){
        direction[0][0]+=pembobot_hindar;
        direction[0][1]+=pembobot_hindar;
        direction[0][2]+=pembobot_hindar;
    }
    if(s[b[0]-1][b[1]-1]==6||s[b[0]-1][b[1]]==6||s[b[0]-1][b[1]+1]==6){
        direction[2][0]+=pembobot_hindar;
        direction[2][1]+=pembobot_hindar;
        direction[2][2]+=pembobot_hindar;
    }
}

void userDraw() {
    glBegin(GL_POINTS);
    if(init==1){
        //initialization
        srand(time(NULL));
       
        targetpos[0][0]=n*90/100;
        targetpos[0][1]=n*10/100;
        s[targetpos[0][0]][targetpos[0][1]]=7;
        targetpos[1][0]=n/2;
        targetpos[1][1]=(int)(1/(1+exp(-1*((double)targetpos[1][0]-n/2)))*n*0.5+(n/4));
        targetpos[2][0]=n*10/100;
        targetpos[2][1]=n*90/100;
        s[targetpos[2][0]][targetpos[2][1]]=7;
        targetpos[3][0]=n*90/100;
        targetpos[3][1]=n*90/100;

        for (int i = 1; i < n2-1; i++) {
            int sigmoid_y = (int)(1/(1+exp(-1*((double)i-n/2)))*n*0.5+(n/4));
            //pembuatan sungai
            for(int j = (river_width/2+1) - river_width; j < (river_width/2+1); j++){
                for(int k = (river_width/2+1) - river_width ; k < (river_width/2+1); k++){
                    if(s[i-j][sigmoid_y-k] != 2){
                        s[i-j][sigmoid_y-k] = 1;
                    }
                }
            }
        }

        //pembuatan castle
        for(int i = (castle_width/2+1) - castle_width; i < (castle_width/2+1); i++){
            for(int j = (castle_width/2+1) - castle_width ; j < (castle_width/2+1); j++){
                s[targetpos[3][0]-i][targetpos[3][1]-j] = 4;
            }
        }

        //pembuatan player
        playerpos[0]=n*10/100;
        playerpos[1]=n*10/100;
        s[playerpos[0]][playerpos[1]]=5;

        //pembuatan pohon
        for (int i = 1; i < n2-1; i++) {
            for (int j = 1; j < n2-1; j++) {
                if(s[i][j]!=1&&s[i][j]!=2&&s[i][j]!=4&&s[i][j]!=5&&s[i][j]!=7){
                    if((double)rand()/RAND_MAX<forest_density){
                        s[i][j]=3;
                    }
                }
            }
        }

        //pembuatan penjaga
        for(int i=0; i<guard_number; i++){
            guardlive[i]=1;
            do{
                guardpos[i][0]=(rand() % n)+1;
                guardpos[i][1]=(rand() % n)+1;
            }while(s[guardpos[i][0]][guardpos[i][1]]==1||s[guardpos[i][0]][guardpos[i][1]]==2||s[guardpos[i][0]][guardpos[i][1]]==3||s[guardpos[i][0]][guardpos[i][1]]==4||s[guardpos[i][0]][guardpos[i][1]]==5||s[guardpos[i][0]][guardpos[i][1]]==7||guardpos[i][1]<=(int)(1/(1+exp(-1*((double)guardpos[i][0]-n/2)))*n*0.5+(n/4)));
            s[guardpos[i][0]][guardpos[i][1]]=6;
        }
        init=0;
    }
    else{
        //update state
        if(gameover==0){
            //perjalanan player
            measuredir(targetpos[to_target],playerpos);
            int tempdir[2]={0,0};
            double tempscore=0.0;
            for(int i=-1;i<2;i++){
                for(int j=-1;j<2;j++){
                    if(s[playerpos[0]+i][playerpos[1]+j] == 0 || s[playerpos[0]+i][playerpos[1]+j] == 2 || s[playerpos[0]+i][playerpos[1]+j] == 4 || s[playerpos[0]+i][playerpos[1]+j] == 7 && (playerpos[0]+i > 0 && playerpos[0]+i <= n && playerpos[1]+j > 0 && playerpos[1]+j <= n)){
                        double r = (double)rand()/RAND_MAX*direction[i+1][j+1];
                        if(tempscore < r){
                            tempscore = r;
                            tempdir[0] = i;
                            tempdir[1] = j;
                        }
                    }
                }
            }
            if(on_bridge[0]==1){
                s[playerpos[0]][playerpos[1]]=2;
            }
            else{
                s[playerpos[0]][playerpos[1]]=0;
            }
            playerpos[0]+=tempdir[0];
            playerpos[1]+=tempdir[1];
            if(s[playerpos[0]][playerpos[1]]==4){
                gameover=1;
                printf("GAME OVER!\n");
            }
            else{
                //pengecekan bidak di posisi target
                if(playerpos[0]==targetpos[to_target][0]&&playerpos[1]==targetpos[to_target][1]){
                    if(to_target==0){
                        for(int j = (river_width/2+1) - river_width; j < (river_width/2+1); j++){
                            for(int k = (river_width/2+1) - river_width ; k < (river_width/2+1); k++){
                                s[targetpos[1][0]-j][targetpos[1][1]-k] = 2;
                            }
                        }
                    }
                    to_target++;
                }

                //pengecekan bidak di atas jembatan
                if(s[playerpos[0]][playerpos[1]]==2){
                    on_bridge[0]=1;
                }
                else{
                    on_bridge[0]=0;
                }

                s[playerpos[0]][playerpos[1]]=5;

                //pengecekan bidak berada di wilayah istana
                if(playerpos[1]>(int)(1/(1+exp(-1*((double)playerpos[0]-n/2)))*n*0.5+(n/4))){
                    if(in_area==0){
                        printf("WARNING! INTRUDER!\n",playerpos[0],playerpos[1],(int)(1/(1+exp(-1*((double)playerpos[0]-n/2)))*n*0.5+(n/4)));
                    }
                    in_area=1;
                }
            }

            //perjalanan penjaga
            if(in_area==0){
                //saat player belum melewati jembatan
                for(int a=0;a<guard_number;a++){
                    if(guardlive[a]==1){
                        int r;
                        int r2;
                        do{
                            r=(int)rand()%3-1;
                            r2=(int)rand()%3-1;
                        }while(s[guardpos[a][0]+r][guardpos[a][1]+r2]==1||s[guardpos[a][0]+r][guardpos[a][1]+r2]==3||s[guardpos[a][0]+r][guardpos[a][1]+r2]==4||s[guardpos[a][0]+r][guardpos[a][1]+r2]==6||s[guardpos[a][0]+r][guardpos[a][1]+r2]==7||guardpos[a][0]+r<1||guardpos[a][0]+r>n||guardpos[a][1]+r2<1||guardpos[a][1]+r2>n);
                       
                        if(on_bridge[a+1]==1){
                            s[guardpos[a][0]][guardpos[a][1]]=2;
                        }
                        else{
                            s[guardpos[a][0]][guardpos[a][1]]=0;
                        }
                        guardpos[a][0]+=r;
                        guardpos[a][1]+=r2;
                        if(s[guardpos[a][0]][guardpos[a][1]]==5){
                            if((double)rand()/RAND_MAX<win_rate){
                                guardlive[a]=0;
                                s[guardpos[a][0]][guardpos[a][1]]=5;
                                printf("WIN FIGHT!\n"); //player membunuh penjaga
                            }
                            else{
                                s[guardpos[a][0]][guardpos[a][1]]=6;
                                gameover=1;
                                printf("GAME OVER!\n"); //player ditangkap
                            }
                        }
                        else{
                            if(s[guardpos[a][0]][guardpos[a][1]]==2){
                                on_bridge[a+1]=1;
                            }
                            else{
                                on_bridge[a+1]=0;
                            }
                            s[guardpos[a][0]][guardpos[a][1]]=6;
                        }
                    }
                }
            }else{
                //saat player sudah melewati jembatan
                for(int a=0;a<guard_number;a++){
                    if(guardlive[a]==1){
                        int find=0;
                        measuredir(playerpos, guardpos[a]);
                        int tempdir[2]={0,0};
                        double tempscore=0.0;
                        for(int i=-1;i<2;i++){
                            for(int j=-1;j<2;j++){
                                if(s[guardpos[a][0]+i][guardpos[a][1]+j]==0||s[guardpos[a][0]+i][guardpos[a][1]+j]==2||s[guardpos[a][0]+i][guardpos[a][1]+j]==5&&(guardpos[a][0]+i>0&&guardpos[a][0]+i<=n&&guardpos[a][1]+j>0&&guardpos[a][1]+j<=n)){
                                    double r=(double)rand()/RAND_MAX*direction[i+1][j+1];
                                    if(s[guardpos[a][0]+i][guardpos[a][1]+j]==5){
                                        tempscore=r;
                                        tempdir[0]=i;
                                        tempdir[1]=j;
                                        find=1;
                                        break;
                                    }
                                    else if(tempscore<r){
                                        tempscore=r;
                                        tempdir[0]=i;
                                        tempdir[1]=j;
                                    }
                                }
                            }
                            if(find==1){
                                break;
                            }
                        }
                        if(on_bridge[a+1]==1){
                            s[guardpos[a][0]][guardpos[a][1]]=2;
                        }
                        else{
                            s[guardpos[a][0]][guardpos[a][1]]=0;
                        }
                        guardpos[a][0]+=tempdir[0];
                        guardpos[a][1]+=tempdir[1];
                        if(s[guardpos[a][0]][guardpos[a][1]]==5){
                            if((double)rand()/RAND_MAX<win_rate){
                                guardlive[a]=0;
                                s[guardpos[a][0]][guardpos[a][1]]=5;
                                printf("WIN FIGHT!\n"); //player membunuh penjaga
                            }
                            else{
                                s[guardpos[a][0]][guardpos[a][1]]=6;
                                gameover=1;
                                printf("GAME OVER!\n"); //player ditangkap
                            }
                        }
                        else{
                            if(s[guardpos[a][0]][guardpos[a][1]]==2){
                                on_bridge[a+1]=1;
                            }
                            else{
                                on_bridge[a+1]=0;
                            }
                            s[guardpos[a][0]][guardpos[a][1]]=6;
                        }
                    }
                }
            }
        }

    }
   
    //draw
    for (int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++){
            if(s[i][j] == 1){
                glColor3fv(river);
            }else if(s[i][j] == 2){
                glColor3fv(bridge);
            }else if(s[i][j] == 3){
                glColor3fv(tree);
            }else if(s[i][j] == 4){
                glColor3fv(castle);
            }else if(s[i][j] == 5){
                glColor3fv(player);
            }else if(s[i][j] == 6){
                glColor3fv(guard);
            }else if(s[i][j] == 7){
                glColor3fv(button);
            }else{
                glColor3fv(nothing);
            }
            glVertex2f(i, j);
        }
    }
    delay();
    glEnd();
}

Terima kasih. Silakan komen jika ada yang perlu ditanyakan.

No comments:

Post a Comment