利用普普通通的游戏引擎实现普普通通的电梯调度算法
注:这是目前WebGL2.0支持的浏览器版本号列表
稀疏
如同在那个慵懒的午后,贴心地给你指出你代码块的错误的主程老大的头发
WebGL2.0这目前稀疏的浏览器支持,着实令人唏嘘,不过我们要说的不是WebGL2.0,而是
一个在游戏引擎中实现的电梯调度算法模拟
如果您的浏览器符合上图中的要求,就可以按住ctrl再点击上面这个标题,可以直接尝试浏览笔者的小团队正在制作的Unity项目(稍等,有疑问请继续看)
哦?怎么看符不符合要求?
允许笔者再翻译一下这个符合要求的浏览器,目前主流的火狐和Chrome都支持,只要您更新到了最新的版本。当然如果您使用Opera的话,恭喜您最新版也是可以直接浏览该页面的(那么我猜IE应该是没人使用的,这里就略过了(逃))
话不多说
本身这个项目只是一个半成品,但是已经达到了作业要求因此才有了这篇blog,从26号作业发布至今,笔者一直在持续维护这个小东西,前几日的工作具体在项目库的push里有一定的说明,但是作为说明就太过简洁了,感兴趣的各位可以点击这里,因此也是为了记录工作的新进展才有了这篇blog,目前就先记录这么多(ps:如果对截图有需要的话,或者提出什么建议的话敬请留言)
再多说点
如果您进入了项目预览的网页,那么具体的操作方式是:
左键点击、右键旋转视角、Lshift视角降低、Space视角升高、WASD控制镜头移动、滚轮控制视角移动速度
左上角新增了一个可点击的UI,用于切换正交和透视视图,默认透视,推荐切换成正交视图可以观察的更清晰
一些说明
游戏引擎?
是的,当时接到这个作业在不到十分钟的时间就拿定了这个主意,主要的原因在于笔者看到要求中“最好有图形界面的实现”,略加思索应该没有比游戏引擎更合适的了,正好笔者对Unity这个引擎略有心得,C#的编程也懂一些就做出了这个决定
Unity?
如果常玩手机游戏的各位应该不陌生,该引擎因其比较轻量和插件式工作的特点很容易上手并且制作跨平台的游戏,被广泛用于制作手机游戏,较低的门槛使得对使用者的能力要求不高,而且是利用C#来作为主要语言进行编程的,所以刚好符合笔者的需求,因而选用了该引擎
额外声明
虽然没有必要,但是还是应该说一下,本项目的电梯调度算法的实现没有使用任何的Unity中的影视动画的相关内容,笔者不是动画师,只是个程序员,自然是用纯编程的方式完成该项目的实现
整个电梯算法只有按钮逻辑的一部分利用了Unity框架里面的UI逻辑,来完成比较直观的按键响应
推荐的设置
几经迭代,本项目已经基本完工了,简陋地给出了几个接口,如果设置不合理的话会出现很奇怪的BUG,为了方便直接观察现象,笔者建议最大生成50名Employee,一次生成两个,间隔时间大于5.5s,三倍速生成,就能看到比较清晰的调度运行过程了
ps:由于生成是采用伪随机机制,所以间隔时间和生成随机数质量有很大关联,尽可能地让一次只生成一个Employee,并且间隔时间大于推荐设置
290419C
也是本博客发表的第一天,要写一些实质性的东西,再次说明一下笔者选择实现电梯调度算法,而其本身的要求正如其名,电梯“调度”
这是一个比较有趣的题目,它说了自己是调度算法,那么它就是通过调度系统(也可以理解为该算法)处理在每次楼内的任意一层上下按钮被按下后,对电梯进行调度的一系列行为
说人话就是它才不用管电梯内是怎么按的,只要在电梯的外部(也就是大楼内部),每一层发出对电梯的请求,而该请求在调度算法预定的规则或者逻辑里进行分配,即电梯调度算法的实现
而至今日中午算是完成了一些小功能以及电梯算法的全部逻辑,笔者的编程思想是只使用规则处理逻辑,而规则再进行细分从而达成算法的优化,表层基本规则如下:
1.电梯分为三种状态:空闲(idle),上行(upward),下行(downward)
2.上行的电梯只处理比自己当前楼层高的“向上”的请求,下行的电梯只处理比自己楼层低的“向下”的请求,空闲的电梯两种请求不论高低都接受
完毕,第一层的规则就是这么简单,只规定基本的处理请求的规格,我们接下来进一步优化它:
3.轮询所有电梯,选择最佳的那一个
各位可能觉得这里很怪异,什么叫最佳的?这里其实就是整个问题的核心部分,即便所有人(对电梯调度问题)的实现方式都有所不同,但都要有这么一步,这也是区分各种电梯调度算法结果优劣的核心——找出最好(花费时间最短就能到达)的电梯,而本算法采用的是:
4.距离最近的电梯优先
这就完了?这就完了,但只是对到这一步而言
到此为止我们的电梯还没有“正规化”,一个提供正常服务的电梯有一个必备的功能:等待
也就是我们常说的开门关门
那么有关于等待再增加简单的规则:
5.不等待的电梯优先
这也就完了?对,这也就完了,但还是只针对到这一步而言,我们这样真的就最优了吗?看看我们的规则哪里有一个巨大的转折?
是的,我们的第4个规则直接将所有远距离的电梯扼杀了,如果那个远距离的电梯只是相差了可以接受的层数,而当前最近的电梯正处于等待这种忙状态呢?
6.距离最近的电梯在等待,此时距离该电梯较近并符合前述规则的电梯优先
好的,至此我们已经处理完了尽可能多的最优规则,实际上这也是笔者所想到的全部限制了。
更多的细节在代码中其实也做了一些优化的实现,比如优先Idle状态的电梯相应请求等,算法相关C#源代码见下文,由于用到了一些Unity的API,如果真的要看的话,只需要看算法的实现思路,具体点击这里,里面有一些自用的注释
接下来要做的事情
在做好了电梯调度算法之后需要做的是如何让它看起来有用,因此要加入可以自动行动的AI,目前正在进行相关代码编写,今天暂时就是如此,以上
020519D
距离4月29日已经过去了两天时间,首先,要承认其中摸鱼的时间,4月30日笔者享受了一天假期,5月1日九点就正式重新开工了
前情提要交代完毕,那么其实虽然30日几乎摸了一天,但是早起用了几行代码把单双层的电梯实现了,感觉还挺简单(可这为之后的工作留下了一个比较大的坑)
实际上今天要说的是关于AI方面的工作,这里看似比较脱离电梯调度本身的相关算法,可实际上在使用AI去模拟大楼的电梯运作的时候解决了算法上的疑惑,也进一步发现若是想要实现题目要求需要注意的一些比较阴郁的角落
相关逻辑在昨天处理了部分,可由于一些引擎效果的实现花费了一番功夫,今天比较顺畅地依靠昨天的框架和思路完成了AI的基本实现,可后来遇到了一个怎么de都找不到代码错误的bug,将近一个小时的排查发现居然是一个死逻辑,这里下文再细说,不过幸运的是解决了包括该问题在内的一些小问题,直到今天下午一点才告一段落,项目的网页预览链接依旧可以点击文章开头的小标题,也可以直接点击这里(别忘了按住ctrl点链接,这是个好习惯),操作请见上文,就不再说明了,接下来说明一下AI的相关叙述和目前完成的工作
社畜多米诺
曾几何时,社畜也有着嘴里的零食,手里的漫画,夕阳西下,老妈催着快点回家,却只想着把自己手里这最后一张pia ji输掉的美好时光,当然,我们要谈的话题不是一代人的回忆,而是社畜这个群体
哇,这么真实的吗?
对唔住,就是这样真实,可是等等,我们不是谈AI吗?对,社畜(Employee)就是我们这次选择的AI模型,他们有着规律的上班时间(以及不规律的下班时间),有着明确的目的(指工作十几年可能也不会了解自己所在的办公楼),以及标准的智能(指上的楼层太高会去按电梯),So,这完全符合我们苛刻的要求
好,其实这蛮基本的,简单地说,一个能在模拟中正常工作的AI只需要赋予我们需要的属性,以及它所能做出的逻辑行为,随着我们的需要不停增加,这些属性和行为会逐渐更新并完善
多米诺的含义
我们这里提到的AI其实是个伪定义,它更像一个行为集合,而我们最终得到的结果是这些行为导致的局部结果相互叠加,相互影响从而产生的,这说的比较绕弯了,笔者的本意就是为了说明这里使用的AI是伪的这个本质,之后该AI类的一切实现都要考虑逻辑方法之间的影响,而不是利用深度学习那样训练AI行为得到效果,这也是我们得以用简单的方式实现模拟的原因
下面我们要叙述一些AI的属性和它们的行为:
1.清晰的“大脑”
一个合格的社畜最好要养成时刻记住自己在几楼的好习惯(并不),这其实是一种对当前工作场地的抽象,我们依靠这个属性,来时刻判断AI是否到达目标的楼层,如果不在同一层的话,我们会让AI去尝试叫电梯,这也是我们的核心目的,以此模拟来检验电梯调度算法
2.
规律地生活快乐地工作
社畜就是要工作,AI的目标就是到达工作的场所(本模拟中表现为随机的一个楼层),并停留一段时间后离开(这里其实可以变更为随机改变停留的时间,目前没有更新)
3.铁打的营盘
流水的畜,既然要有人走,自然要有人来,笔者设置了一个最大可容纳的AI数量,可以动态地控制大楼内社畜的个数,只是目前并没有作为用户接口开放设置
关于本电梯调度算法模拟的AI的大致说明就是这样了,其实AI的具体实现要考虑到很多细节的属性,比如社畜们的状态,笔者在一个enum里面储存了work,back两种状态,以此来改变他们的行为,当然还有更多的属性和逻辑,具体的实现感兴趣的读者可以点击C#源码链接,找到Employees的相关脚本
上文只是为了让读者大致了解我们的AI是怎么去进行模拟的,包括它可能会作出的一些行为和一些理论化的概念,从而明白我们需要这些AI的目的,接下来笔者要再叙述关于本电梯调度的阴郁的问题,也是前文提到的大坑
阴郁
或许这个词不太恰当,但是这个问题很有趣,也是和我的Partner进行过一番讨论,我们可以叫它单双层谬误(没这个名词,就当只是为了帅)
当本层楼有多部电梯停止时,只按一个键,那么几部电梯会打开门?
答案是一个,只有一个默认的最优先电梯会一直保持开启电梯门的状态等你进去
当你的目的地是单数层,而开门的电梯只能到达双数层,这种时候你会做什么?
再按一次按钮?我们刚刚的结论是,仍然还是这部电梯会保持开启,那这种结果不免也太悲伤了,如果前提条件如上,岂不是永远也无法乘电梯到单数层?
没错,但你可以乘双数层电梯到你目的地层数的上一层或下一层,再自己走一层
这看起来好蠢
诚然,但是这样的确利用了单双层的限制,并提高了电梯的利用率,试想一下一部电梯只用处理一半的楼层,自然时间效率就提高了,而笔者看到的一篇应用数学论文中有提到该方式作为一种提高高层电梯使用效率的方案,而实际应用中也有使用在一个电梯井中使用的两层电梯等
抛去题外话,如果真的需要如此处理,将引发一些新的讨论,例如:
我们需要楼梯
蛤蛤,是啊,我们终于走到了这一步,一个大楼的电梯调度算法需要楼梯才能完成最终的实现,其实这并不讽刺,只需要我们换位思考
一个装了电梯的大楼需要一个电梯调度算法
这样就对了,从一开始我们的出发点就不是很正确,如果需要让这种调度真实符合逻辑,那么在模拟中我们就要尽可能地还原逻辑并考虑到相关因子,从而达到实现的目的
那么再进一步讨论,假如我们加入了楼梯,之后该处理什么?
上的楼层太高会去按电梯,不太高则走楼梯
前句是我们上文中提到的原话,这个逻辑已经比较接近于正常的思考了,那么这个太高如何界定呢?这里我们假定它为1(实际上,笔者的实现也将其定为了1),即上下只需一层的情况,我们的Employee(社畜)会选择步行,非常的绿色,非常的健康
事实上
可以完全不处理这个逻辑,只单纯地增加电梯按钮的属性,比如增加一排新的按钮,使得两排按钮控制单双层的电梯,但这样就会违背题内的要求,可这并不是不选择这个方案的理由,也并非是笔者喜欢循规蹈矩,而是
这么弄有意思
接下来的工作
大致地完成了微小的工作,接下来需要继续添加的是电梯增加一个判定检测,增加电梯本身的等待时间,为什么目前没有增加这项功能,因为笔者在处理这部分逻辑的时候,会让AI先判断按钮的情况,当电梯正在处于开门状态时,按钮会是绿的(没被按下的状态),但AI无论电梯的状态,会根据自己的目的先按按钮,通过电梯本身的一些逻辑处理,最后会刷新等待的时间(就像那些急着上快关门的电梯的人一样,(AI不)会狂按墙上的按钮)
那么为什么要添加这个功能,这首先涉及到一个设计思想的问题,笔者习惯于把应有且符合逻辑的功能尽量地添加,因为很有可能会有一个外部调用需要该功能的实现,其次它算是个顺手添加,因为接下来需要实现电梯的承重量和可承载人数这两个属性,它们都可以通过这种判定检测来进行实现,它们也是最后的属性了,那么今天就先写这么多,以上
020519E
刚刚实现了电梯承载人数(承载重量同理),改进了AI选梯的逻辑,并新增加了两个用户接口,用于控制生成时间和最大生成AI的数量,顺便把工作时间(AI停留时间)加上了一个随机量,用于产生非一致的停留时间
030519F
6:00 a.m. 11℃,晴,11340步
八点半准时上工,之后昏睡了六个小时
但是没有关系,虽然笔者一直给人的感觉都像是乌龟,不过笔者不以为然,明明是高傲的鸽子,那么书归正传,今天的工作虽然经历点波折,过程也略显缓慢,不过比较稳定地实现了计划的功能,这很好
首先,进行了模拟程序的界面润色,其实这是最不重要的工作,应该放在最后的
然后,就是漫长的优化AI的工作,这其中一度出现让人怀疑自己的电梯算法本身有错误的bug,但是最终发现是debug用的辅助线没有清理干净,在不应该显示的时候显示了,这算是个经验教训,以后在写debug相关的脚本的时候一定不止要干净简单,还要细查不符合期望的结果
1.现在的AI在选择更符合要求的电梯的基础上,会在错过电梯时,主动去检查按钮状态,正常进入第二轮等待,而不是傻傻的卡在边缘,等别的AI按键了
2.新的逻辑,现在的社畜们(AI)获得了新生,它们找到了自己的梦想,每当当前的工作结束时,有三分之一的概率继续去找一个新的工作,天才的发想!这使得电梯的调度终于不再只是1楼和n楼的往返了,而是x楼和y楼的往返
最后,完善了一些小的功能,并增加了更多的用户接口
1.现在,左上角可以选择模拟进行的速度,有三个倍速
2.现在可以直接看到目前容纳了多少AI了
3.大楼目前根据题的要求已经加到了21层,并且每一层都加了标号(只有这个标号不太好弄,但其实也可以用脚本批量处理,只是笔者这里懒了,手打了21层)
那么工作到这里呢,虽然很多的细节没有做好,但项目的样貌已经基本如此了,再有可以进行进一步的润色,而且因为脚本的耦合度并不是很大,可以当做一个框架进一步去更新,甚至可以做成一个模拟游戏,值得一提的是
声音没有更新(笑)
060519F
距离上次更新已经三天了,其实早在5月4日,也就是在笔者觉得大功告成的第二天,发现了这个电梯调度算法的一个关键性的问题——
较低的效率
但这样的好处是能健全地处理所有按键下达的请求,举个栗子:
当电梯处于12楼,被1楼的向上按钮调度,那么它处于什么状态?
按照先前的逻辑,它毫无疑问处于调度按钮的状态,也就是它现在是个上行(upward)状态的电梯,没错,问题就在这,它现在是个向下运行的上行电梯
同样的道理,也会出现上行的下行电梯这种奇怪的搭配,这种搭配的结果就是当电梯朝着一个方向运行时中途不会接受同向的请求,比如向下运行的上行电梯是不会接受路径上下行的请求的,而这些请求就会挂起并交给别的电梯处理
这样也并非全是坏处,这种电梯理论上不会出现请求卡死,它一定会正确地处理目前的需求,而不论挂起的请求有多晚被解决,但肯定不会被卡死,因为请求轮询电梯是同步且随机的,可能有的读者会觉得这种随机性并不靠谱,笔者想到一个不是特别恰当的例子就是俄罗斯方块,在90年代有论文指出俄罗斯方块游戏(随机产生几何图形)肯定会结束,这种随机是必然收敛的,为了方便理解也可以参考一下边缘效应,概率论相关也不再赘述
扯了这么多
那么笔者究竟要说什么,仅仅是证明这个算法是个劣质的骰子算法?
当然啦,笔者自然更改了本电梯调度的核心算法,也是4日一整天加上5日半天的工作重点
回顾一下本电梯原来的算法特点,即一切为调度服务,电梯的状态(上行/下行)完全遵循所接受的按键调度状态(上/下)的改变而改变,所按即所得,简单粗暴
但是现实的电梯,再差也会在下行的时候接受中间的下行请求(上行同理),也就是电梯的状态是根据自己运行确定的,而接受新的请求的规则同样不变,为了做到这一点我们需要一个新的机制
问询驱动与抛出机制
这名字很雅(笔者是这么想的),那么先分别解释一下:
问询驱动:任何一种问询在请求到达电梯后,电梯因此产生的初始运动,笔者就定义它是受到问询驱动的
抛出机制:在受问询驱动后如果该问询反向(底层发出向上请求/高层发出向下请求),那么记录下这个反向状态,如果中途有请求加入进来,则抛出这个作为初始驱动的反向问询,在问询处理系统中挂起,轮询别的电梯
整个机制综上所述其实就是在以前的基础上添加这样一个驱动和抛出机制
类似地,还有一些细节上的变化,比如现在的电梯还可以监视自己的内部有没有乘客并且在没有乘客和调度请求为空时在短时间内改变自己的运行状态为空闲(Idel),这样能更快接受到其它调度请求,提高效率,还有触底反弹的机制(当电梯处于最高或最低层直接反转运行状态)等
仍需打磨
比较可惜的是,篇幅有限,许多设计细节不能一一细说,比如目前增设的许多接口,还有本模拟使用的是一种比较粗糙的随机生成算法,虽然提高了随机的质量,不过并没有使用函数来控制AI状态的占比和频率,导致没办法模拟大量AI的场景,因为没有开放随机内容更改的接口和储存功能,因此比起更注重仿真细节的模拟程序,这更像一个可以进行些许交互的电梯调度演示程序
一些早先的BUG,没错,尤其是5月5日,那一天突然多了很多点击,而恰好那一天刚好开学,而且更改项目比较多,没急着修复BUG,直到晚上八点才提交更改,许多人看到了这个程序最千疮百孔的样子(悲)
所幸,包含在内的一些BUG都进行了尽可能的修复,包括AI在超载状态下的选梯逻辑,以及选择更优电梯的上梯逻辑,以及在刚刚修复了一处恶性BUG,它导致电梯队列中多出了不应该出现的重复请求,以至于在某一层可能产生超出预计的停留时间
后记
昨天看到邹欣老师的建议,笔者也着实想了很久关于大量模拟和程序正确性的问题,该程序之所以目前只能小量模拟的原因在前文也提到过了,AI的生成虽然开放了一定的接口,但是非常简陋,无法精细设置一些概率相关的变量,内部也没有复杂的生成公式,因为当初设计的初衷其实就考虑过大量高随机性模拟和小量高频率模拟的取舍问题,两者都能在一定程度上测试算法的承受压力,考虑到一些性能问题和实现电梯调度逻辑的优先级更高,故而选择了AI工作量较小的后者作为解决方案
关于正确性,刚刚其实也在试着开放新的UI显示,以表示每一层的驻留人数和每一层的应当存在(工作目标为该层)的人数,作为程序正确性的参考,可是做到一半发现这个功能太过冗余了,因为只要AI能正常出入电梯,就已经证明它能成功地到达预计的楼层,电梯的逻辑只要正确就不会出现卡死和“带人过楼”(让本该向下的Employee到达了更高的楼层)这种现象,也就是说可以正常运行即是一种正确,目前会引起的主要错误是生成了过多的AI导致的一些渲染碰撞问题
那么最后呢,由于本项目基本告一段落了,但实际上笔者是对它另有打算,这些留作后话
总的来说,这一段时间的制作和学习经历着实非常地有价值,感谢高老师一直以来的不离不弃,作为本项目的领航员高老师一直进行着积极的沟通,作品的完善程度和两个人的付出是有着密切关联的,合作对笔者而言是个相当重要的课题,最后按要求附上合作的照骗片
090519F
蛤蛤!三天时间,其实几天前投的版本也是个BUG满满的版本,本来抱着没什么人看,就不急着填坑的心态(咕咕咕),首先,先来经典的忏悔,再就是解释一下这个问题
怎么还有后续啊!!!
是的,项目虽然大体完成了,但仅仅是包括各种要求,以及能运行这两个条件,其实稳定性真的很差,每次添加新的功能或者修改旧的BUG都有可能带来更多的问题,这可真的是...咳,那么闲言少叙,这个后续的主要目的是叙述一下这段时间的工作成果,以及修复BUG的一些新的体会
新的功能
在7日,也就是主体项目告一段落之后看到邹老师的留言陷入了思考,这个东西它真的对吗?一直以来笔者都是靠肉身Debug:观察->出现预期之外的情况->修改代码->观察
并且一直以小频率测试,也就是模拟中生成较少数量单位进行自动测试,效果就当时的情景而言还是比较理想的,因为逻辑简单清晰,没什么坑好说(但后来事实证明道阻且长),并且在大数量单位测试中会遭遇很多预期之外的影响,因为对Unity引擎并不精通的缘故,没能很好的理解大量单位在寻路系统中的一些规则,以及各种功能的细节,导致还没测试调度就已经倒在了测试的路上
在解决了诸多零碎的小问题后,终于一些功能得以实现了,但因为测试不完全有可能出现一些BUG,因此在此处写下新的功能及其使用注意事项
1.Normal 和 Fast
在之前新增2.0X倍速和3.0X倍速的UI基础上,可以点击倍速按钮上方的Normal和Fast切换生成模式,分别对应原先的普通少量测试以及新增的快速大量测试,大量测试提供了10倍速和20倍速(对),并且为了加以区分,新的测试Employee的贴图是蓝色的,并且修改了Normal的默认设置,现在初始的生成速率为0,可以自行更改生成速率,而且现在最好不要更改其它默认设置,这是为了达到最好的效果(其实主要是避免可能出现的丑陋BUG)
需要注意的是,由于AI的寻路渲染是逐帧的,因此在选择高倍速运行时可能出现AI卡在楼梯上的情况,只要调回1倍速就可以解决
2.可以静音了
OK,千呼万唤始出来(并没有)的功能,切实地解决了用户的痛点(确信),现在可以将笔者那魔性的声音给禁止掉了,要问笔者为什么最终还是做这个功能,答案就只可能有一个了
1000个人乱按键或击穿耳膜
好吧,其实没那么严重,再多人按键振幅也不会变大的,因为一些物理模拟机制的原因,只是会变得过度嘈杂,而且当初为了Debug而加入的声音播放在大数量测试中显得过分鸡肋,也因而出现了新的,更加直观的显示效果
3.现在的按键不仅会在按下后变红,而且在请求被成功接收时,颜色会变成黄色,如果请求被弹回,则又会变成红色
这某种意义上提高了的Debug效率,而且事实上,最新的一个最棘手的未知BUG就是依靠观察它产生的现象解决的(也不能算完全解决,源头的代码块虽然找到了,但是为何发生尚不能确认)
4.增加了到正交视图视角的平滑过渡,并且默认会调整到比较合适的观察位置
其实过渡功能是依靠插件本身的特性实现的,仅仅是做了一点小的糖果调整,大致的新增功能和一些特性就这么多,基本操作仍旧和以前一样,项目的源码和预览会尽可能地一直公开,欢迎学习讨论
重点来啦!!无论功能多么花哨,做这个模拟的初衷就是非人为的给出大量测试用例,并直观地获得相应结论,而这次1000模拟后的结论是
算法漏洞
是的,就像前文说的,调度算法逻辑仍需打磨,但切身体会到它的漏洞真的是有一种奇特的感情,说实话,蛮欣喜
这个漏洞也很经典,但凡涉及到电梯调度的相关讨论就一定会出现的顶层/底层挂起,漏洞的原因是在处理上下行逻辑的时候,并没有优先去分配更高层的下行请求,也没有优先分配更底层的上行,低层还好,到了内部调度大量发生的时候能看到高层会挂起相当长的一段时间,也多亏这是四部电梯才能使得没有出现长时间的卡死(虽然当数量到达一定极限的时候也应该会出现近乎完全的卡死),可也正因为这是四部电梯,导致如此多次的模拟都没能直观地发现这个漏洞,一方面是由于模拟早期并没有一个良好的反馈表现,另一方面是头铁不选择减少电梯数量做测试,而这个框架唯一优秀的地方就是能灵活地增删电梯和改变电梯属性(而当时发现该BUG好像也是得益于一次偶然的单电梯测试)
这个算法漏洞目前还没有解决,虽然发现的并不是很晚,但是当笔者做这个1000人测试时是秉着
首先要对,然后再优化的
这个原则去做的,因此一路将碰到的BUG解决,最后提交了这么一个有漏洞的版本,虽然不太光彩,但这也是历程上重要的一环,最后说一下印象比较深刻的BUG
不想回家
描述:AI到达工作坐标点后没有离开
原因:AI没有成功触发到达判定,原因是寻路功能使用A*算法是有运行时间的,导致路径没有渲染完毕,从而判断了旧的目标点和当前坐标,导致提前判断为到达,使得状态设置错误,无法从工作状态中脱离
解决:伪线程等待渲染路径成功
请求搁置
描述:该楼层请求表现为"黄色"(请求已接收),但是却没有电梯停下来
原因:原因并不单一,首先说简单的原因,由于电梯本身弹出请求的机制导致了同层两个请求同时被按下时,电梯符合弹出条件则会去尝试处理另一个请求,但在ElevatorSystem的处理中,电梯目标队列里相同的楼层不会重复置入,这是为了防止在电梯开门时出现预期外的长时间等待而做的,可弹出函数依赖重复输入
解决:在System的重复输入处理中加入判定条件,使得反向驱动状态的电梯可以重复输入一个楼层(可事情并没有就这么结束,前面也说了是简单原因)
本质:根本原因是因为电梯只维护了一个单独的集合,当重复楼层出现时不能判断它们的属性,导致会出现错乱删除的情况,上面还没有提到的另一个比较复杂的原因就是在电梯内的输入楼层和外部调度想要设置的楼层一致时(目前惟一的可能猜测),出现了请求成功但调度楼层未置入的情况
一点说明
虽然还有内容可写,但主要是一个更新介绍,和一些简介,因此先不多说,今后再有更新再继续说(话说这个blog有点太长了吧),最后,大家千万注意自己电脑模拟1000人的时候要量力而行