2
0

GeneticAlgorithm_BoardWarSimulationMOD.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. //
  2. // Genetic Algorithm Example
  3. // Strategy board game war. Units(2-blue) try to capture the target(4-white/yellow) objective
  4. // and eliminate the enemy units(3-red)
  5. //
  6. // A random movement phase is executed. Here a random spot is selected on the map
  7. // if there is a movable unit than this is moved in any direction. If the new position
  8. // is a enemy than this enemy is taken out. The objective can also be captured.
  9. //
  10. // There are MAX_CODE of moves per set. Then a score is calculated based on how
  11. // close the units are to the GOAL(4) and how many enemies are destroyed(3) and if
  12. // the GOAL(4) has been captured.
  13. // There are MAX_ARC amount of moves per set stored. The top 3 scoring runs get
  14. // copied and these copies get mutated so they might score better. Also a number
  15. // of random new runs are added.
  16. //
  17. // The process of simulating the moves and scoring and mutating is done MAX_RUNS amount of times.
  18. // The final top scoring set of moves is played on the canvas.
  19. //
  20. // Better scoring could be done by storing the amount of move taken to take out x enemy units and capturing target.
  21. //
  22. // Building on this you might change the amount of units for each side. maybe mod the amount of goals to be captured.
  23. // In a real game you might use this to simulate if a war for a ai player would be doable in a certain tested setting like this.
  24. //
  25. // Create unit types with different att and def, more scoring with 1+units attacking at the same time.
  26. // add scoring in the execute script stage : units stay close to each other, direct path to target etc.
  27. //
  28. // Crossbreeding - taking two from higher scorers and combining these into new.
  29. // Seeding the list at start with for instance steps into the right direction.
  30. // IMPLEMENTED>>>If move on enemy position (chance of being destroyed itself(.5) <x if more units of own side are nearby)
  31. #include "raylib.h"
  32. #include <math.h>
  33. #define MAX_RUNS 200
  34. #define MAX_CODE 1200
  35. #define MAX_ARC 64
  36. enum terrain{TREE=1,GROUND=0,AIPLAYER1=2,AIPLAYER2=3,GOAL=4,GOALREACHED=5};
  37. enum flag{UP,DOWN,LEFT,RIGHT,WAIT};
  38. //
  39. // You can set any number of 3 and 2 on the map. more 4's untested. keep the borders(1) intact(memory errors)
  40. //
  41. //1=border,2=ai unit,3=defensiveunit,4=objective
  42. int map1[10][10] = { {1,1,1,1,1,1,1,1,1,1},
  43. {1,0,0,0,0,0,0,0,0,1},
  44. {1,0,0,0,3,0,0,4,0,1},
  45. {1,0,0,3,0,0,3,0,0,1},
  46. {1,0,0,0,0,0,0,0,0,1},
  47. {1,2,0,0,0,0,0,3,0,1},
  48. {1,0,2,0,0,0,0,0,0,1},
  49. {1,0,0,0,0,0,0,2,0,1},
  50. {1,0,0,0,0,0,0,2,0,1},
  51. {1,1,1,1,1,1,1,1,1,1}
  52. };
  53. int map[10][10] = {0};
  54. typedef struct code{
  55. Vector2 position;
  56. Vector2 move;
  57. }code;
  58. static struct code arr_code[MAX_CODE];
  59. typedef struct codearc{
  60. Vector2 position[MAX_CODE];
  61. Vector2 move[MAX_CODE];
  62. int score;
  63. }codearc;
  64. static struct codearc arr_codearc[MAX_ARC];
  65. static struct codearc arr_temparc[MAX_ARC];
  66. int getscore();
  67. void executescript();
  68. void storescript(int z,int score);
  69. void sortarc();//copy top 3 to max-5
  70. void mutateandnew();
  71. void geneticalgorithm();
  72. static float distance(float x1,float y1,float x2,float y2);
  73. static float edistance(float x1,float y1,float x2,float y2);
  74. int screenWidth;
  75. int screenHeight;
  76. int tileWidth,tileHeight,mapWidth,mapHeight;
  77. int main(void)
  78. {
  79. // Initialization
  80. //--------------------------------------------------------------------------------------
  81. screenWidth = 800;
  82. screenHeight = 600;
  83. mapWidth = 10;
  84. mapHeight = 10;
  85. tileWidth = ceil((float)screenWidth/(float)mapWidth);
  86. tileHeight = ceil((float)screenHeight/(float)mapHeight);
  87. InitWindow(screenWidth, screenHeight, "raylib example.");
  88. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  89. //--------------------------------------------------------------------------------------
  90. geneticalgorithm();
  91. int playposition=0;
  92. // Main game loop
  93. while (!WindowShouldClose()) // Detect window close button or ESC key
  94. {
  95. // Update
  96. //----------------------------------------------------------------------------------
  97. if(IsKeyPressed(KEY_SPACE)|| playposition>MAX_CODE-2){
  98. geneticalgorithm();
  99. playposition=0;
  100. }
  101. if(playposition==0){
  102. // restore map
  103. for(int y=0;y<10;y++){
  104. for(int x=0;x<10;x++){
  105. map[y][x]=map1[y][x];
  106. }}
  107. }
  108. // execute script
  109. if(map[ (int)arr_code[playposition].position.y ][ (int)arr_code[playposition].position.x ]==AIPLAYER1){
  110. Vector2 p=arr_code[playposition].position;
  111. Vector2 m=arr_code[playposition].move;
  112. Vector2 np=(Vector2){p.x+m.x,p.y+m.y};
  113. if(map[ (int)np.y ][ (int)np.x ]==GOAL){
  114. map[ (int)np.y ][ (int)np.x ] = GOALREACHED;
  115. }
  116. if(map[ (int)np.y ][ (int)np.x ]==GROUND){
  117. map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
  118. map[ (int)p.y ][ (int)p.x ] = GROUND;
  119. }
  120. if(map[ (int)np.y ][ (int)np.x ]==AIPLAYER2){
  121. map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
  122. map[ (int)p.y ][ (int)p.x ] = GROUND;
  123. }
  124. }
  125. playposition+=1;
  126. if(playposition>MAX_CODE-1){
  127. playposition=0;
  128. }
  129. //----------------------------------------------------------------------------------
  130. // Draw
  131. //----------------------------------------------------------------------------------
  132. BeginDrawing();
  133. ClearBackground(RAYWHITE);
  134. //drawmap
  135. for(int y=0;y<10;y++){
  136. for(int x =0;x<10;x++){
  137. int m=map[y][x];
  138. if(m==TREE){
  139. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,(Color){40,90,20,255});
  140. DrawCircle(x*tileWidth+tileWidth/1.5,y*tileHeight+tileHeight/1.5,tileWidth/5,(Color){20,50,20,255});
  141. DrawRectangle(x*tileWidth+tileWidth/2.2,y*tileHeight+tileHeight/2,tileWidth/8,tileHeight/3,BROWN);
  142. DrawCircle(x*tileWidth+tileWidth/2,y*tileHeight+tileHeight/3,tileWidth/4,(Color){120,250,20,255});
  143. DrawCircle(x*tileWidth+tileWidth/2.2,y*tileHeight+tileHeight/4,tileWidth/9,(Color){220,255,220,155});
  144. }
  145. if(m==GROUND){
  146. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,DARKGREEN);
  147. DrawRectangle(x*tileWidth+5,y*tileHeight+10,2,1,GREEN);
  148. DrawRectangle(x*tileWidth+tileWidth/6,y*tileHeight+tileHeight/6,2,1,GREEN);
  149. DrawRectangle(x*tileWidth+tileWidth/1.5,y*tileHeight+tileHeight/1.5,2,1,GREEN);
  150. DrawRectangle(x*tileWidth+tileWidth/2,y*tileHeight+tileHeight/2,2,1,GREEN);
  151. }
  152. if(m==AIPLAYER1){
  153. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,BLUE);
  154. DrawText("AI_Player",x*tileWidth,y*tileHeight+tileHeight/4,16,BLACK);
  155. }
  156. if(m==AIPLAYER2){
  157. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,RED);
  158. DrawText("F",x*tileWidth+tileWidth/3,y*tileHeight+tileHeight/4,40,WHITE);
  159. }
  160. if(m==GOAL){
  161. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,WHITE);
  162. DrawText("City",x*tileWidth+tileWidth/4,y*tileHeight+tileHeight/4,26,BLACK);
  163. }
  164. if(m==GOALREACHED){
  165. DrawRectangle(x*tileWidth,y*tileHeight,tileWidth,tileHeight,YELLOW);
  166. DrawText("Captured",x*tileWidth+4,y*tileHeight+tileHeight/4,16,BLACK);
  167. }
  168. }
  169. }
  170. DrawText("Press space for new simulation.(Autorun=on)",10,10,26,BLACK);
  171. DrawText("Press space for new simulation.(Autorun=on)",9,9,26,WHITE);
  172. /*
  173. int c=0;
  174. for(int y=0;y<40;y++){
  175. for(int x=0;x<5;x++){
  176. if(c<MAX_ARC){
  177. DrawText(FormatText("%i",arr_codearc[c].score),x*200,y*20,20,BLACK);
  178. }
  179. c++;
  180. }}
  181. */
  182. EndDrawing();
  183. //----------------------------------------------------------------------------------
  184. }
  185. // De-Initialization
  186. //--------------------------------------------------------------------------------------
  187. CloseWindow(); // Close window and OpenGL context
  188. //--------------------------------------------------------------------------------------
  189. return 0;
  190. }
  191. void geneticalgorithm(){
  192. // First run
  193. for(int z=0;z<MAX_ARC;z++){
  194. //create random script
  195. for(int i=0;i<MAX_CODE;i++){
  196. arr_code[i].position=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
  197. arr_code[i].move=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
  198. }
  199. // restore map
  200. for(int y=0;y<10;y++){
  201. for(int x=0;x<10;x++){
  202. map[y][x]=map1[y][x];
  203. }}
  204. executescript();
  205. // SCORING!
  206. int score = getscore();
  207. // store script
  208. storescript(z,score);
  209. }
  210. //keep top 3
  211. // copy top 3 to max-5
  212. //mutate 3..max-5
  213. //new random max-5 max
  214. //
  215. // Run it and mutate picking winners
  216. for(int t=0;t<MAX_RUNS;t++){
  217. sortarc();
  218. mutateandnew();
  219. for(int z=0;z<MAX_ARC;z++){
  220. // simulate new
  221. // restore map
  222. for(int y=0;y<10;y++){
  223. for(int x=0;x<10;x++){
  224. map[y][x]=map1[y][x];
  225. }}
  226. getscript(z);
  227. executescript();
  228. // SCORING!
  229. int score = getscore();
  230. arr_codearc[z].score = score;
  231. // store script
  232. //storescript(z,score);
  233. }
  234. }
  235. //return;
  236. // restore map and get the victor into the arr_code (our script)
  237. // restore map
  238. for(int y=0;y<10;y++){
  239. for(int x=0;x<10;x++){
  240. map[y][x]=map1[y][x];
  241. }}
  242. getscript(0);
  243. //executescript();
  244. }
  245. void mutateandnew(){
  246. //mutate 3 to max-5
  247. // This is from a starting point from %10 to %50 to end
  248. for(int z=3;z<MAX_ARC-5;z++){
  249. int start=GetRandomValue(MAX_CODE/4,MAX_CODE/1.5);
  250. for(int i=start;i<MAX_CODE;i++){
  251. arr_codearc[z].position[i]=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
  252. arr_codearc[z].move[i]=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
  253. }
  254. }
  255. // max-5 to max is new ones
  256. for(int z=MAX_ARC-5;z<MAX_ARC;z++){
  257. for(int i=0;i<MAX_CODE;i++){
  258. arr_codearc[z].position[i]=(Vector2){GetRandomValue(0,10),GetRandomValue(0,10)};
  259. arr_codearc[z].move[i]=(Vector2){GetRandomValue(-1,1),GetRandomValue(-1,1)};
  260. }
  261. }
  262. }
  263. void sortarc(){
  264. int top3[3] = {0};
  265. int startval=800;
  266. int currentpos=0;
  267. // get top 3 in list top3
  268. while(startval>0 && currentpos<3){
  269. for(int i=0;i<MAX_ARC;i++){
  270. if(arr_codearc[i].score==startval){
  271. if(currentpos<3){
  272. top3[currentpos]=i;
  273. }
  274. currentpos++;
  275. }
  276. }
  277. startval--;
  278. }
  279. // copy the 3 tops into temp arc
  280. for(int i=0;i<MAX_CODE;i++){
  281. for(int j=0;j<3;j++){
  282. arr_temparc[j].position[i] = arr_codearc[top3[j]].position[i];
  283. arr_temparc[j].move[i] = arr_codearc[top3[j]].move[i];
  284. arr_temparc[j].score = arr_codearc[top3[j]].score;
  285. }
  286. }
  287. // copy top up to max-5
  288. for(int i=0;i<MAX_ARC-8;i+=3){
  289. for(int k=0;k<3;k++){
  290. for(int j=0;j<MAX_CODE;j++){
  291. arr_codearc[i+k].position[j] = arr_temparc[k].position[j];
  292. arr_codearc[i+k].move[j] = arr_temparc[k].move[j];
  293. arr_codearc[i+k].score = arr_temparc[k].score;
  294. }
  295. }
  296. }
  297. }
  298. void getscript(int z){
  299. // store script
  300. //arr_codearc[z].score = score;
  301. //arr_code.score =
  302. for(int i=0;i<MAX_CODE;i++){
  303. //arr_codearc[z].move[i] = arr_code[i].move;
  304. //arr_codearc[z].position[i] = arr_code[i].position;
  305. arr_code[i].move = arr_codearc[z].move[i];
  306. arr_code[i].position = arr_codearc[z].position[i];
  307. }
  308. }
  309. void storescript(int z,int score){
  310. // store script
  311. arr_codearc[z].score = score;
  312. for(int i=0;i<MAX_CODE;i++){
  313. arr_codearc[z].move[i] = arr_code[i].move;
  314. arr_codearc[z].position[i] = arr_code[i].position;
  315. }
  316. }
  317. int getscore(){
  318. int score=0;
  319. //count enemies left
  320. int numenemiesleft=0;
  321. int playersleft=0;
  322. for(int y=0;y<10;y++){
  323. for(int x=0;x<10;x++){
  324. if(map[y][x]==AIPLAYER2)numenemiesleft++;
  325. if(map[y][x]==AIPLAYER1)playersleft++;
  326. }
  327. }
  328. //was the goal taken
  329. bool objectivesuccess = false;
  330. Vector2 goalposition;
  331. for(int y=0;y<10;y++){
  332. for(int x=0;x<10;x++){
  333. if(map[y][x]==GOALREACHED)objectivesuccess=true;
  334. if(map[y][x]==GOAL || map[y][x]==GOALREACHED){
  335. goalposition.x = x;
  336. goalposition.y = y;
  337. }
  338. }
  339. }
  340. //count aiplayer1 and distance to target
  341. float avdist=0;
  342. int nums=0;
  343. int distanceunit[114]={0};
  344. for(int y=0;y<10;y++){
  345. for(int x=0;x<10;x++){
  346. if(map[y][x]==AIPLAYER1){
  347. int d = 0;
  348. d=edistance((float)goalposition.x,(float)goalposition.y,(float)x,(float)y)*2;
  349. distanceunit[nums]=(int)d;
  350. avdist+=d;
  351. nums++;
  352. }
  353. }}
  354. avdist=avdist/(float)playersleft;
  355. score = (100-(numenemiesleft*25))*2;
  356. score+=(100-(int)avdist*5);
  357. if(objectivesuccess==true)score+=75;
  358. // if every unit is close then extra score
  359. bool allclose=true;
  360. for(int i=0;i<playersleft;i++){
  361. if(distanceunit[i]>4)allclose=false;
  362. }
  363. if(allclose==true)score+=100;
  364. //score=avdist;
  365. //if(score<0)score=9999;
  366. return score;
  367. }
  368. void executescript(){
  369. // execute script
  370. for(int i=0;i<MAX_CODE;i++){
  371. if(map[ (int)arr_code[i].position.y ][ (int)arr_code[i].position.x ]==AIPLAYER1){
  372. Vector2 p=arr_code[i].position;
  373. Vector2 m=arr_code[i].move;
  374. Vector2 np=(Vector2){p.x+m.x,p.y+m.y};
  375. if(map[ (int)np.y ][ (int)np.x ]==GOAL){
  376. map[ (int)np.y ][ (int)np.x ] = GOALREACHED;
  377. }
  378. if(map[ (int)np.y ][ (int)np.x ]==GROUND){
  379. map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
  380. map[ (int)p.y ][ (int)p.x ] = GROUND;
  381. }
  382. if(map[ (int)np.y ][ (int)np.x ]==AIPLAYER2){
  383. int neigh=0;
  384. //for(int y=p.y-1;p.y+1;y++){
  385. //for(int x1=(int)p.x-1;(int)p.x+1;x1++){
  386. //
  387. //
  388. if(map[(int)np.y][(int)np.x-1]==AIPLAYER1)neigh+=1;
  389. if(map[(int)np.y][(int)np.x+1]==AIPLAYER1)neigh+=1;
  390. if(map[(int)np.y-1][(int)np.x]==AIPLAYER1)neigh+=1;
  391. if(map[(int)np.y+1][(int)np.x]==AIPLAYER1)neigh+=1;
  392. if(map[(int)np.y+1][(int)np.x-1]==AIPLAYER1)neigh+=1;
  393. if(map[(int)np.y-1][(int)np.x+1]==AIPLAYER1)neigh+=1;
  394. if(map[(int)np.y-1][(int)np.x+1]==AIPLAYER1)neigh+=1;
  395. if(map[(int)np.y+1][(int)np.x-1]==AIPLAYER1)neigh+=1;
  396. //}//}
  397. if(GetRandomValue(0,10-(neigh*2))<4){
  398. map[ (int)np.y ][ (int)np.x ] = AIPLAYER1;
  399. map[ (int)p.y ][ (int)p.x ] = GROUND;
  400. }else{
  401. //map[ (int)np.y ][ (int)np.x ] = AIPLAYER2;
  402. map[ (int)p.y ][ (int)p.x ] = GROUND;
  403. }
  404. }
  405. }
  406. }
  407. }
  408. // Manhattan Distance (less precise)
  409. float distance(float x1,float y1,float x2,float y2){
  410. return (float)abs(x2-x1)+abs(y2-y1);
  411. }
  412. // Euclidean distance (more precise)
  413. float edistance(float x1,float y1,float x2,float y2){
  414. return sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) );
  415. }