遗传编程GP-地图路径寻路

本文介绍的是基于GP,并非A*算法,算是另类实现吧。

先看看地图定义,在文本文件中定义如下字符串,代表30列11行大小的地图

初始位置在左上角(0,0) ,值为1的是允许走的通的路,目标位置为右下角(29,10)

1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1   

算法运行效果如下:

"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.2\lib\idea_rt.jar=54171:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;C:\Research-Code\demo1\target\classes;C:\Users\McKay\.m2\repository\io\jenetics\jenetics\5.1.0\jenetics-5.1.0.jar;C:\Users\McKay\.m2\repository\io\jenetics\jenetics.ext\5.1.0\jenetics.ext-5.1.0.jar;C:\Users\McKay\.m2\repository\io\jenetics\jenetics.prog\5.1.0\jenetics.prog-5.1.0.jar;C:\Users\McKay\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar" MapGame.GameDemo
1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
G: 15769
--------------------
map-->Right-->Right-->Right-->Right-->Right-->Down-->Down-->Down-->Left-->Down-->Down-->Left-->Down-->Down-->Right-->Right-->Right-->Right-->Right-->Down-->Down-->Down-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->
E: 1320.0

Process finished with exit code 0

这边由于是套遗传编程,因此会定义几个固定操作算子:上移、下移、左移、右移;看看上移算子代码:

public class GoUpOp implements Op<TempMapInfo> {
    private MapController mapController;              //地图控制工具类,比如判断能否移动到某个坐标、是否完成地图等
    public GoUpOp(MapController mapController) {
        this.mapController=mapController;
    }

    @Override
    public String name() {
        return "Up";
    }

    @Override
    public int arity() {
        return 1;
    }

    @Override
    public String toString() {
        return "Up";
    }

    @Override
    public TempMapInfo apply(TempMapInfo[] tempMapInfos) {
        TempMapInfo newInfo=tempMapInfos[0].cloneMe();        //需要深度克隆,防止多线程对象直接互相影响

        if(newInfo.currentLocationY==0)
        {
            newInfo.score-=1000;                      //已经在最上方了,不能再做上移动作了
            newInfo.tag+="-UP";                       //惩罚分,扣除1000分
            return newInfo;
        }
        if(!mapController.canMove2(newInfo.currentLocationX, newInfo.currentLocationY-1))    //是否上移位置是路
        {
            newInfo.score-=1000;                                      //惩罚扣除1000分
            newInfo.tag+="-UP";
            return newInfo;
        }

        newInfo.score+=10;                      //可以走,奖励10分
        newInfo.currentLocationY--;                 //递减y坐标
        if(newInfo.visited.contains(newInfo.currentLocationX+","+newInfo.currentLocationY))    //不能重复访问点
            newInfo.score-=1000;
        else
            newInfo.visited.add(newInfo.currentLocationX+","+newInfo.currentLocationY);

        if(mapController.isSuccess(newInfo.currentLocationX, newInfo.currentLocationY))      //判断是否地图完成
            newInfo.score+=1000;
        newInfo.tag+="-UP";
        return newInfo;
    }

}  

  

下面需要将这些操作算子嵌进GP中:

public static void main(String[] args) {

        Integer[][] map=GetMap();
        dispalyMap(map);

        TempMapInfo mapInfo=new TempMapInfo();
        mapInfo.score=0;
        mapInfo.currentLocationX=0;
        mapInfo.currentLocationY=0;          //左上角为起点

        List<Op<TempMapInfo>> terminals=new ArrayList<>();
        terminals.add(Const.of("map", mapInfo));

        MapController mapController=new MapController(map);

        final ISeq<Op<TempMapInfo>> TMS = ISeq.of(terminals);
        final ISeq<Op<TempMapInfo>> OPS = ISeq.of(new GoLeftOp(mapController), new GoRightOp(mapController), new GoUpOp(mapController), new GoDownOp(mapController));
        final GameSearcher gameSearcher =  GameSearcher.of(
                                                            GameSearcher.codecOf(
                                                                    OPS, TMS, 20,
                                                                    t -> t.getGene().size() < 60
                                                            )
                                                );

        final Engine<ProgramGene<TempMapInfo>, Double> engine = Engine
                .builder(gameSearcher)
                .populationSize(500)
                .maximizing()
                .alterers(
                        new SingleNodeCrossover<>(0.1),
                        new Mutator<>(0.3),
                        new UniformCrossover<>(0.5)
                )
                .offspringSelector(new TournamentSelector<>(2))
                .survivorsSelector(new TournamentSelector<>())
                .build();

        final EvolutionResult<ProgramGene<TempMapInfo>, Double> er =
                engine.stream()
                        .limit(Limits.byExecutionTime(Duration.ofSeconds(60)))
                        .collect(EvolutionResult.toBestEvolutionResult());

        final ProgramGene<TempMapInfo> program = er.getBestPhenotype()
                .getGenotype()
                .getGene();

        final TreeNode<Op<TempMapInfo>> tree = program.toTreeNode();
        System.out.println("G: " + er.getTotalGenerations());
        printTree(tree.depthFirstStream().collect(Collectors.toList()));
        System.out.println("E: " + gameSearcher._fitness(tree));
    }

    private static void printTree(List<TreeNode<Op<TempMapInfo>>> lst) {
        System.out.println("--------------------");
        for(TreeNode<Op<TempMapInfo>> node:lst)
            System.out.print(node.getValue()+"-->");
        System.out.println();
    }  

上面的terminals变量是存放终结符的,此处是直接把操作动作放进去了,包含了分数、访问步骤、当前xy坐标等,只有1个变量

public class TempMapInfo {
    public int currentLocationX;
    public int currentLocationY;
    public double score;
    public List<String> visited=new ArrayList<>();
    public String tag="";

    public TempMapInfo()
    {
        visited.add("0,0");
    }

    public TempMapInfo cloneMe()
    {
        TempMapInfo info=new TempMapInfo();

        info.currentLocationX=this.currentLocationX;
        info.currentLocationY=this.currentLocationY;
        info.score=this.score;
        info.tag=this.tag;
        info.visited=new ArrayList<>();
        for(String i:this.visited)
            info.visited.add(i);

        return info;
    }
}

  

GameSearcher是对GP算法的编码、解码封装、计算分值,算是核心:
public final class GameSearcher
	implements Problem<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>, Double>
{

	private final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> _codec;

	private GameSearcher(
		final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec
	) {
		_codec = requireNonNull(codec);
	}

	@Override
	public Function<Tree<Op<TempMapInfo>, ?>, Double> fitness() {
		return this::_fitness;
	}

	@Override
	public Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec() {
		return _codec;
	}

	public double _fitness(final Tree<Op<TempMapInfo>, ?> program) {

		List<TempMapInfo> lst=new ArrayList<>();
		lst.add(new TempMapInfo());

		List<TempMapInfo> results=lst.stream().map(args -> Program.eval(program, args)).collect(Collectors.toList());

		double score=results.stream().mapToDouble(a->a.score).sum();              //这行是用来统计整个操作算子序列总得分用的,很重要
		return score;
	}

	public static GameSearcher of(
		final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec
	) {
		return new GameSearcher(codec);
	}

	public static Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>>
	codecOf(
		final ISeq<Op<TempMapInfo>> operations,
		final ISeq<Op<TempMapInfo>> terminals,
		final int depth,
		final Predicate<? super ProgramChromosome<TempMapInfo>> validator
	) {
		if (depth > 200 || depth < 0) {
			throw new IllegalArgumentException(format(
				"Tree depth out of range [0, 30): %d", depth
			));
		}

		return Codec.of(
			Genotype.of(ProgramChromosome.of(
				depth,
				validator,
				operations,
				terminals
			)),
			Genotype::getGene
		);
	}
}

  

算法介绍完毕,pom依赖如下:

<dependencies>
        <!-- https://mvnrepository.com/artifact/io.jenetics/jenetics -->
        <dependency>
            <groupId>io.jenetics</groupId>
            <artifactId>jenetics</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>io.jenetics</groupId>
            <artifactId>jenetics.ext</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>io.jenetics</groupId>
            <artifactId>jenetics.prog</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

原文地址:https://www.cnblogs.com/aarond/p/GPMap.html

时间: 2024-08-08 21:20:54

遗传编程GP-地图路径寻路的相关文章

遗传编程GP-拟合方程

一般都是用机器学习.梯度下降或sklearn.pytorch来做函数拟合运算,今天介绍遗传编程,或称基因编程/GP,来做这个计算 最终就是构造一棵树AST,来表示运算的先后.权重: 具体原理可以参考这篇文章:https://blog.csdn.net/ocd_with_naming/article/details/98901749 我们的目标是拟合这个函数: np.sin(x) + np.log(x) 图像为: 先来一段java代码,是加载训练数据的,x.y的一个list: private st

编程统计制定路径的文件格式

方法一: 1 #编程统计制定路径的文件格式 2 import os 3 format_file =dict() 4 count=0 5 for each in os.listdir('E:\\'): 6 count+=1 7 (former, latter) = os.path.splitext(each) 8 if latter not in format_file: 9 format_file[latter]=1 10 else: 11 format_file[latter]+= 1 12

客户端地图内寻路总结与优化

首先关于客户端的坐标体系: 菱形框是客户端使用的单位方格,也就是游戏里雷达显示的坐标.客户端中采用的等距视角,使用菱形方格能与平面的场景地图模拟出3D效果.红色矩形框则是客户端和服务端公用的坐标格. 寻路方法入口: bool StartFindPath(CPos start, CPos end, vector<Cvector2f>& path, int IgnoreSteps, int nRatio, bool bAnyDir, int nMaxStep) (下面讲解具体的寻路实现时涉

iOS百度地图路径规划和POI检索详细总结-b

路径规划.png 百度地图的使用 百度地图API的导入网上说了许多坑,不过我遇到的比较少,这里就放两个比较常见的吧.坑一: 奥联WIFI_xcodeproj.png 如上图所示,在infoplist里加入这个字段,而且这里还可以设置提示的内容.不加的话,嘿嘿嘿,期待你的尝试.坑二:如下图 Pasted_Graphic_jpg.png 导入百度地图API运行之后报上图错误大约18到20个左右,解决方法添加libstdc++.6.0.9 的库.填完坑之后看一下我们今天要演示的效果吧. 路线规划图.g

ios百度地图-路径规划

百度地图的路径规划功能, 在使用百度路径的时候,出现了一些小问题,在此,分享一下自己的最简单的一个路径小demo 当然,前面的百度配置问题,我就不和大家讲了,因为这方面的资料太多了!现在,我来介绍一下这个小demo AppDelegate.m文件如下, #import "AppDelegate.h" import "rootViewController.h" @implementation AppDelegate (BOOL)application:(UIAppli

高德地图路径规划

高德地图导航sdk的路径规划获取行程信息主要用到AMapNaviManager这个类 然后调下面的方法 /*! @brief 带起点的驾车路径计算 @param startPoints 起点坐标.支持多个起点,起点列表的尾点为实际导航起点,其他坐标点为辅助信息,带有方向性,可有效避免算路到马路的另一侧. @param endPoints 终点坐标.支持多个终点,终点列表的尾点为实际导航终点,其他坐标点为辅助信息,带有方向性,可有效避免算路到马路的另一侧. @param wayPoints 途经点

cocos creator基础-(二十九)动画编辑器编辑地图路径

思路 1.利用动画编辑器,设置一个路径,多个路径就编辑多个动画 2.用特定的代码对动画进行处理,获取到路径坐标,大佬已经写好代码,不用自己重复造轮子了(微元法求曲线长度) 获得动画路径的贝塞尔曲线方程 求得每一段贝塞尔曲线的长度 每隔一小段打一个点 最终生成一个路径 3.编写寻路脚本,挂载到物体上,让沿着路径移动 动画编辑 脚本挂载 // gen_map_path.js 动画路径转换坐标的代码 已经升级到2.x cc.Class({ extends: cc.Component, properti

Vue 高德地图 路径规划 画点

CDN 方式 <!--引入高德地图JSAPI --> <script src="//webapi.amap.com/maps?v=1.4.13&key=您申请的key值"></script> <!--引入UI组件库(1.0版本) --> <script src="//webapi.amap.com/ui/1.0/main.js"></script> 配置externals 文件路径 bu

0718百度地图路径

<!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>T