自动机编程游戏
转自martrix67's blog,一个玩了好久的游戏,很费脑,但是很值得,可以学到很多的东西……它是真正意义上的程序设计游戏,游戏不但提供了完备的读写和流程控制功能,甚至还引入了随机测试数据。游戏很快就会引入算法的思想,因为玩家渐渐会发现,这些谜题并不是单靠模拟就能解决的;后面的谜题则越发困难,需要相当有技巧性的算法设计,对脑力绝对是一个大挑战。一开始需要按右方向键几下浏览说明然后开始游戏,游戏难度逐步加大,完成这个游戏之后,你会发现自己对于自动机有了新的理解。
Level 1: Robotoast! ACCEPT: Move robots from the entrance (top) to the exit (bottom)! 没有任何悬念,用3个元件,耗时32764(注意这是v1.30里的计时单位,在老版本中大概是0:02)。 Level 2: Robocoffee! If a robot's string starts with blue, accept. Otherwise, reject! 要求接受以蓝色开头的机器人。也没有任何可以商量的,3个元件,耗时24572。 Level 3: Robolamp! ACCEPT: if there are three or more blues! 要求接受纸带中有至少3个蓝点的机器人。8个元件,112570时间。 Level 4: Robofish! ACCEPT: if a robot contains NO red! 要求接受没有红点的机器人。4个元件,32764时间。 Level 5: Robobugs! ACCEPT: if the tape has only alternating colors! 如果纸带上的颜色是交替出现的(没有连续的红色或蓝色)就接受。6个元件,32900时间。 Level 6: Robocats! ACCEPT: if the tape ends with two blues! 如果最后两个颜色是蓝色则接受。11个元件,182272时间。 Level 7: Robobears! ACCEPT: Strings that begin and end with the same color! 如果第一个和最后一个色点颜色相同则接受。注意没有色点和只有一个色点这两种特殊情况。15个元件,176136时间。 Level 8: RC Cars! OUTPUT: The input, but with the first symbol at the end! 把第一个色点放到最后去。7个元件,49144时间。 Leve 9: Robocars! OUTPUT: Replace blue with green, and red with yellow! 把蓝色和红色分别换成了绿色和黄色。7个元件,229374时间。 Level 10: Robostilts! OUTPUT: Put a green at the beginning and a yellow at the end! 在色带的最前端放一个绿色,末尾处放一个黄色。毫无悬念,9个元件,53244时间。 Level 11: ACCEPT: With blue as 1 and red as 0, accept odd binary strings! 只接受奇数数字,也就是最后一位是蓝色的。至于空色带就无所谓了,严格来讲应该是不接受,但至少这个版本里没有这样的测试数据。8个元件,167931时间。 Level 12: Soldiers! OUTPUT: With blue as 1 and red as 0, multiply by 8! 要把输入的数字乘以8,程序员对这个应该是得心应手了,再末尾添加三个0(红色)即可。7个元件,65520时间。 Level 13: Officers! OUTPUT: With blue as 1 and red as 0, add 1 to the binary string! 给输入的数字做加1操作。开始的时候感觉是无法完成的,但仔细想想就很简单。加1操作,从二进制的角度来看,就是把末尾的1都变成0,最后一个0变成1。主要的难点是要从最后一位往前加,所以要不端地循环,每次都处理最后一个没有处理过的色点。另外在优化的时候发现,可以先把末尾的1变成黄色,这样就不需要再另外使用分隔符号了。分隔符用来标记字串的中止以及当前处理到的位置。 19个元件,81580时间。 Level 14: Generals! OUTPUT: Substract 1 from the binary string! (Input >= 1) 减1操作,跟第13关其实是一样的,红色和蓝色互换就好了。19个元件,79750时间。 但这一关还可以再稍微调整一下布局,变成18个元件,81686时间。 Level 15: Robotanks! ACCEPT: With blue as 1 and red as 0, accept binary strings > 15! 要求接受大于15的数字。也就是要求大于或等于16,即1后面至少有四个二进制位。于是就是要判断第一个蓝色后面是否至少有四个色点,不论颜色。25个元件,19958时间。 Level 16: Robospies! ACCEPT: With blue as 1 and red as 0, accept natural powers of four! 要求接受4的幂,也就是第一个蓝色后面必须恰好有偶数(包括0)个红色色点。注意要忽略掉开头的红色。8个元件,57372时间。 Level 17: Androids! ACCEPT: Some number of blue, then the same number of red! 要求纸带上的色点必须是若干个蓝色后面跟着同样数量的红色。开始也是觉得很难,主要是没有办法计数。当然解决办法就是一次一次循环,每次循环中判断一对红蓝色点。对于这种需要循环处理的问题,我一般都用一个黄色作为分隔符作为字符串的终结标记。12个元件,63041时间。 Level 18: Robo-children! ACCEPT: An equal number of blue and red, in any order! 判断色带上蓝色和红色的数量是否恰好相等。依旧是每次循环检查一对。23个元件,266582时间。 Level 19: Police! OUTPUT: Put a yellow in the middle of the (even-length) string! 输入的色带上有偶数个色点(不用判断是否满足),要求在中间位置插入一个黄色。这一关开始想了好久,排满了整个棋盘才搞定,后来一直优化到40个元件。想到了两种方案,一种是在颜色串的首尾各放一个色点,每次循环的时候让两个色点分别向中间移动一格,直到二者相遇。另一种是用起始位置放两个色点,每次循环的时候一个色点往后移动一格,另一个色点往后移动两个。我最后的优化版是采用第二种方法的。40个元件,291584时间。 如果输入的色带上有奇数个色点,那我的算法会在中间色点的后方插入黄色。 Level 20: Judiciary! ACCEPT: (Even-length) strings that repeat midway through! 判断色带上的色点(偶数个)是否恰好前半部分与后半部分的排列完全一样。比如如果前半部分是红蓝红红蓝,后半部分也必须是红蓝红红蓝。这一关我是直接利用了第19关和第29关(恰好我是先完成了第29关才回过头玩的这关),即先给这个颜色串的中间位置添加一个黄色(直接照搬第19关的布局),然后利用第29关的布局判断黄色分割的两个子串是否完全一致。 52个元件,319428时间。 Level 21: Teachers! ACCEPT: X blue, then X red, then X more blue, for any X! 要求色带上恰好是有若干个蓝色,跟着同样数目的红色和另外同样数目个蓝色。也可以是一个色点都没有。跟第17关的算法完全一样,只要再考虑考虑布局即可。 20个元件,76590时间。 Level 22: Politicians! ACCEPT: If there are exactly twice as many blues as red! 判断色带上蓝色是否恰好是红色的两倍。这一关其实跟第18关没有太大区别,一个简单高效的解决办法就是先把蓝色减半,然套用第18关的布局来检测减半后的蓝色是否与红色数目相等。 给蓝色减半的时候,比较传统的办法是用一个黄色作为色串终止符,从头开始,每读到一个红色就写一个红色,读到两个蓝色之后写一个蓝色。或着稍微变化一下,不用额外的黄色作终止符,而是在遍历的时候直接用黄色替换红色,用一个绿色替换两个蓝色。 用29个元件,296870时间。 Level 23: Academics! OUTPUT: Reverse the input string! 把输入的颜色串反转。基本的方法就是把第一个色点放到色串的最后,再把第二个色点放到倒数第二位。除了用一个黄色标记色串的终止外,在用一个绿色分割尚未处理的色串和部分反转了的色串。 用25个元素,227328时间。 Level 24: Engineers! ACCEPT: Perfectly symmetrical strings! 判断颜色串是否是对称的。也比较简单啦,每次用第一个色点做分支,在每个分支里判断最后一个色点,如果跟第一个一样则继续,否则丢弃。用25个元件,47696时间。 Level 25: Roborockets! OUTPUT: Swap blue for red, and red for blue! 把红蓝颜色互换。毫无悬念,7个元件,229374时间。 Level 26: Roboplanes! OUTPUT: All of the blue, but none of the red! 保留输入中的所有蓝色,丢掉红色。跟第25关唯一的区别就是遇到红色后不再写回到色带上。7个元件,22526时间。 Level 27: Rocket Planes! OUTPUT: The input, but with all blues moved to the front! 把输入中的蓝色都移动到红色的前面。 这一关有点儿意思,我最后设计的方法是直接利用第23关反转输入的方法。在第23关的布局中,中轴线左边是针对第一个是蓝色的处理,右边是针对第一个是红色的处理。在这一关里依旧保留右半边,但把左半边改成遇到蓝色就直接写一个蓝色回去。最后的效果就是不断地把红色往最后写,直到红色全都聚集到后半部分。 用16个元件,12390时间。 Level 28: Robomecha! OUTPUT: The input, but with the last symbol moved to the front! 把最后一个色点放到最前面。很简单,19个元件,606214时间。 Level 29: Seraphim! ACCEPT: Two identical strings, separated by a green! 判断由绿色点分开的两个色串是否完全相等。也挺简单的,补一个绿色作为终止符,取出色串一的第一个颜色,把其他的写回纸带,判断色串二的第一个颜色跟它是否一样;这时候两个色串都去掉了第一个颜色,而且刚好色串二跟色串一交换了顺序,再重复用同样的方法判断下去即可。21个元件,166182时间。 Level 30: Ophanim! ACCEPT: Read the tape as two numbers, A and B, split by a green: accept if A > B! 由绿色点分开的两个色串,从二进制数字的角度判断是否前一个数大于后一个数。 我用的方法是求B - A,当然不用记录完整的结果,只要记录借位状态即可。不过我没有再进行优化,现在用了88个元件,60617时间。估计能优化掉一小半的元件。 Level 31: Metatron! OUTPUT: Read the tape as two numbers, A and B, split by a green: output A + B! 计算被绿色分开的两个数字之和。基本上就是从最低位逐位加上去。同样是还没有优化,应该能减少一半以上的元件。现在用120个元件,108630时间。
愿你出走半生,归来仍是少年