您的位置:首页 > 移动开发 > Android开发

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

2016-03-09 10:14 507 查看
本博客所有文章皆为原创,欢迎转载,转载请注明出处,谢谢合作!

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;

b11a
}

// 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星算法的全部过程,代码已经经过优化修改,注释写的比较完整,如果你还有什么问题,可以再此留言,我们一起交流与学习!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息