From 06f13c47457c63ee9c11f05a56e8f9c87a847139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1ndly=20Gerg=C5=91?= Date: Sat, 7 May 2022 15:08:13 +0300 Subject: [PATCH] AI Path Finder --- AIPathFinder.pde | 50 ++++++++++++++++++++++++ Brain.pde | 47 +++++++++++++++++++++++ Dot.pde | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ Genetic.pde | 55 +++++++++++++++++++++++++++ Obstacle.pde | 26 +++++++++++++ Obstacles.pde | 30 +++++++++++++++ Population.pde | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 404 insertions(+) create mode 100644 AIPathFinder.pde create mode 100644 Brain.pde create mode 100644 Dot.pde create mode 100644 Genetic.pde create mode 100644 Obstacle.pde create mode 100644 Obstacles.pde create mode 100644 Population.pde diff --git a/AIPathFinder.pde b/AIPathFinder.pde new file mode 100644 index 0000000..a9599cc --- /dev/null +++ b/AIPathFinder.pde @@ -0,0 +1,50 @@ +PVector goal; +Obstacles obstacles; +Genetic AI; + +void setup(){ + size(800, 800); + frameRate(100000); + goal=new PVector(400, 10); + obstacles=new Obstacles(); + AI=new Genetic(true); + + obstacles.add(new Obstacle(300, 580, 800, 600)); + obstacles.add(new Obstacle(350, 30, 450, 50)); + obstacles.add(new Obstacle(600, 10, 620, 300)); + obstacles.add(new Obstacle(300, 650, 320, 800)); + obstacles.add(new Obstacle(100, 400, 800, 420)); + obstacles.add(new Obstacle(0, 520, 200, 540)); +} + +void draw(){ + background(255); + + //draw goal + fill(255, 0, 0); + ellipse(goal.x, goal.y, 10, 10); + + //draw obstacles + obstacles.display(); + + //run genetica + if(!AI.isDone()){ + AI.update(); + } + else{ + AI.nextGeneration(); + } + + //print infos + fill(0); + text("Generation: "+AI.generation, 10, 10); + text("Minimal steps: "+AI.lessSteps, 10, 20); + text("Minimal distance: "+AI.lessDistance, 10, 30); + text("Max fitness: "+AI.maxFitness, 10, 40); + text("Goal reached: "+AI.goalReached, 10, 50); + text("Steps/s: "+frameRate, 10, 60); +} + +void mouseClicked(){ + AI.toggleDisplay(); +} diff --git a/Brain.pde b/Brain.pde new file mode 100644 index 0000000..ed79ce5 --- /dev/null +++ b/Brain.pde @@ -0,0 +1,47 @@ +class Brain{ + PVector[] directions; + int step=0; + + //Constructor + Brain(int size){ + directions=new PVector[size]; + + //random fill + for(int i=0; i= width-2 || pos.y >= height-2){ + dead=true; + } + //check if intersects obstacle + else if(obstacles.isIntersecting(this)){ + dead=true; + deadByObstacle=true; + } + + //detect if reached goal + if(dist(pos.x, pos.y, goal.x, goal.y) < 2){ + reachedGoal=true; + } + } + + //update point + boolean update(){ + if(!dead && !reachedGoal){ + move(); + return true; + } + else{ + return false; + } + } + + //calculate fitness + float calcFitness(){ + if(reachedGoal){ + fitness=10000.0/(brain.step*brain.step); + } + else if(!deadByObstacle){ + float distToGoal=dist(pos.x, pos.y, goal.x, goal.y); + fitness=2.0/(distToGoal*distToGoal); + } + else{ + float distToGoal=dist(pos.x, pos.y, goal.x, goal.y); + fitness=1.0/(distToGoal*distToGoal); + } + + return fitness; + } + + //get children + Dot getChild(){ + Dot child=new Dot(); + child.brain=brain.clone(); + return child; + } + + //is alive + boolean alive(){ + return !(dead || reachedGoal); + } + + //display dot + void display(){ + if(champ){ + fill(0, 255, 0); + ellipse(pos.x, pos.y, 8, 8); + } + else{ + fill(0); + ellipse(pos.x, pos.y, 4, 4); + } + } +} diff --git a/Genetic.pde b/Genetic.pde new file mode 100644 index 0000000..1d6450d --- /dev/null +++ b/Genetic.pde @@ -0,0 +1,55 @@ +class Genetic{ + int generation=1; + boolean display=false; + Population population; + int lessSteps=0; + float lessDistance=0; + float maxFitness=0; + boolean goalReached=false; + + //constructor + Genetic(boolean disp){ + population=new Population(500); + display=disp; + } + + //check if finished with current population + boolean isDone(){ + return !population.hasDotAlive(); + } + + void toggleDisplay(){ + display=!display; + } + + //update population + void update(){ + if(!isDone()){ + population.update(); + if(display){ + population.display(); + } + } + } + + //generate next population + void nextGeneration(){ + //claculate the fitness of points + population.calcFitness(); + + //get best datas + lessSteps=population.getChampion().brain.step; + lessDistance=dist(population.getChampion().pos.x, population.getChampion().pos.y, goal.x, goal.y); + maxFitness=population.getChampion().fitness; + goalReached=population.getChampion().reachedGoal; + + //naturally select best dots + population.naturalSelection(); + + //mutate the next generation + population.mutate(); + + //increment counter + generation++; + } +} \ No newline at end of file diff --git a/Obstacle.pde b/Obstacle.pde new file mode 100644 index 0000000..fa91893 --- /dev/null +++ b/Obstacle.pde @@ -0,0 +1,26 @@ +class Obstacle{ + PVector c1; + PVector c2; + + //constructor + Obstacle(int x1, int y1, int x2, int y2){ + c1=new PVector(x1, y1); + c2=new PVector(x2, y2); + } + + //check intersection with a dot + boolean isIntersecting(Dot dot){ + if(dot.pos.x >= c1.x && dot.pos.x <= c2.x && dot.pos.y >= c1.y && dot.pos.y <= c2.y){ + return true; + } + else{ + return false; + } + } + + //display it + void display(){ + fill(255, 255, 0); + rect(c1.x, c1.y, c2.x-c1.x, c2.y-c1.y); + } +} \ No newline at end of file diff --git a/Obstacles.pde b/Obstacles.pde new file mode 100644 index 0000000..88ece35 --- /dev/null +++ b/Obstacles.pde @@ -0,0 +1,30 @@ +class Obstacles{ + ArrayList obs; + + //constructor + Obstacles(){ + obs=new ArrayList(); + } + + //add obstacle + void add(Obstacle o){ + obs.add(o); + } + + //check intersection + boolean isIntersecting(Dot dot){ + for(int i=0; ibig){ + big=dots[i].fitness; + champIndex=i; + } + } + + return dots[champIndex]; + } + + //get a perfect parent based on their fitness + Dot getAParent(){ + float rand=random(sumOfFitness); + + float sum=0; + for(int i=0; irand){ + return dots[i]; + } + } + + //shouldn't get here + return null; + } + + //natural selection + void naturalSelection(){ + Dot[] nextGen=new Dot[dots.length]; + + calcFitness(); + + nextGen[0]=getChampion().getChild(); + nextGen[0].champ=true; + + for(int i=1; i