可能的俄罗斯方块序列


11

编写代码以弄清楚官方的Tetris算法是否可以生成一系列Tetris。最少的字节数获胜。


官方的俄罗斯方块游戏以特殊方式生成掉落序列。IJLOSTZ以随机顺序删除这七个片段,然后删除另一个随机排列,依此类推。

JTLOISZ STJOLIZ LISJOTZ ...

此示例包含连续的片段

SZSTJOLIZLIS

请注意,它跨越了一个由7组组成的边界。

SZOTLZSOJSIT

不能是任何俄罗斯方块序列的子字符串,因此在正式的俄罗斯方块游戏中永远不会看到它。


输入:一个非空的字母字符串IJLOSTZ

输出:一个True或Falsey值,表示输入是官方Tetris Random Generator可以生成的序列的子字符串,即七个字母的排列的串联。

测试用例:

真正:

T
JJ                        (unique breakdown: J J)
JTJ                     (possible breakdown: JT J)
LTOZIJS
SZSTJOLIZLIS            (possible breakdown: SZ STJOLIZ LIS)
JTLOISZSTJOLIZLISJOTZ   (possible breakdown: JTLOISZ STJOLIZ LISJOTZ)  
LIJZTSLIJZTS              (unique breakdown: LIJZTS LIJZTS)

假:

SZOTLZSOJSIT
ZZZ
ZIZJLJ
ZJLJLZITSOTLISOJT
JTLOISZSTJOLIZLISJOTZLJTSZLI
IOJZSITOJZST
LIJZTSLIJZTSL

排行榜

图片由MartinBüttner提供

Answers:


6

Pyth,16 15字节

sm*F.{Mc+>Gdz7T

打印0代表false,显示正整数代表true。


6

CJam,23 20 16字节

q7{\+_7/_Lf|=},&

归功于Sp3000减少了4个字节!

它打印出一串数字作为真实值,或不打印任何数字作为虚假值(在打印之前,这些数字实际上是一个非空或空列表,在CJam中确实是虚假或虚假的)。

在这里测试。

说明

这只是将输入的所有7个可能的分区检查为大块。

q      e# Read the input
7{     e# Select the numbers from 0 to 6 for which the following block is true.
  \+   e#   Prepend the number to the input. This shifts the string by one cell
       e#   without adding non-unique elements.
  _7/  e#   Make a copy and split into chunks of 7.
  _Lf| e#   Remove duplicates from each chunk.
  =    e#   Check if the last operation was a no-op, i.e. that there were no duplicates.
},
&      e# The stack now contains the input with [6 5 ... 1 0] prepended as well as a list
       e# of all possible splittings. We want to get rid of the former. To do this in one
       e# byte we take the set intersection of the two: since we've prepended all the
       e# integers to the list, this will always yield the list of splittings.

4

视网膜61 55字节

^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$

由于这只是一个正则表达式,因此Retina将以Match模式运行,并报告找到的匹配数,这将1用于有效序列或0其他情况。与打高尔夫球的语言相比,这没有竞争力,但是我对此感到非常满意,因为我从一个260字节的怪物开始。

说明

^((.)(?<!\2.+))*

该位使用可变长度的唯一字母的前缀,即,它与可能不完整的前导块匹配。向后查找确保此位中匹配的任何字符之前都没有出现在字符串中。

现在,对于其余的输入,我们希望匹配7个数据块而不重复字符。我们可以匹配这样的块:

(.)(?!.{0,5}\1)(.)(?!.{0,4}\2)(.)(?!.{0,3}\3)...(.)(?!.?\5).

也就是说,我们匹配一个在另外6个字符中不出现的字符,然后匹配在另外5个字符中不出现的一个字符,依此类推。但这需要相当糟糕的代码重复,而且我们必须分别匹配一个尾随(可能不完整)的块。

平衡团体以营救!另一种匹配方式

(.)(?!.{0,5}\1)

是将5个空匹配项推入捕获堆栈并尝试将其清空:

(){5}(.)(?!(?<-1>.)*\2)

与一样,*允许最少重复零次,{0,5}并且由于我们已进行了5次捕获,因此两次弹出均不能超过5次。对于此模式的单个实例,此时间更长,但是可重用性更高。由于我们以前瞻方式进行弹出,因此一旦前瞻完成,这不会影响实际的堆栈。因此,在进行前瞻之后,无论内部发生了什么,我们仍然有5个元素在堆栈上。此外,我们可以在每次超前之前从堆栈中弹出一个元素,然后在循环中运行代码,以自动将超前宽度从5减小到0。因此,实际上很长的位实际上可以缩短为

(){7}((?<-1>)(.)(?!(?<-1>.)*\1\3))*

(您可能会注意到两个区别:我们将7而不是5压入了一个。另外一个捕获是因为我们每次迭代之前弹出,而不是每次迭代之后弹出。实际上是有必要的,这样我们才能从堆栈中弹出7次(因为我们想要循环运行7次),我们可以通过确保\1堆栈上至少还有一个元素来修复超前查询中的一对一错误。)

这样做的好处是它也可以匹配尾随的不完整块,因为我们从未要求它重复7次(这只是必要的最大值,因为我们不能从堆栈中弹出更多次了)。因此,我们要做的就是将其包装在另一个循环中,并确保已到达字符串的末尾以获取

^((.)(?<!\2.+))*((){7}((?<-4>)(.)(?!(?<-4>.)*\4\6))*)*$
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.