遗传算法实现机器人寻路
package com.louis.robot; /** * Project Name:GeneticAlgorithm * File Name:Individual.java * Package Name: * Date:2017年9月23日下午5:02:00 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ /** * ClassName:Individual * Function: 个体类 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午5:02:00 * @author michael * @version * @since JDK 1.7 * @see */ public class Individual { //定义染色体,染色体是要很多基因组成 private int[] chromosome; //定义个体实现度,默认值是-1 private double fitness = -1; /* * 通过特定染色体创建个体 * */ public Individual(int[] chromosome){ this.chromosome = chromosome; } /* * 通过随机基因创建个体:染色上的基因是随机数产生的 * */ public Individual(int chromosomeLength){ this.chromosome = new int[chromosomeLength]; for (int gene = 0; gene < chromosomeLength; gene++) { if(0.5<Math.random()){ this.setGene(gene, 1); } else { this.setGene(gene, 0); } } } /* * get 个体的基因 * */ public int[] getChromosome(){ return this.chromosome; } /* * get 基因的长度 * */ public int getChromosomeLength(){ return this.chromosome.length; } /* * 在特定的地方设置基因 * */ public void setGene(int offset,int gene){ this.chromosome[offset] = gene; } /* * 在特定的地方得到基因 * */ public int getGene(int offset){ return this.chromosome[offset]; } /* * 设置个体适应度 * */ public void setFitness(double fitness){ this.fitness = fitness; } /* * 得到个体适应度 * */ public double getFitness(){ return this.fitness; } /* * 染色体(即所有基因)以字符串的形式打印 * */ public String toString(){ String output = ""; for (int gene = 0; gene < this.chromosome.length; gene++) { output +=this.chromosome[gene]; } return output; } }
package com.louis.robot; import java.util.Arrays; import java.util.Comparator; import java.util.Random; import org.apache.jasper.tagplugins.jstl.core.If; /** * Project Name:GeneticAlgorithm * File Name:Population.java * Package Name: * Date:2017年9月23日下午7:44:55 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ /** * ClassName:Population * Function: 种群类 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午7:44:55 * @author michael * @version * @since JDK 1.7 * @see */ public class Population { //种群:所有个体的集合 public Individual[] population; //种群适应度 public double populationFitness=-1; /* * 初始化一个空的种群,参数是种群的大小 * */ public Population(int populationSize){ this.population = new Individual[populationSize]; } /* * 初始化种群,参数是:(1)种群的大小,(2)染色体的长度 * */ public Population(int populationSize,int chromosomeLength){ //新建一个种群,即所有个体的集合 this.population = new Individual[populationSize]; //创建种群中的每个个体 for (int individualCount = 0; individualCount < populationSize; individualCount++) { //调用Individual类的构造方法,创建个体 Individual individual = new Individual(chromosomeLength); //将该个体添加到种群中 this.population[individualCount] = individual; } } /* * 从种群中得到所有个体 * */ public Individual[] getIndividuals(){ return this.population; } /* *通过个体适应度选择一个个体 *先将种群进行排序,最后获得第offset位置的个体 *按适应度顺序排列个体 *从高到底排序 * */ public Individual getFittest(int offset){ //对种群中的个体按照适应度进行排序 Arrays.sort(this.population, new Comparator<Individual>() { @Override public int compare(Individual o1, Individual o2) { if(o1.getFitness()>o2.getFitness()){ return -1; } else if(o1.getFitness()<o2.getFitness()){ return 1; } return 0; } //Arrays.sort(数组,比较器<数组类型>) }); //返回排序第offset的个体 return this.population[offset]; } /* * 得到种群适应度 * */ public double getPopulationFitness() { return populationFitness; } /* * 设置种群适应度 * */ public void setPopulationFitness(double populationFitness) { this.populationFitness = populationFitness; } /* * 得到种群的大小 * */ public int size(){ return this.population.length; } /* * 在第offset位置设置个体 * */ public Individual setIndividual(int offset,Individual individual){ return population[offset] = individual; } /* * 得到第offset位置的个体 * */ public Individual getIndividual(int offset){ return population[offset]; } /* * 随机洗牌 * */ public void shuffle() { Random rnd = new Random(); for (int i = population.length - 1; i > 0; i--) { int index = rnd.nextInt(i + 1); Individual a = population[index]; population[index] = population[i]; population[i] = a; } } }
/** * Project Name:GeneticAlgorithm * File Name:Maze.java * Package Name:com.louis.rebot * Date:2017年9月24日上午9:38:37 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ package com.louis.robot; import java.util.ArrayList; /** * ClassName:Maze * Function: 迷宫类 * Reason: * 0 = Empty * 1 = Wall * 2 = Starting position * 3 = Route * 4 = Goal position * Date: 2017年9月24日 上午9:38:37 * @author michael * @version * @since JDK 1.7 * @see */ public class Maze { private final int maze[][]; private int startPosition[] = {-1,-1}; public Maze(int maze[][]){ this.maze = maze; } /* * 得到起始位置 * */ public int[] getStartPosition(){ //确认已经找到起始位置 if(this.startPosition[0]!=-1&&this.startPosition[1]!=-1){ return this.startPosition; } //返回默认值 int startPosition[] = {0,0}; //遍历 for (int rowIndex = 0; rowIndex < this.maze.length; rowIndex++) { for (int colIndex = 0; colIndex < this.maze[rowIndex].length; colIndex++) { //找坐标值是2的坐标 if(this.maze[rowIndex][colIndex]==2){ this.startPosition = new int[]{colIndex,rowIndex}; return new int[]{colIndex,rowIndex}; } } } return startPosition; } /* * 得到具体位置上的值 * */ public int getPositionValue(int x,int y){ //在指定范围以外的坐标值为1,即是墙 if(x<0||y<0||x>=this.maze.length||y>=this.maze[0].length){ return 1; } return this.maze[y][x]; } /* * 判断是否是墙 * */ public boolean isWall(int x,int y){ return (this.getPositionValue(x, y)==1); } /* * 得到x的最大值,列数-1 * */ public int getMaxX(){ return this.maze[0].length-1; } /* * 得到y的最大值,行数-1 * */ public int getMaxY(){ return this.maze.length-1; } /* * 评估采取的路径,基于踩到的正确地砖的数目 * route是路线,Arrlist类型,里面的数组代表的是经过的坐标点 * */ public int scoreRoute(ArrayList<int[]> route){ int score = 0; boolean visited[][] = new boolean[this.getMaxY()+1][this.getMaxX()+1]; for(Object routeStep:route){ int step[] = (int[])routeStep; if(this.maze[step[1]][step[0]]==3 && visited[step[1]][step[0]]==false){ score++; //已经访问过 visited[step[1]][step[0]] = true; } } return score; } }
/** * Project Name:GeneticAlgorithm * File Name:Robot.java * Package Name:com.louis.rebot * Date:2017年9月24日上午9:38:50 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ package com.louis.robot; import java.util.ArrayList; /** * ClassName:Robot * Function: 机器人类 * Reason: TODO ADD REASON. * Date: 2017年9月24日 上午9:38:50 * @author michael * @version * @since JDK 1.7 * @see */ public class Robot { //定义方向 private enum Direction{NORTH,EAST,SOUTH,WEST}; private int xPosition; private int yPosition; //下一步前往的方向 private Direction heading; //最大移动步数 int maxMoves; //当前移动了多少步 int moves; //传感器的值 private int sensorVal; //传感器行为数组 private final int sensorActions[]; //迷宫 private Maze maze; //行走路线 private ArrayList<int[]> route; public Robot(int[] sensorActions, Maze maze, int maxMoves){ this.sensorActions = this.calcSensorActions(sensorActions); this.maze = maze; int startPos[] = this.maze.getStartPosition(); this.xPosition = startPos[0]; this.yPosition = startPos[1]; this.sensorVal = -1; this.heading = Direction.EAST; this.maxMoves = maxMoves; this.moves = 0; this.route = new ArrayList<int[]>(); this.route.add(startPos); } //基于传感器的输入运行机器人的行为 public void run(){ while(true){ this.moves++; //机器人的下一步移动到为0 if (this.getNextAction() == 0) { return; } //如果到达目的地 if (this.maze.getPositionValue(this.xPosition, this.yPosition) == 4) { return; } //如果步数大于最大步数 if (this.moves > this.maxMoves) { return; } //继续往前走 this.makeNextAction(); } } /* * 将字符串类型的传感器数据映射成行为 * */ private int[] calcSensorActions(int[] sensorActionsStr){ //多少个动作:一个动作,需要两位传感器数据 int numActions = (int)sensorActionsStr.length/2; int sensorActions[] = new int[numActions]; for (int sensorValue = 0; sensorValue < numActions; sensorValue++){ //每次循环,sensorAtion都初始化为0 int sensorAction = 0; if (sensorActionsStr[sensorValue*2] == 1){ sensorAction += 2; } if (sensorActionsStr[(sensorValue*2)+1] == 1){ sensorAction += 1; } //加入到行为数组中 sensorActions[sensorValue] = sensorAction; } return sensorActions; } /* * 下一步执行什么操作 * */ public void makeNextAction(){ // 向前移动 if (this.getNextAction() == 1) { int currentX = this.xPosition; int currentY = this.yPosition; // 向前移动取决于当前的机器人面朝哪 if (Direction.NORTH == this.heading) { this.yPosition += -1; if (this.yPosition < 0) { this.yPosition = 0; } } else if (Direction.EAST == this.heading) { this.xPosition += 1; if (this.xPosition > this.maze.getMaxX()) { this.xPosition = this.maze.getMaxX(); } } else if (Direction.SOUTH == this.heading) { this.yPosition += 1; if (this.yPosition > this.maze.getMaxY()) { this.yPosition = this.maze.getMaxY(); } } else if (Direction.WEST == this.heading) { this.xPosition += -1; if (this.xPosition < 0) { this.xPosition = 0; } } // 不能移动 if (this.maze.isWall(this.xPosition, this.yPosition) == true) { this.xPosition = currentX; this.yPosition = currentY; } else { if(currentX != this.xPosition || currentY != this.yPosition) { this.route.add(this.getPosition()); } } } // 顺时针移动 else if(this.getNextAction() == 2) { if (Direction.NORTH == this.heading) { this.heading = Direction.EAST; } else if (Direction.EAST == this.heading) { this.heading = Direction.SOUTH; } else if (Direction.SOUTH == this.heading) { this.heading = Direction.WEST; } else if (Direction.WEST == this.heading) { this.heading = Direction.NORTH; } } // 逆时针移动 else if(this.getNextAction() == 3) { if (Direction.NORTH == this.heading) { this.heading = Direction.WEST; } else if (Direction.EAST == this.heading) { this.heading = Direction.NORTH; } else if (Direction.SOUTH == this.heading) { this.heading = Direction.EAST; } else if (Direction.WEST == this.heading) { this.heading = Direction.SOUTH; } } // 重新设置传感器的值 this.sensorVal = -1; } /* * 得到下一步的操作 * */ public int getNextAction() { return this.sensorActions[this.getSensorValue()]; } /* * 得到传感器的值 * */ public int getSensorValue(){ // If sensor value has already been calculated if (this.sensorVal > -1) { return this.sensorVal; } boolean frontSensor, frontLeftSensor, frontRightSensor, leftSensor, rightSensor, backSensor; frontSensor = frontLeftSensor = frontRightSensor = leftSensor = rightSensor = backSensor = false; // 机器人是朝哪个方向走的 if (this.getHeading() == Direction.NORTH) { frontSensor = this.maze.isWall(this.xPosition, this.yPosition-1); frontLeftSensor = this.maze.isWall(this.xPosition-1, this.yPosition-1); frontRightSensor = this.maze.isWall(this.xPosition+1, this.yPosition-1); leftSensor = this.maze.isWall(this.xPosition-1, this.yPosition); rightSensor = this.maze.isWall(this.xPosition+1, this.yPosition); backSensor = this.maze.isWall(this.xPosition, this.yPosition+1); } else if (this.getHeading() == Direction.EAST) { frontSensor = this.maze.isWall(this.xPosition+1, this.yPosition); frontLeftSensor = this.maze.isWall(this.xPosition+1, this.yPosition-1); frontRightSensor = this.maze.isWall(this.xPosition+1, this.yPosition+1); leftSensor = this.maze.isWall(this.xPosition, this.yPosition-1); rightSensor = this.maze.isWall(this.xPosition, this.yPosition+1); backSensor = this.maze.isWall(this.xPosition-1, this.yPosition); } else if (this.getHeading() == Direction.SOUTH) { frontSensor = this.maze.isWall(this.xPosition, this.yPosition+1); frontLeftSensor = this.maze.isWall(this.xPosition+1, this.yPosition+1); frontRightSensor = this.maze.isWall(this.xPosition-1, this.yPosition+1); leftSensor = this.maze.isWall(this.xPosition+1, this.yPosition); rightSensor = this.maze.isWall(this.xPosition-1, this.yPosition); backSensor = this.maze.isWall(this.xPosition, this.yPosition-1); } else { frontSensor = this.maze.isWall(this.xPosition-1, this.yPosition); frontLeftSensor = this.maze.isWall(this.xPosition-1, this.yPosition+1); frontRightSensor = this.maze.isWall(this.xPosition-1, this.yPosition-1); leftSensor = this.maze.isWall(this.xPosition, this.yPosition+1); rightSensor = this.maze.isWall(this.xPosition, this.yPosition-1); backSensor = this.maze.isWall(this.xPosition+1, this.yPosition); } // Calculate sensor value int sensorVal = 0; if (frontSensor == true) { sensorVal += 1; } if (frontLeftSensor == true) { sensorVal += 2; } if (frontRightSensor == true) { sensorVal += 4; } if (leftSensor == true) { sensorVal += 8; } if (rightSensor == true) { sensorVal += 16; } if (backSensor == true) { sensorVal += 32; } this.sensorVal = sensorVal; return sensorVal; } /* * 返回机器人行走路径 * */ public ArrayList<int[]> getRoute(){ return this.route; } /* * 获取机器人坐标 * */ public int[] getPosition(){ return new int[]{this.xPosition, this.yPosition}; } /* * 机器人下一个方向 * */ private Direction getHeading(){ return this.heading; } /* * 打印机器人行走路径 * */ public String printRoute() { String route = ""; for (Object routeStep : this.route) { int step[] = (int[]) routeStep; route += "{" + step[0] + "," + step[1] + "}"; } return route; } }
package com.louis.robot; import com.sun.org.apache.bcel.internal.generic.PopInstruction; /** * Project Name:GeneticAlgorithm * File Name:GeneticAlgorithm.java * Package Name: * Date:2017年9月23日下午8:25:25 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ /** * ClassName:GeneticAlgorithm * Function: 遗传算法的核心 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午8:25:25 * @author michael * @version * @since JDK 1.7 * @see */ public class GeneticAlgorithm { /*种群大小*/ private int populationSize; /*变异概率*/ private double mutationRate; /*交叉概率*/ private double crossoverRate; /*精英个体数:种群中最强的个体数。保持原样,不参与交叉和变异*/ private int elitismCount; //锦标大小 private int tournamentSize; /*构造函数*/ public GeneticAlgorithm(int populationSize, double mutationRate, double crossoverRate, int elitismCount, int tournamentSize) { super(); this.populationSize = populationSize; this.mutationRate = mutationRate; this.crossoverRate = crossoverRate; this.elitismCount = elitismCount; this.tournamentSize = tournamentSize; } /* * 调用population的构造方法,使用染色体长度初始化种群 * */ public Population initPopulation(int chromosomeLength){ Population population = new Population(this.populationSize, chromosomeLength); return population; } /* * 计算一个个体的适应度 * */ public double calcFitness(Individual individual, Maze maze) { // 得到个体基因 int[] chromosome = individual.getChromosome(); // 得到适应度 Robot robot = new Robot(chromosome, maze, 100); robot.run(); int fitness = maze.scoreRoute(robot.getRoute()); // 保存适应度 individual.setFitness(fitness); return fitness; } /* * 遍历每个个体评估种群适应度 * */ public void evalPopulation(Population population, Maze maze) { double populationFitness = 0; //遍历每个个体统计种群总适应度 for (Individual individual : population.getIndividuals()) { populationFitness += this.calcFitness(individual, maze); } population.setPopulationFitness(populationFitness); } /* * 判断终止的条件,最大代数 * */ public boolean isTerminationConditionMet(int generationsCount, int maxGenerations) { return (generationsCount > maxGenerations); } /* * 选择交叉的个体 * */ public Individual selectParent(Population population) { // 创建用于锦标赛的种群 Population tournament = new Population(this.tournamentSize); //随机洗牌 population.shuffle(); // 随机向锦标赛插入个体 for (int i = 0; i < this.tournamentSize; i++) { Individual tournamentIndividual = population.getIndividual(i); tournament.setIndividual(i, tournamentIndividual); } // 返回最好的个体 return tournament.getFittest(0); } /* * 单点交叉:返回一个新的种群 * */ public Population crossoverPopulation(Population population) { // 重新创建一个种群 Population newPopulation = new Population(population.size()); // 按适应度遍历原来的种群 for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) { //因为已经按照适应度对种群进行排序了,所以这里是从小往大选择 Individual parent1 = population.getFittest(populationIndex); // 是否交叉,交叉率大于随机数并且pass掉精英个体 if (this.crossoverRate > Math.random() && populationIndex >= this.elitismCount) { // 初始化下一代个体 Individual offspring = new Individual(parent1.getChromosomeLength()); // 通过锦标赛选择第二个父个体 Individual parent2 = this.selectParent(population); // 随机产生交叉点 int swapPoint = (int) (Math.random() * (parent1.getChromosomeLength() + 1)); for (int geneIndex = 0; geneIndex < parent1.getChromosomeLength(); geneIndex++) { // 在交叉点前用1的基因,交叉点后用2的 if (geneIndex < swapPoint) { offspring.setGene(geneIndex, parent1.getGene(geneIndex)); } else { offspring.setGene(geneIndex, parent2.getGene(geneIndex)); } } // 将子个体加入到种群中 newPopulation.setIndividual(populationIndex, offspring); } else { // 没有交叉的个体直接加入到种群中,精英个体 newPopulation.setIndividual(populationIndex, parent1); } } return newPopulation; } /*变异得到新种群*/ public Population mutatePopulation(Population population){ Population newPopulation = new Population(this.populationSize); //通过适应度遍历当前种群 for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) { //按照从小到大的顺序选择个体 Individual individual = population.getFittest(populationIndex); //遍历个体的基因 for (int geneIndex = 0; geneIndex < individual.getChromosomeLength(); geneIndex++) { if(populationIndex>this.elitismCount){ //判断该基因是否变异 if(this.mutationRate>Math.random()){ int newGene = 1; if(individual.getGene(geneIndex)==1){ newGene = 0; } //变异基因 individual.setGene(geneIndex, newGene); } } } newPopulation.setIndividual(populationIndex, individual); } return newPopulation; } }
/** * Project Name:GeneticAlgorithm * File Name:RobotController.java * Package Name:com.louis.robot * Date:2017年9月24日上午9:39:50 * Copyright (c) 2017, 2692613726@qq.com All Rights Reserved. * */ package com.louis.robot; /** * ClassName:RobotController * Function: 执行类 * Reason: TODO ADD REASON. * Date: 2017年9月24日 上午9:39:50 * @author michael * @version * @since JDK 1.7 * @see */ public class RobotController { //设置最大的代 public static int maxGenerations = 1000; public static void main(String[] args) { //创建迷宫 Maze maze = new Maze(new int[][] { { 0, 0, 0, 0, 1, 0, 1, 3, 2 }, { 1, 0, 1, 1, 1, 0, 1, 3, 1 }, { 1, 0, 0, 1, 3, 3, 3, 3, 1 }, { 3, 3, 3, 1, 3, 1, 1, 0, 1 }, { 3, 1, 3, 3, 3, 1, 1, 0, 0 }, { 3, 3, 1, 1, 1, 1, 0, 1, 1 }, { 1, 3, 0, 1, 3, 3, 3, 3, 3 }, { 0, 3, 1, 1, 3, 1, 0, 1, 3 }, { 1, 3, 3, 3, 3, 1, 1, 1, 4 } }); //创建遗传算法 GeneticAlgorithm ga = new GeneticAlgorithm(200, 0.05, 0.9, 2, 10); Population population = ga.initPopulation(128); /* * 评估种群 * */ ga.evalPopulation(population, maze); int generation =1; /* * 开始进化 * */ while (ga.isTerminationConditionMet(generation, maxGenerations) == false) { // 打印种群中适应度最好的个体 Individual fittest = population.getFittest(0); System.out.println("G" + generation + " Best solution (" + fittest.getFitness() + "): " + fittest.toString()); // 交叉 population = ga.crossoverPopulation(population); // 变异 population = ga.mutatePopulation(population); // 评估种群 ga.evalPopulation(population, maze); // 迭代 generation++; } System.out.println("Stopped after " + maxGenerations + " generations."); Individual fittest = population.getFittest(0); System.out.println("Best solution (" + fittest.getFitness() + "): " + fittest.toString()); } }
posted on 2017-09-23 11:23 Michael2397 阅读(...) 评论(...) 编辑 收藏