SorrowEngine
老爹汉堡店是一个较为简单的益智模拟经营游戏,主要内容是为顾客制作汉堡。其中主要分为三个界面:点餐,烤肉和搭建界面。每个顾客会根据这三项内容进行评分,并且根据分数和顾客等级给予小费。
虽然该游戏的过程较为简单,但想要完整的规划游戏的自动化流程,是有一定难度的。因此该文章主要写了对于该游戏的分析过程和对于Python进行自动化控制的部分原理分析。
【资料图】
1 研究的工具及游戏介绍
该程序运行环境为Windows11+Adobe Flash Player34+1920*1080分辨率屏幕放大+原始版本+Windows导航栏在下方。
鼠标的自动控制该程序使用的是pyautogui库,该库可以通过调用函数达到鼠标移动,点击,拖动等多个功能。同时,该python库也支持对于特定图片进行判断。如果通过引入opencv库,还可以设置一定的识别容错率,从而消解因为截图和图像裁剪处理而造成的图像变化和游戏放大后所造成的图像不一致问题。需要注意pyautogui在识别时会耗费大量的时间,有几种方案可供缓解:①设置为灰度图识别模式,但是在识别花纹不明显的物体(比如芝士片)和形状相同但颜色不同的物体(比如四种酱料)时判断效果很差,因此不采用。②使用准确的图片进行查找,不使用opencv进行相似查找。问题在于在图像放大时本身可能会变形,并且在截图时的颜色变化难以避免,因此难以获取准确图片,可能造成漏判,因此不采用。③通过限定判断区域的方式进行判断。可以加快判断速度,但是需要确定合适的判断范围,以免造成漏判。综合考虑下,目前主要通过限定判断区域的方式进行判断。 数据储存在数据储存中,选用了较为简单的CSV文件,对每一个顾客的正确点单进行储存,方便管理。 游戏介绍在点餐过程中,点餐等待时间过程和出餐等待时间过长都会造成扣分。其中点餐等待时间的扣分相对出餐等待时间的扣分相对要更严苛一些。在出餐等待时,可以通过顾客挣来的钱进行海报张贴和物品购买(如报纸,电视,咖啡机,游戏机等),可以适当延长出餐时的等待时间扣分时长。在烤肉界面,主要影响因素有三个:烤肉的程度(即三分熟,五分熟,七分熟,在游戏中标注为蓝色,黄色和红色,后文用“蓝色烤肉”“黄色烤肉”“红色烤肉”替代。在烤肉过程中,还需要注意烤肉的均匀程度。烤肉的均匀程由每一面的烤制时长决定,两面均为50%烤制时间分数最高。烤肉的温度也会造成较大的影响。烤肉温度越高,分数越高。可以通过道具购买保温灯以减缓烤肉的冷却速度。在出餐界面,主要影响因素为出餐内容是否符合点餐顺序和汉堡搭建是否偏离中心。只有在三个方面均得到100分,最终结果才能为100分,可以说要求很严格,人的手工操作也很难做到这一点。这次我希望通过电脑达到控制游戏自主游玩,并且达到全100分的效果。
2 各方法过程分析为了直观地了解和分析每种方法的流程和效率,采用了流程图+甘特图的方法对每种方法进行分析。在分析之前我们假设:每个顾客点餐和出餐的时间均为15秒;每20秒进店一位顾客;界面切换/烤肉翻面等微小时间忽略不计;每一小格为5秒;烤肉行为烤肉的时间统计,蓝色,黄色,红色分别代表三种烤肉的时间;顾客行,紫色为等待点餐时间,绿色行为等待出餐时间。
第一版方案在第一次实验中,本人采用了“先烤肉,后出单”的方案,优点是功能简单,编写方便,并且能够比较正常的使用。
第二版方案
第一种方法存在比较大的缺陷:每次烤肉的量是固定的,因此当某一种肉的需求过大时,可能会导致烤肉数量不足而出现问题。对于该问题,通过在出餐时,若发现某种烤肉不够,则重新唤起对应的烤肉界面得以解决。
但是,既然可以做到在烤肉时重新调用烤肉界面,那么为什么不放弃一开始的烤肉内容,而是直接通过出餐界面的调用解决问题呢?于是在删除了起始烤肉的设置后,从理论和实践的角度,都可以发现效率有了微弱的提高。
第三版方案
但这种情况显然不是设计的最优解。通过个人实践我们可以发现,三种烤肉的翻面/出餐间隔时间约为15/30/45秒,在原来的程序中,我们没有合理利用这一部分时间,从而导致了效率的降低。因此我们自然想到了在等待烤肉的时间内接收顾客的点餐。但是随之而来的也几个问题:烤肉的等待时间是否能够支持一个顾客的点餐?是否会因为顾客的点餐而导致烤肉的时间超时?对此我的方案是,为了提高效率,先暂时牺牲一部分烤肉的时间,同时将点餐时间设置计时,如果没有超出15秒的时间,则可以等待剩下的时间后正常翻面/移出。若超出了正常的间隔时间,则将错就错,按照原先的预想翻面/移出。经过实验发现,顾客点餐的时间约为12-15秒之间,如果点餐长度较短则可以比较准确的的占有预定时间,但是若点餐长度较长则没有办法继续承担。可以看到,在采取该种方法后,烤肉的效率得到了进一步提高,在整体的时间上得到了大幅的缩短,但是由于只点餐不出单,导致顾客在点餐后等待和排队时间增长,从而在等待时间也会降低分数。同时我们也意识到,如果烤肉之间的时间可以被合理利用,那么通过出单回调点单的方法会对点单顾客的等待时间变长,从而不利于分数。因此,我们又改回了原先先烤肉+回调烤肉的流程,使得点餐人员的等待时间进一步缩小。这也是一个比较完整的解决方案。
第四版方案
但是显然顾客的等待时间过长,这会对等待时间的分数造成极大的影响。为了改善点餐时间等待过长的状况,我们打算利用烤肉的时间进行点餐的同时,也合理的进行出餐。但是有一个问题需要解决:点餐随时可以,但是出餐则需要对应的肉已经烧制完成,如果没有烧制完成的就出单的话,会触发回调烤肉的情况,从而出现程序错误。因此如果需要烤肉的话需要先判断该种肉是否烧制完成,之后再选择出单。由于每次烤肉的量较多,该方法暂时不用考虑烤肉之后的数量是否充足。由于点餐等待的扣分相对较严苛,因此我选择了先点餐,后出餐的形式,如果没有点餐的人员,再判断是否有合适的出餐人员,之后按照“先来后到”的判断方法出餐。这种方法对于不同的顾客要求组合也会有不同的效率形式。对于正常的蓝-黄-红模式,效率会相对较高,但是对于红-黄-蓝模式,由于之前堆积大量订单,会导致效率有所降低。
第五版方案
从图中我们可以看到还有一个小问题需要解决:即在由于之前的顺序模式,导致在烤肉时为先点单,而在烤肉结束后,会变成先出餐,这会导致之前积压的点单会集体出餐,会给后面的顾客极长的等待时间。同时也有一个问题:烤肉是受温度影响的。烤肉结束后,后面的顾客如使用了放置较长时间的蓝色烤肉,则会因为温度降低而导致扣分增加。我们对于这两种问题的解决方案是,让烤肉在整个事件内开启循环,在烤肉过程中本身已经具有了完整的判断出餐/点餐的系统,可以完整的满足顾客的需求。若开启循环,则可以让烤肉温度更高的同时,解决点餐和出餐的顺序问题。这种方案对于后几名顾客来说是一种较大的提升。
第六版方案
但是在这种模式成功以后,分数却还是不理想。于是我们还需要采取其他方案来解决问题。
一开始,我想到了烤肉炉的利用效率问题。由于蓝色烤肉和红色烤肉的需求量不大,因此这两种烤肉只占了半个烤肉炉,同时也是为了烤肉的堆积数量考虑,若烤肉过多则会出现展开栏,导致烤肉不好定位,从而造成编程上的复杂。但是我们可以考虑在烤制红色烤肉的同时烤制蓝色烤肉,每个炉子各占一半,这样就可以使烤肉炉利用率提高,同时可以缩短等待红色烤肉的人的等待时间。在后来,我想到了更为提升效率的解决方法,将三种烤肉放置在同一个炉子里进行烧烤。由于蓝色烤肉的翻转时间间隔为15秒,黄色为30秒,红色为45秒,而最终时间则为30,60,90秒,想要对这三种烤肉进行不间断的统一烧烤,就必须想好每一次循环需要的时间。经过推算后,我发现这本身是一个寻找最小公倍数的问题。30/60和90的最小公倍数是180,也就是说可以通过180秒的时间对烤肉进行一次循环控制,其中蓝色烤肉烧制6次,黄色烧制3次,红色烧制两次。这样可以在最大程度上保证烤肉的温度,提升顾客的分数。这种方法已经基本上达到了该游戏的理论效率最高值,但是在实际中还有一些小问题需要解决。
总计图
由此我们可以看出,在逐渐优化的过程中,在整体时间逐渐减少的同时,顾客的等待时间也在逐渐减少,可见优化方案是有效的。
3 实践问题
点餐问题
点单偶尔会出现99分的情况,通过判断是由于点餐人数数量过多,从而导致没有机会出餐,导致等候出餐人数积压。因此之后会改为单数大于等于4张时优先先部分出餐。 汉堡搭建问题汉堡搭建的分数有所降低。汉堡为了在汉堡搭建的准确度上提高,我统计了该游戏所有44位顾客的点餐需求,并根据识别结果在点餐人群中找到最匹配的进行使用。这修补了由于识别不准而带来的用料不正确的问题。
44位顾客在经过匹配修正之后,正确率是否能够比之前更高呢?通过长期观察发现,汉堡识别的错误一般为1个,因此,只要每个顾客之间的识别差异大于等于三,那么基本可以保证识别的正确率。因此在统计之后,汉堡差异小于3的顾客只有2对,这说明匹配错误的几率是很小的。
最终统计结果:
关于搭放汉堡偏离中心扣分的问题,我假设每个人对于汉堡的搭放没有所谓“宽容度”的区分,而是通过物品偏移程度及便宜量进行综合计算。通过统计我发现,只要是 含有芝士或酱料(不包含黄酱)的内容,在我的电脑上都会扣分,而所有这些内容都不包含的点单要求,基本都可以获得满分。于是我尝试对于这些特殊的内容进行像素级调整和修改。
烤肉问题
由于追求15秒的翻面时间,点餐和出餐的时间需要有一定的提速。对于整个流程我进行的全方位的分析,并作出了如下修改: 点餐识别时间优化
对于点餐,由于需要判断该点餐包含哪种肉类以便于分析,我设置了在点餐结束回到大厅时对点单内容进行判断。但由于判断需要一定时间,因此会停顿1-2秒。我通过判断点餐顾客是否说到“汉堡顶”作为判断开始的标志,利用顾客点餐的时间中进行物品的识别,从而最大程度降低识别对于点餐时间的影响。 点餐人员时间优化
在点餐过程中,需要对是否有点餐人员进行识别,原先的方法是通过对点餐气泡的识别进行判断,同样对气泡的识别也需要消耗一定的时间。我的优化方法是先点击气泡所对应的位置,如果点餐有人就会开始点餐,在之后判断时候在点餐页面中,从而达到判断效果。如果没有人点餐,那么在点击对应位置后没有点单内容生成。此时再判断是否出餐,可以减轻点餐识别所用的秒时间,从而部分提升效率。 出餐识别时间优化
在出餐时,由于识别的影响同样需要卡顿1-2秒的时间。由于之间已经有了一部分的识别内容,再识别内容就有些多余,因此设计了一个二维数组,将之前识别出的内容进行保存,待出餐时再进行调用,可以节省1-2,秒时间,从而使出餐速度更快。 改进方案
对于改进方案,接下来有以下几种想法:①尝试单独烤肉查看效果②进行梳理③去B站搜索正确汉堡的样子并进行对照(没找到,没有一个100分的)④经过实验,和窗口大小无关
4 解决方案
游戏分数判断规则
一开始我们试图通过数据分析的方式来进行偏移的判断。在排查过程中,发现只要有芝士或酱料的汉堡基本都为100分,而都没有的汉堡则大多都为99分。这使我对于芝士和酱料的位置产生了怀疑。于是我将每一种酱料的坐标分开判断,从而部分修复了问题。但是后来随着统计越来越多,我们逐渐发现了一些不符合该规律的问题。例如一位名为Sue的顾客,她只有西红柿,肉饼和汉堡顶三种食材,但却为分。而在之前的判断种西红柿和肉饼的位置都是正确的。于是我怀疑可能是出现了累加问题,可能每一个物体都有一定的偏移,累加起来导致偏移量过大从而导致扣分。
由于这种实验方法过于枯燥且无效,我打算通过另一种方法测确定猜想,即通过一些特殊手段深入了解该游戏的打分机制。
通过判断与梳理,我发现该游戏的评分机制如下(所有单位均换算成秒):
等待分数 = 四舍五入(100-点餐等待时间扣分-出餐等待时间扣分)(公式4-1)
点餐等待时间扣分=[点餐等待时间-(点餐理想等待时间+奖励等待时间)]* (3/10) 或 0
出餐等待时间扣分=[出餐等待时间-(出餐理想等待时间+奖励等待时间+烤肉时间)]* (3/10) 或 0点餐理想等待时间 = 25秒
出餐理想等待时间 = 60秒
烤肉时间为 * 2或4或6 秒,取决于所需时间最长的烤肉时间
奖励等待时间 =
罗马诺海报 2秒
酱汁海报 2秒
素食海报 2秒
披萨海报 2秒
莫奇海报 2秒
奶酪海报 3秒
汉堡海报 3秒
SnJ海报 3秒
Patty海报 3秒
Kingsley海报 2秒
电视 4秒
报摊 6秒
Arcade橱柜 8秒
口香糖机 3秒
自动点唱机 8秒
咖啡摊 3秒
烤肉分数 = 四舍五入(原烤肉分数总和 / 烤肉总数)(公式4-2)
原烤肉分数 = 100-(超时/不足时时间)-四舍五入温度扣分-偏离50%百分比
超时/不足时时间 = 超过/不足预定时间秒时,每超过1秒扣1分
四舍五入温度扣分 = [(195-出烤肉炉时间) / 180 或 1] * 100
偏离50%百分比 = 例如51%/49%为1,52%/48%为2
搭建分数 = 四舍五入(*错位比率-*错位扣分比率-*总偏移量)(公式4-3)
错位比率 = 点单错误数/顾客总单数
错位扣分比率 = 点单错位数*75/顾客总单数
总偏移量 = 与判断中心偏移超过1像素的偏移量总和
评分机制分析根据该规则我得知了一些内容:①烤肉最重要的是均匀程度,程序会扣除偏离50的分数,如果想要达到一百分,那么烤肉的两边必须为50%才可以。②烤肉的温度下降很快,在15秒内温度才不会被扣分,一旦超过十五秒分数就会下降。加热灯只能缓解温度下降速度,而并不能增加温度等待程度。③烤肉对于时间的要求较为宽裕,红/黄/蓝烤肉均允许偏离烤肉时间1/8而不扣分,而偏离更多时则会被扣分。点餐等待时间很长短,而出餐等待时间很长,因此尽量先点餐。
搭建汉堡优化经过调整,我发现了以下搭建汉堡的问题:汉堡的得分最高位置不是正中心。这是因为在判断分数时,程序调用的是出餐界面的缩略汉堡图片,而不是搭建界面的大汉堡可能是由于程序设计失误,导致判定点的正中心并没有和确定的汉堡底的正中心对齐,而缩略的汉堡图片又是由搭建的汉堡图片得来的,因此相当于搭建时的汉堡中心点也不在汉堡的正中心。有趣的是,程序对于偏离中心点的扣分相当严苛,在四舍五入的情况下,如果偏离超过1像素点就会被记录求和,最终按每偏离一个像素点扣分的标准计算。但是由于设计问题,不能自由移动的汉堡底本身偏移了个像素点,这导致人的操作只能够多偏移个像素点,才能够保证满分。
该图为测试时出现的一个例子。从肉眼已经可以看出,整个汉堡除下方的汉堡底以外,其他物体的中心都已经向左偏移。
在调试过程中,我发现芝士是一个特殊的存在:由于我的程序设计是将鼠标移动至物体上,然后拖动至指定位置,但是在改变移动到芝士上的坐标时,芝士却完全没有移动。后来我意识到由于芝士的形状和拖出来的形状不同,这说明了两者拖出来的不是一种物体。而拖出来的芝士会自动移动到中心位置,所以只有改变芝士拖动到的位置,才能够改变芝士的最终位置。最终通过调试和修改,可以保证在搭建环节顾客的评分一定为100分。
烤肉环节优化理论在烤肉环节,如何平衡烤肉温度,烤肉均匀度,顾客等待时间三者之间的关系成为了重要的问题。由上述分析我们知道,烤肉对于时间有较强的宽容度,因此我们可以通过延长时间来改善烤肉的均匀度。但是由于烤肉的温度改变较快,烤肉时间变长会导致烤肉变凉,从而影响分数和顾客等待时间分数。而缩短烤肉时间,又可能会使得烤肉两边时间不均,从而导致烤肉不均,进而导致扣分。我们需要找到一个较为合适的中间时间,并且需要进行权衡。由于游戏的限制和pyautogui的运行速度限制,我们无法做到精确控制时间,从而只能通过统计大致时间的方法进行烤肉时间的判断和改进。通过分析可以知道,在烤肉过程中拖动肉饼所需要的时间较长,如果所拖动的肉饼过多需要花费3-4秒的时间,而给所有肉饼翻面仅需要1-2秒的时间。同时还需要考虑到在翻面过程中烤肉不会进行,约有秒的时间差,并且也需要考虑点击烤肉界面,点击按钮等方面的微小时间差距等等。最终我们没能做出一个完美的烤肉优化方案,但是理论上来说全100分是可行的。
5 图鉴
关键词: