这是一篇非技术类文章,仅仅是回顾自己这几年在开源项目上的工作,记录下一点点想法。我也并非技术类博主,不太会总结各个技术点,仅仅随想随记。
我接触开源已经有大概7、8个年头了吧,这期间也存在断断续续或是长期不活跃的状态。开源对于我来说,可能更多时候不是目的,而更像是记录,记录自己突然的一点想法,然后把它做完再把它保留起来。所以,很多时候,我写的东西其实并不是特别实用的东西,仅仅是自己想法的一个Demo吧。不管怎么说,写了几个小项目还是略有心得的,以下是关于自己的几个开源项目的来源和自己的想法。
# 开源的初尝试 - 迷宫寻址
大约在2014或2015年那会儿,我对开源完全没有想法,也从未想过要自己做些开源项目。对于选什么项目做,什么目的做更是没有概念。当年的Github对于我来说,其实和网盘无异,无非就是把原本自己放在U盘里的代码在线化而已。
一开始自己仅仅限制于写点小东西,比如[24计算器](https://github.com/mumuy/calc24/)这样的代码段来锻炼下自己的编程能力。
当时在自己完成以后,就在在琢磨一个问题:这个算法好像只是对数值进行计算而已,那如果是平面图形呢?于是想起了小时候喜欢在纸张上的杰作--迷宫!如果能写一个算法自动找出迷宫的路,会不会也挺有趣的?
于是乎,说干就干!当时的我并不知道什么 Dijkstra 和 A*算法,寻址对我来说也是朦胧的一个概念。当时的最初想法就是:我该如何在一个二维数组中,找到两个点的连线,并且它们是最短的解。既然是迷宫,一定是有墙和路的,我该如何在路的岔路口选择路线呢?
我的第一想法就是,每个路口都尝试下各个方向,那么每个路口都应该是一个新的开始对吧?这似乎和高中时的一个知识点很像!什么呢?你们猜猜?
我想很多人可能想不到,不卖关子了,是“波”。在高中的物理学中“波的传播”特性:波阵面上的任一点都是下一个波源。寻径的过程不就是波的传播过程吗?
算法的原理也很简单:
(1)首先记录第1步能到达的点把它们收集起来,就是第1代“波阵面”了;
(2)再递归记录第1代“波阵面”上的点走下1步能到达的点,它们就是第2代“波阵面”,以此类推;
(3)每走1步都把波阵面向的点收集起来,记录该点上一个点在哪里(类似于小狗沿路撒尿留下痕迹);
(4)等某一刻波碰到了终点,即代表寻找到了从起点到终点的解。
这时候只要把一路上记录的上一个点的坐标反向按顺序输出,不就是来时的路吗?而与此同时,并没有更早到达的点,那么它就是最短路径的解了!
项目开源地址:[https://github.com/mumuy/finder](https://github.com/mumuy/finder)
# 巧妙的算法运用 - Pacman吃豆人游戏
在写最短路径寻址的时候,我正在学 canvas的使用 ,对于一些 api 掌握没有很大把握,就想着做一个小游戏试试巩固下。直觉告诉我,最短的路径寻找在游戏一定是大有用处的!但是如果用它呢?我想起了经典的游戏一些游戏:围住神经猫、吃豆人……可是,这时候有个问题,我不会作图啊!围住神经猫看来没有戏了,于是我就选中了最容易靠代码画图实现的吃豆人~
吃豆人的寻径大体上就是 4 个幽灵如何抓玩家,问题是最短路径算法只能是一对一寻找。由于游戏设定一定是玩家跑的速度比 NPC 快的,如果只是单独 NPC 寻径追着玩家,那必然会出现几个 NPC 跟在玩家后面跑,这样的游戏体验将大打折扣。那么如何实现多个 NPC 相互配合呢?我想起了小时候和小伙伴追赶的游戏,第一反应是,如果我和几个小伙伴一起围堵一个人,那么当我在这个巷子发现有人已经在堵他了,那我一定是找下一个巷子包抄。那么这时候一起配合追赶的小伙伴对于我来说就是一堵墙吧?
于是乎,我有了清晰的实现逻辑:当 NPC 各自在寻找玩家的过程中,相互都把其他 NPC 当做游戏中的墙,然后利用最短路径算法去追玩家,这不就实现了几个 NPC“智能”的围堵逻辑?!(我真是个天才,哈哈哈)
另外在做游戏过程中发觉,一个游戏系统必然少不了对对象的管理,还加入了一些动画管理及事件绑定等操作。
项目演示地址:[https://passer-by.com/pacman/](https://passer-by.com/pacman/)
项目开源地址:[https://github.com/mumuy/pacman/](https://github.com/mumuy/pacman/)
# 在需求中完善工具库 - jQueryWidget
早期自己做项目,碰到轮播基本上都是从百度那里临时搜索些代码段,因为那时候也没Swiper这些还没有流行,而自己每次需求也不尽相同。所以每次做项目,几乎是又重新整,照常代码维护。于是,我产生了自己写插件的想法,因为我也实在没有经历每次都重新根据需求写一份代码。
而当时的我对如何写jQuery插件并没有概念,于是乎我到处搜索如何写插件,插件一般要如何写才易使用、易扩展。现在总结起来,主要是需要考虑这些问题:
1. 参数名、方法名的设计;如果命名不够规范,不够通俗易懂,那么对于用它的人将会是个灾难,对方并不能通过命名直觉地明白它的用法;
2. 内部方法或者事件的暴露;插件的用法并不是死的,用户或多或少需要在一定范围对插件的使用习惯进行业务性调整。适当的将插件内部的方法或者事件调用暴露出来自然必不可少了。
3. 模块化封装;当前前端工程化开发,有各种模块化开发方案,如何做好各种模块化方案也很重要。UMD就是将AMD、commonjs、浏览器script引用一起兼容的做法。
4. 参数的重载和重置;需要考虑用户传递不同形式的参数,如何传参和回调,如果窗口状态变化,如何重置内部参数。
在工作中每当碰到有个长期需要的功能,我就把它抽象出来,做成一个插件。如果下次碰到新的需求,就完善它。慢慢的积累,我就有了一个属于自己的插件库了。有了轮播、标签页、日期、浮动菜单、搜索建议、滚动条、对话框、城市三级联动、弹出层等等工具。之所所以选择开源,是自己用了觉得功能较为完备了,可以去让更多人使用了。并不是为了让更多人使用而去选择开源,毕竟这对于大多数开发者来说是再常见不过的代码了,无非是造了几个轮子罢了。
项目演示地址:[https://jquerywidget.com/](https://jquerywidget.com)
项目开源地址:[https://github.com/mumuy/widget/](https://github.com/mumuy/widget/)
# 开源数据解决痛点 - 行政区划数据
在做城市三级联动插件的时候,我碰到了一个问题:市面上大多数地区联动的插件数据并不是很新很全,很多都是好几年前的地名了。这对于做项目肯定是不够的,因为错误的地名可能让你的用户感到困惑。
于是,我用nodejs跑了下民政部和国家统计局的数据,将其汇总起来做成项目。我也是较早把它发布到Github。这也是我获得最多star的项目了,虽然后面陆陆续续有其他人做了类似的事情,而且获得了更多的关注。可以说,这个项目是因为当时解决了开发者对数据的痛点才得到了关注,并不是自己整理的数据有多全或者详细。
对于行政区划,应用的地方还是很多的,它可以对一些包含地名的数据进行标准化管理。可用户地址选择,或者身份证号码有效性验证等等。
项目演示地址:[https://passer-by.com/data_location/](https://passer-by.com/data_location/)
项目开源地址:[https://github.com/mumuy/data_location/](https://github.com/mumuy/data_location/)
# 无心插柳而成 - 浏览器判断
这个项目最开始就是为了识别360浏览器而写的一小段代码。后来觉得,既然最难搞的360都判断出来了,何不整理下,把其他常见的浏览器判断都收集起来,免去每次都加代码段重新判断。于是,我就有了一段专门判断各种浏览器的轮子脚本了
项目演示地址:[https://passer-by.com/browser/](https://passer-by.com/browser/)
项目开源地址:[https://github.com/mumuy/browser/](https://github.com/mumuy/browser/)
# 最复杂的工程 - 亲戚称呼计算器
这个项目的起源大致可以追溯到2015年末的时候,当时看到一则新闻在报道一个来自于中国香港的APP“三姑六婆计算器”。就是一个计算器模样的APP,简单的按几下按键,就可以计算出亲戚关系。我对这种具有“中国特色”的小玩意儿情有独钟,觉得科技不就是解决我们日常中的问题而诞生的吗?我大概尝试了点击测试,大致了解了他们的原理,就是简单的称呼对应关系的映射,用穷举的方式保存数据。然而我觉得这样的方式有点傻乎乎的,因为它并没有发挥“计算”的奥妙之处,仅仅是哈希映射单层的关系。
如果用户输入是别称呢?要知道中国的亲戚称呼有各式各样样的叫法,如果仅仅是哈希映射关系,无法做到完整,更无法拓扑出关系网来。
我想了好一阵子,应该以怎么样的数据结构去设计中国亲戚关系网络。这样的数据结构需要满足以下特点:
1. 一种关系链可以同时容纳多种称呼;比如爸爸,可以叫:老爸、爹地、老头子等等;
2. 能够通过称呼寻找多种关系链,比如舅公,可以是爸爸的舅舅、妈妈的舅舅、老公的舅舅;
3. 可以对关系链计算进行最简化计算;如果用户输入的称呼来回绕,可能把一层简单的关系描述复杂,需要对关系链进行最简化计算。
4. 需要根据称呼判断年龄大小和性别;这是个比较棘手的问题,比如堂哥的哥哥一定还是堂哥,不会是堂弟。而堂哥的弟弟就可能是堂哥或者堂弟。岳母的女儿可能是老婆、大小姨子,同时可以确定自己一定是男性。
最开始我的想法是每个节点都是一个对象,里面存着对应的称呼及属性,在计算时,这些对象组成一个链表结构,有个指针在根据用户输入在这个对象之间改变指针。然而如何精简这个数据结构却是我头疼的问题,我如何描述每个节点之间的关系,是否需要分配id?然后将这些id关联起来。
我开始了对id的设计工作。这样的id最好本身就包含关系的信息,可是“爷爷”本身他也是他儿子的爸爸呀?我该如何描述“爷爷”呢?这个关系那就应该以我为中心了吧!
于是,我将爷爷描述成了f,f (即爸爸的爸爸)。慢慢的,我用英文名称的首字母定义了大部分关系了,当时我想的只是把他们作为id把关系串起来,然后改变指针寻址。慢慢的,我意识到有点不对,既然这个id已经可以描述关系了,我直接处理它不就好了???为什么要需要作为对象的属性绑定呢。它的数据结构本身就字符串,我有没有办法将字符串进行最简计算呢?我想到了一个神器 - 正则表达式。
于是,我便才是了我这套算法的最基础构想,通过正则表达式缩减关系链表达式进行计算。关于我算法原理的详细说明可以参考:["亲戚关系计算器"算法实现](https://www.jianshu.com/p/74290f1ae838)
在长达7年的时间里,我不断有新的想法往这个项目里面添加,也参考了大量的书籍去收集各式各样的称呼。慢慢的,我发现它已经特别复杂而完备了。包含了数十个亲戚旁支,不仅仅可以查询自己和亲戚的关系,亦可以查你的两个亲戚之间如何称呼及合称等。
项目演示地址:[https://passer-by.com/relationship/](https://passer-by.com/relationship/)
项目开源地址:[https://github.com/mumuy/relationship/](https://github.com/mumuy/relationship/)
有人说,这个项目貌似前端也用不到,平时使用频率也很低呀,为啥要做它?我觉得吧,它更像是一个课题吧,一个实现自己想法的演示品。
网友评论