<template>
<div>
<!-- 按钮用于生成新地图 -->
<button @click="generateMap">Generate Map</button>
<!-- 显示地图的容器 -->
<div class="grid">
<!-- 循环生成行 -->
<div v-for="(row, rowIndex) in grid" :key="rowIndex" class="row">
<!-- 循环生成每一行中的单元格 -->
<div v-for="(cell, colIndex) in row" :key="colIndex" :class="getClass(cell)" class="cell"></div>
</div>
</div>
<!-- 显示步数 -->
<div v-if="steps !== null">本轮路程: {{ steps }} 格</div>
</div>
</template>
<script>
export default {
data() {
return {
grid: [], // 存储地图数据
start: { x: 0, y: 0 }, // 起点坐标
end: { x: 7, y: 7 }, // 终点坐标
steps: null, // 步数
};
},
methods: {
generateMap() {
this.steps = null; // 重置步数
// 随机生成起点和终点
this.start = { x: Math.floor(Math.random() * 8), y: Math.floor(Math.random() * 8) };
this.end = { x: Math.floor(Math.random() * 8), y: Math.floor(Math.random() * 8) };
// 生成地图并确保起点和终点不是障碍物
this.grid = [];
for (let i = 0; i < 8; i++) {
const row = [];
for (let j = 0; j < 8; j++) {
row.push(Math.random() < 0.2 ? "obstacle" : "empty");
}
this.grid.push(row);
}
// 设置起点和终点
this.grid[this.start.y][this.start.x] = "start";
this.grid[this.end.y][this.end.x] = "end";
// 找到路径
this.findPath();
},
async findPath() {
// 调用 A* 算法寻找路径
const path = this.aStar();
// 如果没有找到路径,步数设为 0
if (!path) {
this.steps = 0;
return;
}
// 更新步数
this.steps = path.length - 1;
// 在路径上逐步移动并显示每一步
for (const [x, y] of path) {
if (this.grid[y][x] !== "start" && this.grid[y][x] !== "end") {
this.grid[y][x] = "path";
await this.sleep(300); // 每一步停留 300 毫秒
}
}
},
// 用于暂停指定的毫秒数
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},
// 根据单元格类型返回相应的 CSS 类
getClass(cell) {
switch (cell) {
case "start":
return "start";
case "end":
return "end";
case "obstacle":
return "obstacle";
case "path":
return "path";
default:
return "empty";
}
},
// A* 算法实现
aStar() {
// 获取邻居节点
const neighbors = (node) => {
const dirs = [
{ x: 1, y: 0 },
{ x: -1, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: -1 }
];
const result = [];
for (const dir of dirs) {
const x = node.x + dir.x;
const y = node.y + dir.y;
// 确保邻居节点在地图范围内且不是障碍物
if (x >= 0 && x < 8 && y >= 0 && y < 8 && this.grid[y][x] !== 'obstacle') {
result.push({ x, y });
}
}
return result;
};
// 计算启发式估计(曼哈顿距离)
const heuristic = (a, b) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
// 初始化起始节点
const startNode = { ...this.start, g: 0, h: heuristic(this.start, this.end), f: 0, parent: null };
startNode.f = startNode.g + startNode.h;
const openList = [startNode]; // 开放列表
const closedList = []; // 关闭列表
// A* 算法主循环
while (openList.length > 0) {
// 按照 f 值对开放列表排序
openList.sort((a, b) => a.f - b.f);
const currentNode = openList.shift(); // 取出 f 值最小的节点
closedList.push(currentNode); // 将节点加入关闭列表
// 如果到达终点,返回路径
if (currentNode.x === this.end.x && currentNode.y === this.end.y) {
const path = [];
let temp = currentNode;
while (temp) {
path.push([temp.x, temp.y]);
temp = temp.parent;
}
return path.reverse();
}
// 处理当前节点的每个邻居节点
for (const neighbor of neighbors(currentNode)) {
if (closedList.find(n => n.x === neighbor.x && n.y === neighbor.y)) {
continue; // 跳过已经处理的节点
}
const gScore = currentNode.g + 1; // 计算 g 值
const existingNode = openList.find(n => n.x === neighbor.x && n.y === neighbor.y);
if (!existingNode || gScore < existingNode.g) {
// 如果邻居节点是新的或找到更短的路径
const neighborNode = { ...neighbor, g: gScore, h: heuristic(neighbor, this.end), f: 0, parent: currentNode };
neighborNode.f = neighborNode.g + neighborNode.h;
if (!existingNode) {
openList.push(neighborNode); // 加入开放列表
} else {
existingNode.g = neighborNode.g;
existingNode.h = neighborNode.h;
existingNode.f = neighborNode.f;
existingNode.parent = neighborNode.parent;
}
}
}
}
return null; // 无法找到路径
}
},
mounted() {
// 组件挂载后生成初始地图
this.generateMap();
},
};
</script>
<style>
/* 设置地图的网格布局 */
.grid {
display: grid;
grid-template-columns: repeat(8, 40px);
grid-gap: 2px;
}
/* 每行的布局 */
.row {
display: contents;
}
/* 设置单元格的样式 */
.cell {
width: 40px;
height: 40px;
border: 1px solid #ccc;
}
/* 空单元格的背景颜色 */
.empty {
background-color: white;
}
/* 障碍物单元格的背景颜色 */
.obstacle {
background-color: brown;
}
/* 起点单元格的背景颜色 */
.start {
background-color: blue;
}
/* 终点单元格的背景颜色 */
.end {
background-color: green;
}
/* 路径单元格的背景颜色 */
.path {
background-color: yellow;
}
</style>
关于A star 算法的地图障碍物起点到终点
最新推荐文章于 2024-06-22 21:53:36 发布