手机版

Vue实现美团app的影院推荐选座功能【推荐】

时间:2021-08-30 来源:互联网 编辑:宝哥软件园 浏览:

经常用美团app买电影票,不禁对它的推荐选座功能产生好奇,于是打算自己实现一个类似的算法。美团app推荐选座界面如下

最多可选择5个座位,本次演示的座位选择界面如下

在上图中,点击推荐的5人座

座位选择较晚(绿色),这个演示和美团app的区别是可以连续推荐座位,美团app点击推荐座位后必须购票才能继续选择。

这个演示是由Vue-cli构建的,github地址在这里。克隆后,npm启动可直接用于特定操作

算法思维过程

对于这个座位推荐算法,我尝试过不同的电影来推荐座位,总结了以下几点

(1)推荐算法首先从电影院中间一排最后一排的中间搜索下图

可以确定就是这个逻辑,其他几款游戏也是如此

(2)优先在后排搜索。后排搜索完成后,从中间开始位置搜索到前排是对的。如下图所示,偶尔会有差异

(3)后排搜索完成后,每一排都会有一个结果(每一排的结果是最靠近中轴线的那组座位),这些结果中距离中轴线距离最小的结果作为最终结果,而不是越靠近屏幕。

大多数情况下也是如此,有些情况是错误和奇怪的

(4)仅考虑并排和连续座椅,一排或一排之间必须有间隔。比如过道这种可以理解。毕竟,坐成一排绝对是更好的观看体验

剧院座位数据结构

可以肯定的是,二维数组seatArray用于表示电影院的座位。人们注意到电影院座位的分布是不规则的。因此,需要确定一个座位行和一个座位列来确定电影院座位的阵列大小,分别表示行数和列数。对于那些没有座位的地方,seatArray的对应位置用-1填充。以下是座椅的具体价值和含义。

-1个非座位0个可选座位(白色)1个选定座位(绿色)2个购买座位(红色)

然后初始化已安装的座椅,初始值均为0(可选座椅),如下所示

//初始座位数组initseatarray : function(){让座位数组=array (this。座椅排)。填充(0)。map (()=array (this。座位栏)。填充(0));this . seat array=seat array;//将父容器的宽度除以座位的宽度。这个。座位=这个。参考文献。innersetwrapper?parsent(parsent)(window . getcomputed style(this。$ refs.innerSeatWrapper)。宽度,10)/this.seatCol,10):0;//初始化this.initNonSeatPlace(),不是座位;},//初始化initnonsat place : function(){ for(让I=0;i9;I){ this . seat array[I][0]=-1;} for(让I=0;i8;I){ this . seat array[I][this . seat array[0]。length-1]=-1;this . seat array[I][this . seat array[0]。length-2]=-1;} for(让I=0;i9;I){ this . seat array[I][this . seat array[0]。length-3]=-1;} for(让I=0;ithis.seatArray[0]。长度;I){ this . seat array[2][I]=-1;}}初始化后,使用一个双循环来构建html结构,两个v-for嵌套循环出整个结构,如下所示

div class='内部座位包装' ref=' innerSeatWrapper ' div-for=' seatRow中的行'!-v-如果这里很重要,如果不可用,就会导致错误,因为seatArray的初始状态为空-div v-for=' col in seat col ' v-if=' seat array . length 0 ' class=' seat ' 3360 style=' { width : seat size ' px ',height 3360 seat size ' px ' } ' div class=' inner-seat ' @ click=' handlechoose seat(row-1,col-1)' v-if='seatArray[row==-1 ' : class=' seat array[row-1][col-1]===2 '?购买座位' :(座位阵列[row-1][col-1]===1 '?selected-seat ' : ' unselected-seat ')'/div/div/div上面提到的内座类的div是一个特定的座位div,v-if显示如果是-1,也就是过道,就不渲染了,然后:class控制这个座位对应的类的值。使用嵌套的三项式运算符进行控制,并切换每个座位绑定点击事件handleChooseSeat(行-1,列-1)的状态

//手柄座椅选择逻辑handlecooseat:函数(row,col){让座椅值=this。座椅阵列[行][列];让new array=this . seat array;//如果是购买的座位,直接回到if(seatValue===2) return //如果点击选中的座位,会变成未选中的If(seat value===1){ new array[row][col]=0 } else If(seat value===0){ new array[row][col]=1 }//二维数组必须整体更新,Vue检测不到数组的更新,只能通过切片复制一个数组。this . seat array=new array . slice();},这里需要注意的是,要更改vue中数据中的2D数组,必须先缓存2D数组,修改后会重新分配2D数组,否则修改不会生效,因为Vue检测不到数组中的变化。

推荐座位的具体代码

首先,将活动智能选择绑定到每个推荐座位的按钮上

代码如下

//推荐座位选择,参数是推荐座位号smart choose : function(num){//找到电影院后排座位中间的水平和垂直位置,让row start=parsent((this。座椅排-1)/2,10)1;//搜索let back结果=this。searchsearchdirection(行开始,此。座位排-1,num)从中间排到后排;if(back result . length 0){ this . choose seat(back result);Return} //搜索信件转发结果=这个。search search direction(row start-1,0,num)从中间一行到前面一行;if(forward result . length 0){ this . choose seat(forward result);Return} //提示用户没有合法位置可供选择提醒('没有合法位置可供选择!')},第一步是找到后排的横竖中间位置的电影院座位,然后把这个叫做。this . search seattby direction要在这个方向搜索,首先从中间一排到后排,然后从中间一排到前排。如果搜索结果是任意方向找到的,直接返回,否则提示用户没有合法位置,使用chooseSeat改变座位状态

重点是searchSeatByDirection的实现。代码如下

//前后某个方向搜索的函数,参数有起始行、结束行、推荐座位号searchsearchseatdirection 3360函数(from row,torow,num) {/* *推荐座位规则* (1)初始状态下,从最后一排座位数一半的中间开始分别向左和向右搜索,取最靠近中间的一个。如果满足条件,*记录结果与座椅中轴线的距离,后排搜索完成后,取距离最小的结果作为最终结果,先在后排搜索。*前排搜索同上。* (2)只考虑并排连续的座位,需要保存当前方向搜索结果的数组,一行或一行之间留有空格。* *//* *元素是一个对象。结果为结果数组,offset表示距中心轴的偏移距离* {* result:array ([x,y])* offset : number * } */let currentdirectionsearcheresult=[];//确定行数的大小关系,由小到大遍历让largeRow=fromRowtoRow?fromRow:toRow,smallRow=fromRowtoRow?toro w3 3360 from row;//逐行搜索(让I=smallrowi=largeRowI ){ //搜索每一行找出一组该行中轴线最近的座位:让temprowresult=[],mindistancetomidline=infinityfor(设j=0;j=this . seatcoll-num;J ){ //如果有法律立场如果(这个。checkrowsetcontinuous和empty (I,j,jnum-1)){//计算这组位置的中轴线到:的距离,这组位置的中间位置到中轴线的距离让resultmidpos=parsent((jnum/2),10);让距离=math . ABS(parsent(this . seatcol/2)-resultMidPos);//如果距离短,则更新if(distancemindistancetominaclementline){ mindistancetomidline=distance;//此行的最终结果temprowresult=this。generaterowresult (I,j,jnum-1)} }//保存此行的最终结果currentdirectionsearcheresult . push({ result : temprow result,Offset : mindistancetomidline })}//处理后排:的搜索结果,找到与中轴距离最短的那个。//注意这里的逻辑需要区分前后行。对于后排,从后向前查找let isBackDir=fromRow toRow让finalReuslt=[],minDistanceToMid=InfinityIf(isBackDir){ //对于后排,currentdirectionsearchresult。foreach((项)={if(项。offsetmindistancetomid){ final reuslt=item。结果;minDistanceToMid=item.offset} });}else{ //第一行,查找currentdirectionsearchresult。反转()。foreach((项)={if(项。offsetmindistancetomid){ final reuslt=item。结果;minDistanceToMid=item.offset} })}//直接返回结果return finalReuslt},代码有点长,但逻辑并不难,也就是执行之前的规则,可能每一行搜索都有多个合理的座位结果。

我过去常常从左向右走。如果推荐五个座位,先判断位置1-5是否合理。如果合理,记录中间位置(3号)到中轴线的距离和座椅结果数组。然后移动一个位置,检查位置2-6是否合理。如果合理,比较位置2-6的中间位置(4号)与前一个距离的距离,取最短的一个,同时更新座位结果数组,这样就可以确定这条线的最终结果。每行的最佳结果将存储在CurrentDirectorySearchResult数组中。遍历完后排的所有行后,将获得一个由每行最佳结果组成的数组CurrentDirectorySearchResult。然后遍历这个数组,按照规则取最靠近中心轴的一个作为最终的返回结果。

这个算法可以优化,直接从中间往两边看,找到了再返回,但是写起来有点麻烦,但是肯定是有效率的。需要注意的是,currentdirectionsearchresult。reverse()前排应该倒过来,因为前排后排部分是首选(没有人想坐第一排!),与后排相反

最后的

这个算法有问题,如下图

最左边的两个绿色座位是上次点击推荐两个座位的结果,但是这个位置没有另一个箭头处的两个位置合理,说明算法其实并不完善,上面的分析可能也不到位。其实美团的算法也有问题,如下图

这个建议的合理位置应该是四个位置向左移动一格,这是中心位置。这个推荐有偏移,不知道为什么。网上没有具体的算法逻辑,只能靠猜想和实验。

摘要

上面提到的是边肖推出的Vue实现了美团app的剧场推荐选座功能,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:Vue实现美团app的影院推荐选座功能【推荐】是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。