结果预览:
写小程序的原因
毕业之后(其实也不是), 不知道从什么时候开始, 不想把所有自由的时间用来肝游戏了, 还有总是有一些"不得不闲着"的时间, 于是今年年初就开始计划怎么度过这些时间, 除了游戏/看番, 还是多出来很多闲着的时间, 于是刷了一段时间leetcode
顺便在网上报了一个n4日语的课程, 就在这期间同学推荐了一个英语练习发音的小程序(明明是日语班学英语的还不少)…这样突然想到我为什么不也写一个日语主题的小程序, 于是就放弃了刷leetcode, 开始了小程序计划
一开始只是为了收集阴阳师式神台词语音以及同学们的录音, 后来才想到实现一个五十音主题的连连看, 或许可以帮助同学们记忆平假名和片假名
只是发布时大家都已经N4毕业了, 有点残念…
正题
为了方便理解我特地写了一个浏览器实验版本:
连连看-实验版
本文将围绕这个实验版带大家理解连连看算法, 顺便说明JS实现细节
有疑问可以到知乎上留言:
知乎的同篇文章
JavaScript实现源码:
连连看源码
内容:
如果你有耐心的话, 可以继续完善写一个属于自己的连连看!
那么, 分析开始
方块类型:
可以将以上方块类型分类:
▲按位置分类:
- 在直线上
- 不在直线上
▲按折点分类:
- 0折点
- 1折点
- 2折点
连线折点不超过2
每一个分类对应算法的一个分支(if), 同时也要考虑连接方向, 于是这样实现下来之后分支会变得异常的多!!!
开始我就是尝试这样实现, 写到2折点的时候我发现…
what the f**k (╯°Д°)╯︵ ┻━┻ 我在写什么鬼东西? 就没有更优雅的写法!?
改进的算法:
(你可能想到写一个暴力的递归!emm…你可以Fork尝试改写实现)
抑制住砸键盘的冲动以及经过一番思想的碰撞之后,发现了一个比较有趣的实现思路:
假设从A连接B
- 把B点往四个方向无阻挡延伸的点称为目标点
- 从A点顺时针(右-下-左-上)寻路
- 有交点:
- 无交点
这时候再分类的话, 只有两类:
- AB点的延伸有交点
- AB点的延伸无交点
与折点分类比较的话, 就是把0折和1折合并了, 并且简化了实现, 或者说对原算法进行了降维
算法实现:
概括:
- 计算目标点:
- (右-下-左-上)寻路
- 无交点时进行二次寻路
====================================
JavaScript实现
计算目标点:
//二维数组--储存方块的状态(true有效/false空白)
var fields = []
//定义储存目标点的数组
var this_lefts = []
var this_rights = []
var this_ups = []
var this_downs = []
//计算目标点
function initTargetPoint(this_row, this_col){
this_lefts = []
this_rights = []
this_ups = []
this_downs = []
var step_col = this_col
//计算左边
while (step_col > 0){
step_col -= 1
//非空白方块退出
if (fields[this_row][step_col]) break
this_lefts.push(this_row+","+step_col)
//例:this_lefts = ["2,2", "2,1", "2,0"]
}
step_col = this_col
while (step_col < max_col){
step_col += 1
if (fields[this_row][step_col]) break
this_rights.push(this_row+","+step_col)
}
var step_row = this_row
while (step_row > 0){
step_row -= 1
if (fields[step_row][this_col]) break
this_ups.push(step_row+","+this_col)
}
step_row = this_row
while (step_row < max_row){
step_row += 1
if (fields[step_row][this_col]) break
this_downs.push(step_row+","+this_col)
}
}
====================================
向右寻路:
//A点(row, col)-->B点(row, col):
//begin_col = A.col end_col = B.col
//fixed_row = A.row
function rightLink(begin_col, end_col, fixed_row){
console.log("----右")
var steps = [] //存储经过的路径方块点(row, col)
var step_col = begin_col
while (step_col < end_col){
step_col += 1
if (fields[fixed_row][step_col]) break
var row_col = fixed_row+","+step_col
steps.push(row_col)
//判断是否与(左目标点)有交点
var idx = this_lefts.indexOf(row_col)
if (idx != -1){
//(经过路径+交点到B点) = 全部路径
steps = steps.concat(this_lefts.slice(0, idx).reverse()) //为了路径有序进行reverse()
return steps
}
idx = this_ups.indexOf(row_col)
if (idx != -1){
steps = steps.concat(this_ups.slice(0, idx).reverse(