JS+H5可视化广度优先算法

源码在效果图后面 

可标记 障碍 起始点 终点 

点击寻路按钮后,表格上会自动出现一条蓝色最佳路径(加了一格一格显示的动画)

以下是效果图  橙色起点 绿色终点 红色障碍物

6b1d74120387425290903666de0e3a66.png

 以下是寻路结果

583ce5caaed04353865f6f53cdf9cc9f.png 源代码

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=0.9">
    <title>广度优先搜索算法</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }

        #grid {
            display: grid;
            grid-template-columns: repeat(8, 50px);
            grid-template-rows: repeat(8, 50px);
            gap: 1px;
            background-color: gray;
        }

        .cell {
            width: 50px;
            height: 50px;
            background-color: white;
            border: 1px solid #ccc;
            cursor: pointer;
        }

        .cell.obstacle {
            background-color: red;
        }

        .cell.start {
            background-color: orange;
        }

        .cell.end {
            background-color: green;
        }

        .cell.visited {
            background-color: lightpurple;
        }

        .cell.path {
            background-color: blue;
        }

        #buttons {
            margin: 20px 0;
        }

        button {
            padding: 10px 15px;
            margin: 0 5px;
            border: none;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            cursor: pointer;
            transition: background-color 0.3s;
        }

        button:hover {
            background-color: #ddd;
        }

        #markObstacle {
            background-color: red;
            color: white;
        }

        #reset {
            background-color: green;
            color: white;
        }

        #markStart {
            background-color: orange;
            color: white;
        }

        #markEnd {
            background-color: blue;
            color: white;
        }

        #startSearch {
            background-color: purple;
            color: white;
        }
    </style>
</head>

<body>
    <div id="grid"></div>
    <div id="buttons">
        <button id="markObstacle">标记障碍物</button>
        <button id="reset">重置</button>
        <button id="markStart">标记起点</button>
        <button id="markEnd">标记终点</button>
        <button id="startSearch">开始寻路</button>
    </div>

    <script>
        const OBSTACLE = 1;
        const START = 2;
        const END = 3;
        const VISITED = 4;
        const PATH = 5;

        let grid = Array.from({ length: 8 }, () => Array(8).fill(0));
        let startCell = null;
        let endCell = null;

        const gridElement = document.getElementById('grid');

        // 创建格子
        for (let i = 0; i < 8; i++) {
            for (let j = 0; j < 8; j++) {
                const cell = document.createElement('div');
                cell.classList.add('cell');
                cell.dataset.row = i;
                cell.dataset.col = j;
                cell.addEventListener('click', () => handleCellClick(i, j));
                gridElement.appendChild(cell);
            }
        }

        function handleCellClick(row, col) {
            const cell = gridElement.children[row * 8 + col];

            if (cell.classList.contains('obstacle')) {
                cell.classList.remove('obstacle');
                grid[row][col] = 0;
            } else if (cell.classList.contains('start')) {
                alert('起点已存在,请先重置或选择其他格子');
            } else if (cell.classList.contains('end')) {
                alert('终点已存在,请先重置或选择其他格子');
            } else if (cell.classList.contains('visited') || cell.classList.contains('path')) {
                alert('此格子已被访问或是路径');
            } else {
                if (markingMode === 'obstacle') {
                    cell.classList.add('obstacle');
                    grid[row][col] = OBSTACLE;
                } else if (markingMode === 'start') {
                    if (startCell) {
                        grid[startCell.row][startCell.col] = 0;
                        gridElement.children[startCell.row * 8 + startCell.col].classList.remove('start');
                    }
                    cell.classList.add('start');
                    grid[row][col] = START;
                    startCell = { row, col };
                } else if (markingMode === 'end') {
                    if (endCell) {
                        grid[endCell.row][endCell.col] = 0;
                        gridElement.children[endCell.row * 8 + endCell.col].classList.remove('end');
                    }
                    cell.classList.add('end');
                    grid[row][col] = END;
                    endCell = { row, col };
                }
            }
        }

        let markingMode = '';

        document.getElementById('markObstacle').onclick = () => markingMode = 'obstacle';
        document.getElementById('markStart').onclick = () => markingMode = 'start';
        document.getElementById('markEnd').onclick = () => markingMode = 'end';
        document.getElementById('reset').onclick = resetGrid;
        document.getElementById('startSearch').onclick = startSearch;

        function resetGrid() {
            grid = Array.from({ length: 8 }, () => Array(8).fill(0));
            startCell = null;
            endCell = null;
            Array.from(gridElement.children).forEach(cell => {
                cell.className = 'cell';
            });
        }

        function startSearch() {
            if (!startCell || !endCell) {
                alert('请标记起点和终点');
                return;
            }

            const queue = [startCell];
            const visited = new Set();
            visited.add(`${startCell.row},${startCell.col}`);

            const parentMap = {};

            while (queue.length > 0) {
                const current = queue.shift();
                const { row, col } = current;

                if (row === endCell.row && col === endCell.col) {
                    reconstructPath(parentMap, current);
                    return;
                }

                for (const [dx, dy] of [[-1, 0], [1, 0], [0, -1], [0, 1]]) {
                    const newRow = row + dx;
                    const newCol = col + dy;

                    if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8 &&
                        grid[newRow][newCol] !== OBSTACLE && !visited.has(`${newRow},${newCol}`)) {
                        queue.push({ row: newRow, col: newCol });
                        visited.add(`${newRow},${newCol}`);
                        parentMap[`${newRow},${newCol}`] = current;
                        gridElement.children[newRow * 8 + newCol].classList.add('visited');
                    }
                }
            }
            alert('未找到路径');
        }

        function reconstructPath(parentMap, end) {
            let current = end;
            const path = [];

            while (current) {
                path.push(current);
                current = parentMap[`${current.row},${current.col}`];
            }

            // 反转路径数组
            path.reverse();

            // 逐个显示路径
            path.forEach((cell, index) => {
                setTimeout(() => {
                    const { row, col } = cell;
                    gridElement.children[row * 8 + col].classList.add('path');
                }, index * 100); // 每个格子延迟100毫秒
            });
        }
    </script>
</body>

</html>

 

 

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值