扶苏是一个舞萌吃。她今天学习了如何编写舞萌的谱面!现在,她要来教一下你了。
舞萌是一款街机游戏,游戏框体共有两个机位,玩家可以单人游玩,亦可以双人组队,其玩法与大多数音乐游戏相似,音符则从屏幕中心向四周移动,玩家需要在合适的时机拍击按键或者触摸屏幕外侧,并达到一定分数才可通关。
图片来源:wikipedia
舞萌框体共有 8 个可供拍打的外键,写谱时以右上角为 1 号键,顺时针进行编号,如下所示:
舞萌谱面使用一种名为 s-simai (simplified-simai) 的语言进行编写。为了方便处理,我们对 s-simai 做进一步简化。
节拍与时值
一拍是谱面的一个基本时间单位,被称为一个四分音 或一个四分音符 。在本题中,可以认为一拍对应一个固定的时间长度,其具体数值并不重要,你无需区分接下来表述中音符的「时值」和「时长」,可以认为二者是统一的。如果你愿意,可以认为一拍是 秒,即一个四分音符占 秒的时间。
除了四分音符外,还有其他时长的音符。一个 分音符的时长是一拍的 倍。例如,一个 分音符的时长是一拍的一半,即半拍。如果一拍是 秒,则一个八分音占 秒。一个 分音符(虽然乐理中一般不采用「十二分音」这样的表述,但这里为了方便描述做了统一)的时长是一拍的 。我们保证 是 六个数字之一。
简化的 s-simai 语言一行表示若干个时长相同的音符,以 {x}, 开头,表示本行音符的时值(时长)。音符与音符之间以 , 分隔。例如,{16},A,B,C,D, 表示了接下来连续 个十六分音的音符分别是 A,B,C,D。多行 s-simai 表示的时间是连续的。例如:
就表示了连续的四个 分音和两个 分音的谱面,谱面的总长度是两拍。
接下来我们介绍音符的具体表示法。
休止符
如果在某一个时值内什么都不做,则谱面中当前音符为空,例如 {16},,,C,D, 表示前两个十六分音什么都不做(没有音符),后两个十六分音分别是 C,D 两个音符。
Tap 音符
Tap 音符需要在一个音符开始 的瞬间拍击某一个标号的按键,然后瞬间松开。在谱面中直接写出需要拍击的按键编号。例如,{16},1,,2,, 表示接下来一拍(四个 分音)内,在第一个和第三个 分音的开始时刻分别拍击 号和 号按键,第二个和第四个 分音里什么都不做。
如果同一个时刻要拍击多个按键,可以把按键的编号用 / 隔开。例如,{16},1/8,,2/7,, 表示在第一个 分音的开始时刻同时拍击 和 号键,在第三个 分音的开始时刻同时拍击 和 号键。
Hold 音符
这是一种需要持续按压的音符,用 ph[x:y] 表示在 号键上出现一个 Hold 音符,在当前分音开始的瞬间开始按压,持续按压 个 分音符的长度, 保证 是 六个数字之一。例如,{16},1h[8:1],,2h[8:1],, 表示在第一个 分音的开始时刻起按压 号键,持续时间为 个八分音符,即在第二个 分音的结束时刻(也是第三个 分音的开始时刻)松开按压;然后在第三个 分音的开始时刻类似地按压 号按键。同样的,在同一时刻拍击的多个 Hold 音符也可以用 / 分隔;/ 也可以用于分隔 Tap 音符和 Hold 音符。例如,下面的谱面都是合法的:
{4},1h[4:1]/2h[4:1],
{4},1h[4:1]/2,
{4},1h[4:1]/2/3,
{4},1/2/3,
{4},1h[4:1]/2h[8:1],
我们保证 / 分隔开的按键编号 是不同的,即不会出现 {4},1/1 或 {4},1/1h[8:1] 这样的情况。
无理检测
因为你只有两只手,所以谱面必须保证在任何时刻,都只有至多 两个按键被按下(含拍击)。类似这样的谱面被称为多押无理 :{16},1h[8:1]/2h[8:1],3,,因为在第二个 分音开始时,你的两只手分别正在按压 号和 号按键,没有多余的手来按压 号按键。特别的,{16},1h[8:1]/2h[8:1],,3,, 也是多押无理,因为 Hold 音符结束时刻(第二个 分音结束时)和 Tap 拍击时刻(第三个 分音开始时)是同一个时刻。
在 Hold 音符持续过程内,按键持续处于按下状态,因此无法拍击同一位置上的 Tap 音符。因此这样的谱面被称为嵌套无理 :{16},1h[8:1],1,,因为第二个 分音开始时, 号键处于按下状态,无法拍击。在一个 Hold 音符的结束时刻于同一按键出现一个 Tap 音符也属于嵌套无理,如 {16},1h[16:1],1。
给定一个 s-simai 谱面,你需要判定该谱面是否含有上述两种无理。