关于A star 算法的地图障碍物起点到终点

<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>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值