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

news2024/9/25 3:28:11

源码在效果图后面 

可标记 障碍 起始点 终点 

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

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

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>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1945891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「运费速查神器」精明买家必备!一键查询1688供应商发货费用

对于从事跨境买家还是国内电商买家&#xff0c;在选品时&#xff0c;需要全面考虑商品成本&#xff0c;发货费用是供应链成本的重要组成部分。 原来如果我们在1688选品看供应商发货运费&#xff0c;需要一个个单独点击到商品的详情页去查看&#xff0c;再选择具体的收货地、再…

【C# WInForm】将TextBox从输入框设置为文本框

1.需求情形&#xff1a; textbox作为最常用的控件之一&#xff0c;通常是用来输入文本信息或者显示文字&#xff0c;但是如果要在界面中显示大段文本&#xff0c;一个带有边框、可选中的文本样式似乎不合适。像这样&#xff1a; 我需要的是这段文字不仅能跨行&#xff0c;而且…

浏览器打开PDF卡在加载(侧边翻译插件打不开PDF)

如果你的浏览器安装了一些翻译插件&#xff0c;那么可能会导致PDF加载不出来 比如我的浏览器中安装了“侧边翻译”&#xff0c;而我在view Elsever的论文时出现了加载不出来的问题—— 仍然以此扩展为例&#xff0c;那么解决办法是&#xff1a; 取消勾选——

2023 N1CTF-n1proxy

文章目录 参考rsa握手rust_proxy源码公匙交换和签名会话钥匙后续通信生命周期和裸指针代码审计漏洞点 libc-2.27.so大致思路&#xff08;exp还有变化&#xff09;调试exp泄露libc写free_hook执行命令exp 参考 https://github.com/Nu1LCTF/n1ctf-2023/tree/main/pwn/n1proxy ht…

【数据结构】AVL树(平衡二叉搜索树)

文章目录 1.AVL树1.1 AVL树的概念1.2 AVL树节点的定义1.3 AVL树的插入1.4 AVL树的旋转1.4.1 左单旋1.4.2 右单旋1.4.3 右左双旋1.4.4 左右双旋 1.5 AVL树的平衡验证1.6 AVL树的删除1.7 AVL树的性能 1.AVL树 在前面&#xff0c;我们已经介绍过了二叉搜索树&#xff0c;也了解到…

03 capture软件操作界面和常用设置介绍04 capture软件自带元件库设置

03 capture软件操作界面和常用设置介绍&&04 capture软件自带元件库设置 第一部分 03 capture软件操作界面和常用设置介绍一、分辨率二、产品选择三、颜色设置四、格点设置 第二部分 04 capture软件自带元件库设置 第一部分 03 capture软件操作界面和常用设置介绍 一、…

初识c++:string类(2)

#本节主要讲解c&#xff1a;string类的模拟实现 全部代码的实现在最后面&#xff01;&#xff01;&#xff01;有需要的自己往下滑&#xff0c;自取&#xff01;&#xff01;&#xff01;1.string类的模拟实现 2.浅拷贝 3.深拷贝 目录 #本节主要讲解c&#xff1a;string类…

使用Ollama和OpenWebUI,轻松探索Meta Llama3–8B

大家好&#xff0c;2024年4月&#xff0c;Meta公司开源了Llama 3 AI模型&#xff0c;迅速在AI社区引起轰动。紧接着&#xff0c;Ollama工具宣布支持Llama 3&#xff0c;为本地部署大型模型提供了极大的便利。 本文将介绍如何利用Ollama工具&#xff0c;实现Llama 3–8B模型的本…

WEB前端10- Fetch API(同步/异步/跨域处理)

Fetch API Fetch API 可以用来获取远程数据&#xff0c;用于在 Web 应用程序中发起和处理 HTTP 请求。它基于 Promise&#xff0c;提供了一种简单而强大的方式来处理网络通信&#xff0c;替代了传统的 XMLHttpRequest。 Promise对象 Promise 对象是 JavaScript 中处理异步操…

Netty:基于NIO的 Java 网络应用编程框架

Netty 是一个被广泛使用的&#xff0c;基于NIO的 Java 网络应用编程框架&#xff0c;Netty框架可以帮助开发者快速、简单的实现客户端和服务端的网络应用程序。“快速”和“简单”并不用产生维护性或性能上的问题。Netty 利用 Java 语言的NIO网络编程的能力&#xff0c;并隐藏其…

C++ 鼠标轨迹API【神诺科技SDK】

一.鼠标轨迹模拟简介 传统的鼠标轨迹模拟依赖于简单的数学模型&#xff0c;如直线或曲线路径。然而&#xff0c;这种方法难以捕捉到人类操作的复杂性和多样性。AI大模型的出现&#xff0c;使得神诺科技 能够通过深度学习技术&#xff0c;学习并模拟更自然的鼠标移动行为。 二.…

Spring Security 介绍

1.概要 Spring Security是一个用于在Java应用程序中实现身份验证和访问控制的强大框架。它可以轻松地集成到任何基于Spring的应用程序中&#xff0c;提供了一套丰富的功能来保护应用程序的安全性。 https://spring.io/projects/spring-security/ demo:https://docs.spring.i…

Java使用AsposePDF和AsposeWords进行表单填充

声明&#xff1a;本文为作者Huathy原创文章&#xff0c;禁止转载、爬取&#xff01;否则&#xff0c;本人将保留追究法律责任的权力&#xff01; 文章目录 AsposePDF填充表单adobe pdf表单准备引入依赖编写测试类 AsposeWord表单填充表单模板准备与生成效果引入依赖编码 参考文…

Java | Leetcode Java题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; class Solution {public int hIndex(int[] citations) {int n citations.length;int left 0, right n - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > n - mid) {right mid - 1;} else {lef…

【Hot100】LeetCode—322. 零钱兑换

目录 题目1- 思路2- 实现⭐322. 零钱兑换——题解思路 3- ACM 实现 题目 原题连接&#xff1a;322. 零钱兑换 1- 思路 思路 其中 amount 是背包容量 ——> 其中 nums 数组代表的背包重量 2- 实现 ⭐322. 零钱兑换——题解思路 class Solution {public int coinChange(in…

计算机网络基础:3.DNS服务器、域名分类

一、DNS服务器 DNS服务器在网络中的作用类似于餐厅中的“顾客座位对照表”&#xff0c;它帮助前台&#xff08;路由器&#xff09;将顾客&#xff08;用户&#xff09;的请求转发到正确的餐桌&#xff08;目标设备&#xff09;。 (1)概念与原理 DNS的基本概念 DNS&…

构建智慧农业监管系统:架构设计与技术创新

随着农业现代化的推进和消费者对食品安全的关注增加&#xff0c;智慧农业监管系统的设计变得至关重要。本文将探讨如何利用先进的技术和创新的系统架构&#xff0c;确保农产品生产过程的透明性、安全性和合规性&#xff0c;为农业发展注入新的动力和保障。 ### 1. 系统架构概述…

信息收集Part3-资产监控

Github监控 便于收集整理最新exp或poc 便于发现相关测试目标的资产 各种子域名查询 DNS,备案&#xff0c;证书 全球节点请求cdn 枚举爆破或解析子域名对应 便于发现管理员相关的注册信息 通过Server酱接口接收漏洞信息 https://sct.ftqq.com/ https://github.com/easych…

go中map

文章目录 Map简介哈希表与Map的概念Go语言内建的Map类型Map的声明Map的初始化Map的访问Map的添加和修改Map的删除Map的遍历 Map的基本使用Map的声明与初始化Map的访问与操作Map的删除Map的遍历Map的并发问题实现线程安全的Map 3. Map的访问与操作3.1 访问Map元素代码示例&#…

生成树协议配置与分析

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、相关知识 1、生成树协议简介 生成树协议&#xff08;STP&#xff09;是一种避免数据链路层逻辑环路的机制&#xff0c;它通过信息交互识别环路并…