javaScript 实现BFS可视化(青春版)

我为什么要做这个?

无意间接触到了各种排序算法可视化的网页,想用以前学过的算法自己也弄一个可视化网页,那就从最简单的BFS开始好了

前言

这个网页还有很多bug没有解决目前也想不到好的方法,不过大致的功能已经差不多实现了


以下是本篇文章正文内容

一、网页大致样式

在这里插入图片描述

二、使用步骤

1.首先在白色边匡中选一个起点,以及一个终点,然后点击左上角的star就可以演示了

灰色背景是障碍物

2.演示

在这里插入图片描述

在这里插入图片描述


思路

1、js代码变量含义,

let box = document.getElementsByClassName("box")[0]; //获取根节点
let p = document.getElementsByTagName("p"); //获取提示
let btn = document.getElementsByTagName("button"); //获取按钮
let itemArray = new Array(); //每个坐标是不是障碍
let boxArray = new Array(); //获取每个坐标里的div
let r = 25; //初始化行
let l = 25; //初始化列
let vis = []; //每个点是否被访问过
let count = 0; //选择起点为1,选择终点为2
let point = new Object(); //保存起点终点
let step = []; //记录上一步的方向
let mov = [ //方向数组
	[0, 1],
	[1, 0],
	[-1, 0],
	[0, -1],
	/* [1, 1],
	[1, -1],
	[-1, 1],
	[-1, -1] */
];

2、首先绘制一个宽800px的大盒子,里面的单元格宽高为30px,

<body>
		<div class="box">
			
		</div>
		<div style="position: absolute;top: 100px;">
			<p>选择起点:</p>
			<p>选择终点:</p>
			<p>最少步数:</p>
		</div>
		<div style="position: absolute;top: 0px;">
			<button type="button">star</button>
		</div>
</body>
*{
			padding: 0;
			margin: 0;
		}
		.box{
			width: 800px;
			display: flex;
			flex-direction: row;
			flex-wrap: wrap;
			margin: 0 auto;
		}
		.item{
			font-size: 12px;
			text-align: center;
			color: #fff;
			width: 30px;
			height: 30px;
			border: 1px solid black;
			transition: all 2s;
		}
		button{
			width: 100px;
			height: 50px;
			display: block;
			
			top: 0;
		}

3、实现createItem方法创造子元素

/**
 *  @param {sting} str div背景颜色
 * @return {Object} 返回一个div 
 */
function createItem(str = "#fff") {
	let div = document.createElement("div");
	div.className = "item";
	div.style.backgroundColor = str;
	box.appendChild(div)
	return div;
}

4、实现createBranch方法创造25*25的地图

/**
 * @param {number} row  行
 * @param {number} column 列
 * 创建矩阵
 */
function createBranch(row, column) {
	for (let i = 0; i < row; i++) {
		let lsArray = [];
		boxArray[i] = [];
		vis[i] = [];
		for (let j = 0; j < column; j++) {
			let xx = parseInt(Math.random() * row)
			let yy = parseInt(Math.random() * column)
			if (Math.abs(i * j - xx * yy) <= 40) { //随机障碍物
				boxArray[i].push(createItem("gray"))
				lsArray.push(1)
			} else {
				boxArray[i].push(createItem())
				lsArray.push(0)
			}
			vis[i].push(0)
		}
		itemArray.push(lsArray)
	}
}

5、实现addDivListen方法为每个非障碍物单元格添加点击事件选择起始点

/**
 * @param {number} row
 * @param {number} column
 * 为每个格子添加事件
 */
function addDivListen(row, column) {
	for (let i = 0; i < row; i++) {
		for (let j = 0; j < column; j++) {
			if (!itemArray[i][j]) {
				//console.log(boxArray[i][j]);
				boxArray[i][j].addEventListener("click", () => {
					if (count == 0) { //如果count为0选择起点
						boxArray[i][j].style.backgroundColor = "red";
						p[0].innerHTML += `row:${i}--column:${j}`
						point.star = i;
						point.estar = j;
						count++;
					} else if (count == 1) { //如果count为1选择终点
						boxArray[i][j].style.backgroundColor = "green";
						p[1].innerHTML += `row:${i}--column:${j}`
						point.send = i;
						point.end = j;
						count++;
					} else console.log(point); //输出起始点
				})
			}
		}
	}
}

6、核心代码BFS,实现bfs思路很简单,难的是如何边寻路边修改dom元素,
参考:https://blog.csdn.net/qq_39542027/article/details/78893873

1,js是同步加载的
2,浏览器执行js程序,高于页面渲染
所以同步代码不能实现实时刷新dom元素
如何解决?使用定时器,直接看代码吧

function BFS(row, column) {
	let step = 0;     //最短步数
	let proxy = new Object(); //存起始点
	let queue = []; //申请队列  使用unshift和pop实现出队入队
	proxy.x = point.star;
	proxy.y = point.estar;
	proxy.k = 0;
	queue.push(proxy)
	vis[proxy.x][proxy.y] = 1;
	let f = true;
	return new Promise(resolve =>{      //使用异步函数就可以实现每寻路一次渲染一次dom
		setInterval(() => {
			while (queue.length > 0) {
				let p = queue[queue.length - 1];
				queue.pop();
				if (p.x == point.send && p.y == point.end) {
					boxArray[p.x][p.y].innerHTML = "终点";
					boxArray[p.x][p.y].style.backgroundColor = "black"
					step = p.k
					f = false;
					resolve(step)
				} else {
					if (!f) return;
					else {
						setTimeout(() => {
							for (let i = 0; i < 4; i++) {
								let xx = p.x + mov[i][0]
								let yy = p.y + mov[i][1] //判断下一个点是否越界,或者是否障碍物,或者是否被访问过
								if (xx >= 0 && yy >= 0 && xx < row && yy < column && (!vis[xx][yy]) && (!itemArray[xx][yy])) {
									boxArray[xx][yy].style.backgroundColor = "yellow"  //将这个点渲染黄色表示已经访问过
									vis[xx][yy] = 1;
									let pp = {};
									pp.x = xx;
									pp.y = yy;
									pp.k = p.k + 1;
									queue.unshift(pp)
								}
							}
						}, 300)
					}
				}
			}
		}, 1000)
	})
}

我也是刚学习异步函数的一些知识所以很多问题也不知道怎么解决,比如如果起点无法到达终点将没有提示

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值