瀏覽代碼

Create GeneticAlgorithm_BoardWarSimulation.c

Rudy Boudewijn van Etten 4 年之前
父節點
當前提交
0a1d72d9eb
共有 1 個文件被更改,包括 417 次插入0 次删除
  1. 417 0
      ai/GeneticAlgorithm_BoardWarSimulation.c

+ 417 - 0
ai/GeneticAlgorithm_BoardWarSimulation.c

@@ -0,0 +1,417 @@
+//
+// Genetic Algorithm Example
+
+// Strategy board game war. Units(2-blue) try to capture the target(4-white/yellow) objective
+// and eliminate the enemy units(3-red)
+// 
+// A random movement phase is executed. Here a random spot is selected on the map
+// if there is a movable unit than this is moved in any direction. If the new position
+// is a enemy than this enemy is taken out. The objective can also be captured.
+//
+// There are MAX_CODE of moves per set. Then a score is calculated based on how
+// close the units are to the GOAL(4) and how many enemies are destroyed(3) and if
+// the GOAL(4) has been captured.
+
+// There are MAX_ARC amount of moves per set stored. The top 3 scoring runs get
+// copied and these copies get mutated so they might score better. Also a number
+// of random new runs are added.
+// 
+// The process of simulating the moves and scoring and mutating is done MAX_RUNS amount of times.
+
+// The final top scoring set of moves is played on the canvas.
+//
+
+// Better scoring could be done by storing the amount of move taken to take out x enemy units and capturing target.
+
+
+#include "raylib.h"
+#include <math.h>
+
+#define MAX_RUNS 50
+#define MAX_CODE 1500
+#define MAX_ARC 32
+
+enum terrain{TREE=1,GROUND=0,AIPLAYER1=2,AIPLAYER2=3,GOAL=4,GOALREACHED=5};
+enum flag{UP,DOWN,LEFT,RIGHT,WAIT};
+
+
+//1=border,2=ai unit,3=defensiveunit,4=objective
+int map1[10][10] = {    {1,1,1,1,1,1,1,1,1,1},
+                        {1,0,0,0,0,0,0,0,0,1},
+                        {1,0,0,0,0,0,3,4,0,1},
+                        {1,0,0,3,0,0,0,0,0,1},
+                        {1,0,0,0,0,0,3,0,0,1},
+                        {1,2,0,0,0,0,0,3,0,1},
+                        {1,0,2,0,0,0,0,0,0,1},
+                        {1,0,2,2,0,0,0,0,0,1},
+                        {1,0,0,0,0,0,0,0,0,1},
+                        {1,1,1,1,1,1,1,1,1,1}
+                        };  
+int map[10][10] = {0};
+
+
+typedef struct code{
+    Vector2 position;
+    Vector2 move;
+}code;
+static struct code arr_code[MAX_CODE];
+
+typedef struct codearc{
+    Vector2 position[MAX_CODE];
+    Vector2 move[MAX_CODE];
+    int score;
+}codearc;
+static struct codearc arr_codearc[MAX_ARC];
+static struct codearc arr_temparc[MAX_ARC];
+
+
+int getscore();
+void executescript();
+void storescript(int z,int score);
+void sortarc();//copy top 3 to max-5
+void mutateandnew();
+void geneticalgorithm();
+static float distance(float x1,float y1,float x2,float y2);
+static float edistance(float x1,float y1,float x2,float y2);
+
+int screenWidth;
+int screenHeight;
+int tileWidth,tileHeight,mapWidth,mapHeight;
+
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    screenWidth = 800;
+    screenHeight = 600;
+    mapWidth = 10;
+    mapHeight = 10;
+    tileWidth = ceil((float)screenWidth/(float)mapWidth);
+    tileHeight = ceil((float)screenHeight/(float)mapHeight);
+    
+    InitWindow(screenWidth, screenHeight, "raylib example.");
+ 
+    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    geneticalgorithm();
+   
+    
+    int playposition=0;
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        
+        if(IsKeyPressed(KEY_SPACE)){
+            geneticalgorithm();
+            playposition=0;
+        }
+        
+        if(playposition==0){
+            // restore map
+            for(int y=0;y<10;y++){
+            for(int x=0;x<10;x++){
+                map[y][x]=map1[y][x];
+            }}                
+        }
+        // execute script
+        if(map[ (int)arr_code[playposition].position.y ][ (int)arr_code[playposition].position.x ]==AIPLAYER1){
+            Vector2 p=arr_code[playposition].position;
+            Vector2 m=arr_code[playposition].move;
+            Vector2 np=(Vector2){p.x+m.x,p.y+m.y};
+            if(map[ (int)np.y ][ (int)np.x ]==GOAL){
+                map[ (int)np.y ][ (int)np.x ] = GOALREACHED;
+            }
+            if(map[ (int)np.y ][ (int)np.x ]==GROUND){
+                map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
+                map[ (int)p.y ][ (int)p.x ] = GROUND;
+            }
+            if(map[ (int)np.y ][ (int)np.x ]==AIPLAYER2){
+                map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
+                map[ (int)p.y ][ (int)p.x ] = GROUND;
+                
+            }                
+        }
+        
+        playposition+=1;
+        if(playposition>MAX_CODE-1){
+            playposition=0;
+        }
+        
+        //----------------------------------------------------------------------------------
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+            //drawmap
+            for(int y=0;y<10;y++){
+                for(int x =0;x<10;x++){
+                    int m=map[y][x];
+                    if(m==TREE){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,GREEN);                        
+                    }
+                    if(m==GROUND){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,DARKGREEN);                        
+                    }
+                    if(m==AIPLAYER1){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,BLUE);                        
+                    }
+                    if(m==AIPLAYER2){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,RED);                        
+                    }
+                    if(m==GOAL){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,WHITE);                        
+                    }
+                    if(m==GOALREACHED){
+                        DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,YELLOW);                        
+                    }
+
+
+            }
+            }
+            DrawText("Press space for new simulation.",10,10,20,BLACK);
+//            int c=0;
+//            for(int y=0;y<40;y++){
+//            for(int x=0;x<5;x++){
+//                if(c<MAX_ARC){
+//                    DrawText(FormatText("%i",arr_codearc[c].score),x*200,y*20,20,BLACK);
+//                }
+//                c++;
+//            }}
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+
+
+}
+
+void geneticalgorithm(){
+
+    for(int z=0;z<MAX_ARC;z++){
+        //create random script
+        for(int i=0;i<MAX_CODE;i++){
+            arr_code[i].position=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
+            arr_code[i].move=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
+        }
+        
+        // restore map
+        for(int y=0;y<10;y++){
+        for(int x=0;x<10;x++){
+            map[y][x]=map1[y][x];
+        }}
+        
+        executescript();
+        // SCORING!
+        int score = getscore();
+        // store script
+        storescript(z,score);
+
+
+    }
+    
+    //keep top 3
+    // copy top 3 to max-5
+    //mutate 3..max-5
+    //new random max-5 max
+    //
+    for(int t=0;t<MAX_RUNS;t++){
+        sortarc();
+        mutateandnew();
+
+        for(int z=0;z<MAX_ARC;z++){
+            // simulate new
+            // restore map
+            for(int y=0;y<10;y++){
+            for(int x=0;x<10;x++){
+                map[y][x]=map1[y][x];
+            }}
+            getscript(z);
+            executescript();
+            // SCORING!
+            int score = getscore();
+            arr_codearc[z].score = score;
+            // store script
+            //storescript(z,score);
+        }
+    }
+
+    // Final set and display
+    // restore map
+    for(int y=0;y<10;y++){
+    for(int x=0;x<10;x++){
+        map[y][x]=map1[y][x];
+    }}    
+    getscript(0);
+    executescript();
+}
+
+void mutateandnew(){    
+    //mutate 3 to max-5
+    // This is from a starting point from %10 to %50 to end
+    for(int z=3;z<MAX_ARC-5;z++){
+        int start=GetRandomValue(0,MAX_CODE/2);
+        for(int i=start;i<MAX_CODE;i++){
+            arr_codearc[z].position[i]=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
+            arr_codearc[z].move[i]=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
+        }
+    }
+    // max-5 to max is new ones
+    for(int z=MAX_ARC-5;z<MAX_ARC;z++){
+        for(int i=0;i<MAX_CODE;i++){
+            arr_codearc[z].position[i]=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
+            arr_codearc[z].move[i]=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
+        }
+    }
+}
+ 
+
+void sortarc(){
+    int top3[3] = {0};
+    int startval=2000;
+    int currentpos=0;
+    // get top 3 in list top3
+    while(startval>0 && currentpos<3){
+        for(int i=0;i<MAX_ARC;i++){
+            if(arr_codearc[i].score==startval){
+                if(currentpos<3){
+                    top3[currentpos]=i;
+                }
+                currentpos++;
+            }
+        }
+        startval--;
+    }
+    
+    // copy the 3 tops into temp arc
+    for(int i=0;i<MAX_CODE;i++){
+        for(int j=0;j<3;j++){
+            arr_temparc[j].position[i] = arr_codearc[top3[j]].position[i];
+            arr_temparc[j].move[i] = arr_codearc[top3[j]].move[i];
+            arr_temparc[j].score = arr_codearc[top3[j]].score;
+        }
+    }
+    
+    // copy top up to max-5
+    for(int i=0;i<MAX_ARC-8;i+=3){            
+        for(int k=0;k<3;k++){
+            for(int j=0;j<MAX_CODE;j++){
+                arr_codearc[i+k].position[j] = arr_temparc[k].position[j];
+                arr_codearc[i+k].move[j] = arr_temparc[k].move[j];
+                arr_codearc[i+k].score = arr_temparc[k].score;
+            }
+        }
+    }
+}
+
+void getscript(int z){
+    // store script
+    //arr_codearc[z].score = score;
+    //arr_code.score = 
+    for(int i=0;i<MAX_CODE;i++){
+        //arr_codearc[z].move[i] = arr_code[i].move;
+        //arr_codearc[z].position[i] = arr_code[i].position;
+        arr_code[i].move = arr_codearc[z].move[i];
+        arr_code[i].position = arr_codearc[z].position[i];
+    }    
+}        
+
+
+void storescript(int z,int score){
+    // store script
+    arr_codearc[z].score = score;
+
+    for(int i=0;i<MAX_CODE;i++){
+        arr_codearc[z].move[i] = arr_code[i].move;
+        arr_codearc[z].position[i] = arr_code[i].position;
+    }    
+}        
+
+int getscore(){
+    int score=0;
+    //count enemies left
+    int numenemiesleft=0;
+    for(int y=0;y<10;y++){
+    for(int x=0;x<10;x++){
+        if(map[y][x]==AIPLAYER2)numenemiesleft++;
+    }
+    }
+    //was the goal taken
+    bool objectivesuccess = false;
+    Vector2 goalposition;
+    for(int y=0;y<10;y++){
+    for(int x=0;x<10;x++){
+        if(map[y][x]==GOALREACHED)objectivesuccess=true;
+        if(map[y][x]==GOAL || map[y][x]==GOALREACHED){
+            goalposition.x = x;
+            goalposition.y = y;
+        }
+    }
+    }
+ 
+    //count aiplayer1 and distance to target
+    float avdist=0;
+    int nums=0;
+    for(int y=0;y<10;y++){
+    for(int x=0;x<10;x++){
+        if(map[y][x]==AIPLAYER1){
+            avdist+=edistance((float)goalposition.x,(float)goalposition.y,(float)x,(float)y)*2;
+            nums++;
+        }
+    }}
+    avdist=avdist/(float)4;
+    
+
+    score = 100-(numenemiesleft*25);
+    score+=(50-(int)avdist);
+    if(objectivesuccess==true)score+=50;
+    //score=avdist;
+    if(score<0)score=9999;
+    
+    return score;
+}
+
+
+void executescript(){
+    // execute script
+    for(int i=0;i<MAX_CODE;i++){
+        if(map[ (int)arr_code[i].position.y ][ (int)arr_code[i].position.x ]==AIPLAYER1){
+            Vector2 p=arr_code[i].position;
+            Vector2 m=arr_code[i].move;
+            Vector2 np=(Vector2){p.x+m.x,p.y+m.y};
+            if(map[ (int)np.y ][ (int)np.x ]==GOAL){
+                map[ (int)np.y ][ (int)np.x ] = GOALREACHED;
+            }
+            if(map[ (int)np.y ][ (int)np.x ]==GROUND){
+                map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
+                map[ (int)p.y ][ (int)p.x ] = GROUND;
+            }
+            if(map[ (int)np.y ][ (int)np.x ]==AIPLAYER2){
+                map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
+                map[ (int)p.y ][ (int)p.x ] = GROUND;
+                
+            }                
+        }
+    }
+}
+
+
+// Manhattan Distance (less precise)
+float distance(float x1,float y1,float x2,float y2){
+    return (float)abs(x2-x1)+abs(y2-y1);
+}
+
+// Euclidean distance (more precise)
+float edistance(float x1,float y1,float x2,float y2){
+    return sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) );
+}