【Android】A星算法演示代码(自定义view方便查看效果)

来源:互联网 发布:nginx error log 关闭 编辑:程序博客网 时间:2024/06/11 01:53

本博客所有文章皆为原创,欢迎转载,转载请注明出处,谢谢合作!
http://blog.csdn.net/shinnwxwx/article/details/50833150

以下代码需要理解A星算法,如果您还不了解什么是A星算法,可以前往此链接学习一下。
http://blog.csdn.net/shinnwxwx/article/details/50835517

介绍:本代码是A星算法的演示代码,使用自定义view实现效果,直接在android layout里引用即可查看效果,无需新建工程,一个类搞定a星。

你可以根据代码注释,灵活修改参数进行预览,【起】点和【终】点可以通过点击屏幕中的方块随意修改。

效果图:
这里写图片描述

不废话,直接上能用的源码,拉进工程里就能用啦!

public class ViewForCircle extends View {    int rect[][] = new int[20][40];// 地图矩阵 x , y    int nowx = 2;// 起点x    int nowy = 2;// 起点y    int endx = rect.length - 3;// 终点x    int endy = rect[0].length - 3;// 终点y    List<Point> list_open = new ArrayList<Point>();// 保存开放列表    List<Point> list_close = new ArrayList<Point>();// 保存关闭列表    List<Point> list_result = new ArrayList<Point>();// 保存最终路径列表    float paddingframe;// 与屏幕边缘的距离    float view_width;// 显示的宽度    float view_height;// 显示的高度    float every_width;// 每个方块的宽度    float every_height;// 每个方块的高度    Paint p;    int press_flag = 0;    FontMetrics fm;    Context context;    boolean isLoading = false;    boolean isPlaying = false;    int animNum = 0;// 动画步数    int speed = 100;// 动画速度    public class Point {        public int x;// x坐标        public int y;// y坐标        public int g;// 移动权重        public int h;// 目标权重        public int f;// 总权重        public Point fatherpoint;// 父节点        public Point(int x, int y, int g, int h, int f, Point fatherPoint) {            this.x = x;            this.y = y;            this.g = g;            this.h = h;            this.f = f;            this.fatherpoint = fatherPoint;        }    }    public ViewForCircle(Context context) {        super(context);        this.context = context;    }    public ViewForCircle(Context context, AttributeSet attrs) {        super(context, attrs);        this.context = context;    }    public ViewForCircle(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        this.context = context;    }    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        init();    }    public boolean onTouchEvent(MotionEvent event) {        if (event.getAction() == MotionEvent.ACTION_UP) {            if (event.getX() - paddingframe < 0 || event.getY() - paddingframe < 0                    || event.getX() - (paddingframe + view_width) > 0 || event.getY() - (paddingframe + view_height) > 0                    || isPlaying || isLoading)                return true;            int x = (int) ((event.getX() - paddingframe) / view_width * rect.length);            int y = (int) ((event.getY() - paddingframe) / view_height * rect[0].length);            if (isCanMove(x, y) == false)                return true;            press_flag++;            if (press_flag % 2 == 1) {                nowx = x;                nowy = y;            } else if (press_flag % 2 == 0) {                endx = x;                endy = y;            }            updateRun();        }        return true;    }    public void init() {        // 初始化属性        p = new Paint();        p.setTextAlign(Paint.Align.CENTER);        p.setTextSize(40);        p.setStyle(Paint.Style.FILL);        p.setAntiAlias(true);        fm = p.getFontMetrics();        paddingframe = 50;        view_width = getWidth() - paddingframe * 2;        every_width = view_width / rect.length;        view_height = getHeight() - paddingframe * 2;        every_height = view_height / rect[0].length;        // 创建障碍        updateObject(rect[0].length * rect.length / 4);        // 寻路        updateRun();    }    public void updateObject(int randomnum) {        Random rd = new Random();        List<Integer> list_object = new ArrayList<Integer>();        for (int i = 0; i < rect.length * rect[0].length; i++) {            if (i == nowy * rect.length + nowx)                continue;            else if (i == endy * rect.length + endx)                continue;            list_object.add(i);        }        for (int i = 0; i < randomnum; i++) {            int index = (rd.nextInt() >>> 1) % list_object.size();            int result = list_object.get(index);            rect[result % rect.length][result / rect.length] = 1;            list_object.remove(index);        }    }    public void updateRun() {        new Thread() {            public void run() {                handler.sendEmptyMessage(0);                list_result.clear();                list_open.clear();                list_close.clear();                // 将起点加入到关闭列表中                list_close.add(new Point(nowx, nowy, 0, Math.abs(nowx - endx) + Math.abs(nowy - endy),                        Math.abs(nowx - endx) + Math.abs(nowy - endy), null));                boolean isLooper = true;                while (isinEnd() == false && isLooper) {                    // 将符合条件的节点加入开放列表                    for (int i = 0; i < list_close.size(); i++) {                        addPoint(list_close.get(i));                    }                    // 更新关闭列表和开放列表中的节点                    if (updatePoint() == false) {                        list_result.clear();                        list_open.clear();                        list_close.clear();                        isLooper = false;                    }                }                // 将最终结果筛选,并保存到最终路径列表中                refreshPoint();                handler.sendEmptyMessage(1);            }        }.start();    }    Handler handler = new Handler() {        public void handleMessage(Message msg) {            if (msg.what == 0) {                // 显示loading                isLoading = true;            } else if (msg.what == 1) {                // 隐藏loading                isLoading = false;            } else if (msg.what == 2) {                // 刷新步数                if (animNum == list_result.size()) {                    isPlaying = false;                } else {                    animNum++;                }            }            invalidate();        }    };    public boolean updatePoint() {        Point minPoint = null;        for (int i = 0; i < list_open.size(); i++) {            if (minPoint == null)                minPoint = list_open.get(i);            else {                if (minPoint.f >= list_open.get(i).f)                    minPoint = list_open.get(i);            }        }        if (minPoint != null) {            list_close.add(new Point(minPoint.x, minPoint.y, minPoint.g, minPoint.h, minPoint.f, minPoint.fatherpoint));            list_open.remove(minPoint);            return true;        } else {            return false;        }    }    public void refreshPoint() {        // 获得最终路径列表        if (list_close.size() != 0) {            Point endPoint = list_close.get(list_close.size() - 1);            while (endPoint != null) {                list_result.add(0, endPoint);                endPoint = endPoint.fatherpoint;            }            animNum = 0;            isPlaying = true;        }    }    // 检查当前节点周围节点    public void addPoint(Point p) {        int arrow_up = 0;        int arrow_down = 0;        int arrow_left = 0;        int arrow_right = 0;        // 判断是否越界        if (isOut(p.x, p.y - 1) || isCanMove(p.x, p.y - 1) == false)            arrow_up = 1;        if (isOut(p.x, p.y + 1) || isCanMove(p.x, p.y + 1) == false)            arrow_down = 1;        if (isOut(p.x - 1, p.y) || isCanMove(p.x - 1, p.y) == false)            arrow_left = 1;        if (isOut(p.x + 1, p.y) || isCanMove(p.x + 1, p.y) == false)            arrow_right = 1;        // 如果arrow方向所对应的值仍然为0,那么判断节点是否在关闭列表中        for (int i = 0; i < list_close.size(); i++) {            int tempx = list_close.get(i).x;            int tempy = list_close.get(i).y;            if (arrow_up == 0 && tempx == p.x && tempy == p.y - 1) {                arrow_up = 1;            } else if (arrow_down == 0 && tempx == p.x && tempy == p.y + 1) {                arrow_down = 1;            } else if (arrow_left == 0 && tempx == p.x - 1 && tempy == p.y) {                arrow_left = 1;            } else if (arrow_right == 0 && tempx == p.x + 1 && tempy == p.y) {                arrow_right = 1;            }        }        // 如果arrow方向所对应的值仍然为0,那么判断节点是否在开放列表中        for (int i = 0; i < list_open.size(); i++) {            int tempx = list_open.get(i).x;            int tempy = list_open.get(i).y;            if (arrow_up == 0 && tempx == p.x && tempy == p.y - 1) {                arrow_up = 1;            } else if (arrow_down == 0 && tempx == p.x && tempy == p.y + 1) {                arrow_down = 1;            } else if (arrow_left == 0 && tempx == p.x - 1 && tempy == p.y) {                arrow_left = 1;            } else if (arrow_right == 0 && tempx == p.x + 1 && tempy == p.y) {                arrow_right = 1;            }        }        // 将符合条件的节点加入开放列表中        if (arrow_up == 0) {            list_open.add(new Point(p.x, p.y - 1, p.g + 1, Math.abs(p.x - endx) + Math.abs(p.y - 1 - endy),                    p.g + 1 + Math.abs(p.x - endx) + Math.abs(p.y - 1 - endy), p));        }        if (arrow_down == 0) {            list_open.add(new Point(p.x, p.y + 1, p.g + 1, Math.abs(p.x - endx) + Math.abs(p.y + 1 - endy),                    p.g + 1 + Math.abs(p.x - endx) + Math.abs(p.y + 1 - endy), p));        }        if (arrow_left == 0) {            list_open.add(new Point(p.x - 1, p.y, p.g + 1, Math.abs(p.x - 1 - endx) + Math.abs(p.y - endy),                    p.g + 1 + Math.abs(p.x - 1 - endx) + Math.abs(p.y - endy), p));        }        if (arrow_right == 0) {            list_open.add(new Point(p.x + 1, p.y, p.g + 1, Math.abs(p.x + 1 - endx) + Math.abs(p.y - endy),                    p.g + 1 + Math.abs(p.x + 1 - endx) + Math.abs(p.y - endy), p));        }    }    // x,y是否可以移动    private boolean isCanMove(int x, int y) {        if (rect[x][y] == 1)            return false;        return true;    }    // x,y是否出界    private boolean isOut(int x, int y) {        if (x < 0 || x >= rect.length || y < 0 || y >= rect[0].length)            return true;        else            return false;    }    // 终点x,y是否在关闭列表中    public boolean isinEnd() {        for (int i = 0; i < list_close.size(); i++) {            int tempx = list_close.get(i).x;            int tempy = list_close.get(i).y;            if (tempx == endx && tempy == endy) {                return true;            }        }        return false;    }    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawRGB(255, 255, 255);        // 显示障碍        p.setColor(Color.parseColor("#cccccc"));        for (int i = 0; i < rect.length; i++) {            for (int j = 0; j < rect[i].length; j++) {                if (rect[i][j] == 1)                    canvas.drawRect(paddingframe + every_width * i, paddingframe + every_height * j,                            paddingframe + every_width * (i + 1), paddingframe + every_height * (j + 1), p);            }        }        // 显示路径        p.setColor(Color.parseColor("#ff9912"));        for (int i = 0; i < list_result.size(); i++) {            if (i <= animNum) {                canvas.drawRect(paddingframe + (every_width * list_result.get(i).x),                        paddingframe + (every_height * list_result.get(i).y),                        paddingframe + (every_width * (list_result.get(i).x + 1)),                        paddingframe + (every_height * (list_result.get(i).y + 1)), p);            }        }        if (animNum == list_result.size()) {            isPlaying = false;        } else {            new Thread() {                public void run() {                    try {                        Thread.sleep(speed);                        handler.sendEmptyMessage(2);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }.start();        }        // 显示地图表格        p.setColor(Color.parseColor("#666666"));        for (int i = 0; i < rect[0].length + 1; i++) {            canvas.drawLine(paddingframe, paddingframe + every_height * i, paddingframe + view_width,                    paddingframe + every_height * i, p);        }        for (int i = 0; i < rect.length + 1; i++) {            canvas.drawLine(paddingframe + every_width * i, paddingframe, paddingframe + every_width * i,                    paddingframe + view_height, p);        }        // 显示起点,终点        canvas.drawText("起", paddingframe + every_width * nowx + every_width / 2,                paddingframe + every_height * nowy + every_height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent, p);        canvas.drawText("终", paddingframe + every_width * endx + every_width / 2,                paddingframe + every_height * endy + every_height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent, p);        if (isLoading) {            p.setColor(Color.parseColor("#ff0000"));            canvas.drawText("寻路中...请稍后...", getWidth() / 2, getHeight() / 2 + (fm.descent - fm.ascent) / 2 - fm.descent,                    p);        }    }}

具体功能性函数已经写好注释,大家可以直接在自己的layout里引用这个自定义的View设置好宽高位置即可,附上例子layout代码

<这里写上你的包名.ViewForCircle        android:id="@+id/circleview"        android:layout_width="fill_parent"        android:layout_height="fill_parent" />

只要这些步骤,你就可以在自己的项目里预览A星算法的全部过程,代码已经经过优化修改,注释写的比较完整,如果你还有什么问题,可以再此留言,我们一起交流与学习!

0 0
原创粉丝点击