连线达人: Javascript算法

今天闲来无事看到女票在玩一个小游戏连线达人, 感觉蛮有意思的.
看到她过不了关满脸着急就花了点时间✍搞了个小后门🤭
咳咳~, 闲话少说!!!
程序资源下载

连线达人到底是个啥😚

在这里插入图片描述
就是这么个小游戏, 从头部开始把所有的格子都连起来就算过关, 挺简单的吧😏

先分析分析!

首先要清楚几个东西:

  1. 地图先这么叫着吧中所有需要连接的格子有哪些? 坐标横向为行, 纵向为列
  2. 开始坐标在哪里? 结束坐标不确定
  3. 当前已经走过的格子是哪些? 嗯, 规则是不能交叉连线
  4. 当前坐标的上一步在哪里? 当然这是为了方便回退并再次尝试
  5. 是否已经通关

来, 看看界面!

根据以上逻辑, 做了简单界面
断点为第一次尝试
断点是第一次尝试失败!!! 别着急后面还有9999次🤭

界面使用HTML画出来

<div style="padding:15px 0;">
	<input id="rowIpt" type="number" min="1" max="10" step="1" placeholder="输入行数"></input>
	<input id="cellIpt" type="number" min="1" max="10" step="1"  placeholder="输入列数"></input>
	<input id="retryCount" value="10000" type="number" min="1" max="10000" step="1" placeholder="尝试次数"></input>
	<button id="gen">生成 [Enter]</button>
</div>

<div class="container">
	<div class="row">
		<div class="cell road startPoint"></div>
		<div class="cell road"></div>
		<div class="cell road"></div>
		<div class="cell road"></div>
		<div class="cell road"></div>
		<div class="cell road"></div>
	</div>
</div>

<div class="menus">
	<div data-key='49'>道路[1]</div>
	<div data-key='50'>开始点[2]</div>
	<div data-key='51'>开始计算[3]</div>
</div>

<dl>
	<dt>结果</dt>
	<dd id="result"></dd>
</dl>
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>

样式表在这里

.cell {display:inline-block;}
.container > .row div {border:1px solid #aaa;}
.container > .row {display:flex; height:50px;}
.container > .row > .cell {flex:1; cursor:pointer; color:#f00; text-align:center;}
.container > .row > .cell:hover {border-color:#f00;}
.container {width:300px;}
.road {background:#0f0;}
.startPoint {background:#00f;}
.menus > * {display:inline-block; margin:10px; padding:12px; cursor:pointer; border:1px solid #aaa; background:#eee;}
.menus > *:hover {background:#ddd;}
.menus .active {background:#1fad43;}

逻辑怎样实现的?

先绘制地形图整张地图的所有格子, 截图示例是6*6的方格. (输入对应的行/列数量后按Enter键).
在这里插入图片描述
然后按大键盘的1键标记需要连接的方块♦有哪些, 绘制完成后再按大键盘2键指定开始方块是那个坐标
在这里插入图片描述
接着指定尝试次数, 路径越复杂尝试次数需要越大, 同时花费的时间越多. 上图指定尝试次数为10万
惭愧~, 作者试过1万次解不出来 T_T

手术刀准备好, 开始解剖

打开浏览器调试工具通常是F12, 并将Breakpoint设置到失败时回退上一步的位置.

...
// 所有方向都不通
// 回到上一步, 并清除当前已通过点
var dir = $el.attr("data-from");
$el.removeAttr("data-from").text('');
var prevPath = pathArr.pop();
delete pathMap[pathKey]; // 删除无效路径

// 计算下一个开始位置(当前位置前一步)
path = prevPath;
...

在这里插入图片描述

你从哪里来?

程序首次运行时,当前位置就是起始位置

var $el= $('.startPoint').attr('data-from', 'startPoint');
var sps = getPoint($el); // 当前点的坐标(rowIndex/ri,cellIndex/ci)

要到哪里去(核心逻辑)?

从当前点出发到达下一个点有4个方向。同时要指出后退方向,在失败时需要回到上一个点尝试其他路径。

var dirs = {up:'↑', down:'↓', left:'←', right:'→'};// 显示走过的路
var dirsRevers = {up:'down', down:'up', left:'right', right:'left'};// 方向反转

出发之前先真理好行李
point:今晚在哪落脚
fromDir:昨晚在哪落脚,有机会回去找老板开发票
toDir:接下来准备去哪呢?要记得好马不吃回头草

{
	point:{ri:number, ci:number},
	fromDir:string, // 'start' + dirs.keys
	toDir:{
		up:boolean, // true-已尝试, false-未尝试, null-此路不通
		down:boolean,
		left:boolean,
		right:boolean
	}
}

有句话叫不撞南墙不回头,所以呢~走起。我们需要在4个方向不断尝试(转角遇到爱),直到撞墙。从dirs各个方向前进一步。

var hasNext = false;
for (var k in dirs) {

	// 跳过已尝试
	switch (path.toDir[k]) {
		case true:
		case null: continue;
	}

	// 不允许走回头路
	if (dirsRevers[k] == $el.attr('data-from')) {path.toDir[k]=null; continue;}

	var nextSps = nextPoint(k, sps);
	if (!nextSps) {path.toDir[k]=null; continue;}

	var $row = $('.row:eq('+nextSps.ri+')');
	if (!$row.length) {path.toDir[k]=null; continue;}

	var $cell = $row.find('.cell:eq('+nextSps.ci+')');
	if (!$cell.hasClass('road')) {path.toDir[k]=null; continue;}

	// 不允许重复
	if ($cell.attr('data-from')) {path.toDir[k]=null; continue;}

	$el.text(dirs[k]);
	$cell.attr('data-from',k);
	sps = nextSps;
	$el = $cell;

	hasNext = true;
	path.toDir[k] = true;
	path.fromDir = k;
	break;
}

找到今晚的落脚点了吗?当然~

...
$el.text(dirs[k]);
$cell.attr('data-from',k);
sps = nextSps;
$el = $cell;

hasNext = true;
path.toDir[k] = true;
path.fromDir = k;
...

一定要记得不要鬼打墙,绕进死胡同。

// 跳过已尝试
switch (path.toDir[k]) {
	case true:
	case null: continue;
}

如果不小心走到悬崖峭壁还是原路返回,去上个路口看看有没有别的出路

// 所有方向都不通
// 回到上一步, 并清除当前已通过点
var dir = $el.attr("data-from");
$el.removeAttr("data-from").text('');
var prevPath = pathArr.pop();
delete pathMap[pathKey]; // 删除无效路径

// 计算下一个开始位置(当前位置前一步)
path = prevPath;
sps = nextPoint(dirsRevers[dir], path.point);
$el = $('.row:eq('+sps.ri + ') .cell:eq('+sps.ci+')');
$el.text('');

**哇哈环球旅游结束**,当然这一生不可能就在这里打转儿总还得找点别的事做。所以,当然要限制尝试的次数

// 获取最大尝试次数
var max = $('#retryCount').val()||0;
max = Math.max(0, max);

// 控制尝试次数防止死循环
var i = 0;
while(max > ++i) {
	...
	if (pathArr.length == roads.length) break;
	...
}

上面这段逻辑看懂了,那么恭喜你可以去问老板涨工资啦
咳咳~当然是开玩笑😝

多尝试几次就好啦.

在这里插入图片描述
仅以此献给不断学习的自己!如有疑问欢迎探讨🎇

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值