推倒一些多米诺骨牌!


22

感谢这个问题的启发

在这个挑战,我们将代表一行多米诺骨牌作为串|/\。您将获得一串多米诺骨牌作为输入,并且必须确定它们安定后的样子。这是多米诺骨牌掉落的规则

  • |左下降的多米诺骨牌左侧的立式多米诺骨牌\也将变为左下降的多米诺骨牌。

  • |正确的多米诺骨牌的立式多米诺骨牌/也将变成正确的多米诺骨牌。

  • 如果站立的多米诺骨牌介于左\下落的/多米诺骨牌和右下落的多米诺骨牌之间,它将保持站立状态。

重复应用这些规则,直到排列不再更改。

这是单个输入如何得出结论的示例

|||||||\/|||||||\||\|||/||||||\|||||

||||||\\//|||||\\|\\|||//||||\\|||||
|||||\\\///|||\\\\\\|||///||\\\|||||
||||\\\\////|\\\\\\\|||////\\\\|||||
|||\\\\\////|\\\\\\\|||////\\\\|||||
||\\\\\\////|\\\\\\\|||////\\\\|||||
|\\\\\\\////|\\\\\\\|||////\\\\|||||

\\\\\\\\////|\\\\\\\|||////\\\\|||||

您的任务是编写查找并输出输入最终结果的代码。您可以假定输入始终有效,并且至少包含2个字符。

这是因此答案将以字节计分,而字节数越少越好。

测试用例

|||/||||  -> |||/////
|||\||||  -> \\\\||||
|/||||\|  -> |///\\\|
||/|||\|  -> ||//|\\|
||\|||/|  -> \\\|||//

6
反斜杠转义了哦!(我们可以使用其他符号吗?)
Arnauld

1
@Arnauld不,您应该使用斜杠。
小麦巫师

1
我不能...弄清楚该逃避什么,不逃避什么。
–totalhuman

输入的内容是空字符串还是单个字符?
门把手

3
像`///////// | \之类的东西被认为是稳定的东西,这让我感到不安。
MooseBoys

Answers:


13

视网膜,32字节

+`(/.\\)|(/)\||\|(\\)
$1$2$2$3$3

在线尝试!

说明

+告诉视网膜直到它不能改变字符串运行在一个循环的替代品。每个替换计算下降的多米诺骨牌一步。替换本身实际上是三个替换之一,但这确保了它们同时发生:

(/.\\)...
$1

这只是匹配/|\(以及/\\/\\,但没有关系),然后将其重新插入不变。这样做的目的是跳过|两边倒下的多米诺骨牌,因为这比在其他两种情况下用单独的环视排除那些情况要短。

...(/)\|...
$2$2

匹配/|并将其转换为//

...\|(\\)
$3$3

匹配|\并将其转换为\\


不能说我没有看到那件事。视网膜无疑是完成这项工作的好工具。
小麦巫师

@WheatWizard易于解决,但可能在所有转义上仍然太冗长,$1$2$2$3$3无法击败高尔夫语言。
马丁·恩德


4

V,23个字节

òÓ¯À<!|¨Ü©ü¨¯©|ÜÀ!/±±²²

在线尝试!

确实,这与视网膜答案非常相似,只是看起来丑陋。使用正则表达式压缩。

十六进制转储:

00000000: f2d3 afc0 3c21 7ca8 dca9 fca8 afa9 7cdc  ....<!|.......|.
00000010: c021 2fb1 b1b2 b2                        .!/....

说明:

ò告诉V运行直到字符串不变。其余的是压缩的正则表达式。让我们将其转换为等价的vim ...

:s/\v\/@<!\|(\\)|(\/)\|\\@!/\1\1\2\2/g

:s/                                     " Substitute...
   \v                                   " Turn on magic (use less escaping)
          \|                            " A bar
            (\\)                        " Followed by a captured backslash
       @<!                              " That is not preceded by
     \/                                 " A forward slash
                |                       " OR...
                 (\/)                   " A captured forward slash
                     \|                 " Followed by a bar
                       \\@!             " That is not followed by a backslash
                           /            " Replace this with
                            \1\1        " Pattern 1 twice (will be empty if we matched the second path)
                                \2\2    " Pattern 2 twice (will be empty if we matched the first path)
                                    /g  " Replace every match on this line

4

SNOBOL4(CSNOBOL4) 117个 115 112 111字节

	D =INPUT
S	D '/|\' ='_'	:S(S)
	E =D
	D '/|' ='//'
	D '|\' ='\\'
	D E	:F(S)
R	D '_' ='/|\'	:S(R)
	OUTPUT =D
END

在线尝试!

值得一提的是Rod的python答案,它给出了停止条件的想法,并带有第二个变量来查看更改而不是测试D '/|' | '|\'

	D =INPUT		;* read input
S	D '/|\' ='_'	:S(S)	;* replace '/|\' with '_', recursively
	E =D			;* set E to D, this is the while loop
	D '/|' ='//'		;* topple right
	D '|\' ='\\'		;* topple left
	D E	:F(S)		;* if D doesn't match E, goto S
R	D '_' ='/|\'	:S(R)	;* replace '_' with '/|\' (inverse of statement S)
	OUTPUT =D		;* output
END

3

Haskell中114个 107字节

until=<<((==)=<<)$g
g s=t<$>zip3('|':s)s(tail s++"|")
t(l,'|',r)|l<'0',r/='\\'=l|r=='\\',l>'/'=r
t(_,e,_)=e

在线尝试!第一行定义了一个匿名函数。

说明:

  • until=<<((==)=<<)$g是一个定点函数(请参阅此处以获取解释),该函数将函数应用于g输入字符串,直到结果不再更改为止。
  • zip3('|':s)s(tail s++"|")为每个多米诺骨牌(即字符串中的字符)创建一个,在前和后一个多米诺骨牌上添加s一个三元组,并|在边缘填充。例如,/\|变成[(|,/,\),(/,\,|),(\,|,|)](忽略转义)。
  • 然后将该函数t应用于每个三元组,以计算该三元组中心部分的新位置。


2

Prolog(SWI),132字节

+[]-->[].
+[47,124,92|T]-->"/|\\",+T.
+[47,47|T]-->"/|",+T.
+[92,92|T]-->"|\\",+T.
+[X|T]-->[X],+T.
X+Y:- +(N,X,[]),!,(X=N,Y=N;N+Y).

在线尝试!

+/2如果第二个参数是第一个参数的稳定版本,则此程序定义的谓词为true。这两个参数都是字符代码列表。

说明

此解决方案使用DCG找出下一步,然后重复计算下一步,直到下一步与当前步骤相同为止。

DCG

+[]-->[].
+[47,124,92|T]-->"/|\\",+T.
+[47,47|T]-->"/|",+T.
+[92,92|T]-->"|\\",+T.
+[X|T]-->[X],+T.

这五行代码定义了DCG(定值子句语法)规则+,该规则在程序中用于计算多米诺骨牌倒塌的单个步骤。Prolog中的DCG通过查找规则右手匹配字符串的第一种情况并在该过程中确定规则左手的参数来工作。如果案例不匹配,则它将回溯并尝试以后的案例。

+[]-->[].

该行表示+规则的基本情况。它仅声明如果当前没有多米诺骨牌,那么在下一步中将仍然没有多米诺骨牌。

+[47,124,92|T]-->"/|\\",+T.

由于此程序的字符代码列表,专用于处理它要注意的是,对于字符代码/\以及|分别为47%,92%和124。+规则的这种情况处理/|\字符串。

+[47,47|T]-->"/|",+T.

这种情况下处理一个右下降的多米诺骨牌,将多米诺骨牌撞到它的右边。由于它是在处理案件之后进行的,/|\因此不会用于这种可能性。

+[92,92|T]-->"|\\",+T.

处理左下降的多米诺骨牌撞倒其左侧的多米诺骨牌的情况。

+[X|T]-->[X],+T.

这是通配符的情况。由于除了上面描述的内容外,其他都没有改变,因此只要输入字符串中剩余文本,只要它与上述任何情况都不匹配,就将其复制到输出中。

谓词

X+Y:- +(N,X,[]),!,(X=N,Y=N;N+Y).

主要谓词有两个参数,第一个是初始多米诺骨牌设置,第二个是已解决的多米诺骨牌。由于这是Prolog,因此可以不确定第二个,程序将对其进行计算。谓词本身非常简单,+(N,X,[])称为DCG,并计算将其存储在中的多米诺骨牌的下一步N(X=N,Y=N;N+Y)检查多米诺骨牌的下一个步骤是否与当前步骤相同,是否设置Y为当前步骤,因为多米诺骨牌必须已经稳定,如果不是,则递归,请使用下一步的多米诺骨牌调用相同的谓词,N而不是X



1

,166字节

\|/,cm_/o>AvI[IIcP/+PP|m_/m*/Sl*Im1/11:~-_I|'|?_1-_P|?_1`I-III_|+II|'I.C:1-_I|?_C'|-_P|?_C_|'I-_I|`I?_!'I.C:!'|'|-III+II|'I:C_|-PPP+PPI'I?I~_I-PPP+PP|-**1?*~Sl*Iw*I*>

将输入作为命令行参数并输出到STDOUT。由于该提交中的错误修复,因此仅在提交86494f6中有效。

为美观包装:

\|/,cm_/o>AvI[IIcP/+PP|m_/m*/Sl*Im1/11:~-_I|'|?_1-_P|?_1`I
-III_|+II|'I.C:1-_I|?_C'|-_P|?_C_|'I-_I|`I?_!'I.C:!'|'|-III
+II|'I:C_|-PPP+PPI'I?I~_I-PPP+PP|-**1?*~Sl*Iw*I*>

并取消/评论:

\|/,cm_/o>              ( setup )

AvI[II                  ( store input into I )
cP/+PP|m_/              ( store 92, ascii for \, into P, meaning prev char )
m*/Sl*Im1/11            ( store length of input into counter variable * )

( main loop: )
:~

    -_I|'|?_1           ( branch to 1 if the character is not \ )
    -_P|?_1             ( also branch to 1 if the previous character wasn't | )
    `I-III_|+II|'I      ( we have a sequence |\ so prev needs to be toppled )
    .C                  ( jump to C, the "continue" label at end of loop )

    :1
    -_I|?_C             ( branch to C if the character is not | )
    '|-_P|?_C           ( also branch to C if the previous character wasn't / )
    _|'I-_I|`I?_!       ( branch to ! if the next character isn't \ )
    'I.C:!              ( otherwise, skip the next \ and branch to continue )
    '|'|-III+II|'I      ( if all conditions hold we have /|| or /|/ so topple )

    :C
    _|                  ( reset pointer to source )
    -PPP+PPI            ( update prev variable )
    'I                  ( step through data )

?I~

_I-PPP+PP|-**1          ( reset input/prev and decrement counter )
?*~                     ( repeat main loop as many times as there are chars )

Sl*Iw*I*>               ( output final string to stdout )

这里有一些巧妙的技巧可以节省一些额外的字节,例如

  • 变量的命名| 和/,其ASCII值可通过代码中的自省访问

  • '|主循环的第一行上,而不是在第二行上调用,以设置| 主循环第二部分中使用的指针


1

Perl 5、52 + 1(-p)= 53字节

-6个字节,感谢mik

对于Perl来说,可能并不是最好的选择,但这就是我能想到的。

0while(s/(?<!\/)\|(?=(\\))|(?<=(\/))\|(?!\\)/$1$2/g)

说明

while(
  s/
    (?<!\/)\|(?=(//)) # If there's a | that precedes a \ but doesn't follow a /, capture /
      | # Or
    (?<=(\/))\|(?!//)/ # If there's a | that follows a / doesn't precede a \, capture /
  /$1$2/ # Replace all | with capture group 1 or 2, as one of the two will always be empty
  g # Repeat as much as possible for this string
)

在线尝试!


-p而不是-a消除需求print;; 使用while作为后缀的虚设表达(例如0)将节省另一个2个字节
MIK

谢谢@mik,我不知道这些技巧。我也意识到我可以用其他东西来分隔正则表达式以节省一些字节。可能稍后再说。
Geoffrey H.

1

Perl 5、44(代码)+ 1(-p)= 45字节

1while s,(/)\|(?!\\)|(?<!/)\|(\\),$1$1$2$2,g

在线尝试!

说明

1while s,                        ,        ,g   while anything found substitute globally
         (/)\|(?!\\)              $1$1         /| that is not followed by \ to //
                    |                          or
                     (?<!/)\|(\\)     $2$2     |\ that is not preceded by / to \\


0

红宝石,83个字节

从技术上讲9.times,或者甚至只是作弊,999.times但我不觉得自己便宜:)

仍有巨大的高尔夫潜力。(注意:y while undone比更长x.size.times

->x{x.size.times{x.gsub! /\/\|\\?|\|\\/,'/|\\'=>'/|\\','/|'=>'//','|\\'=>'\\\\'}
x}

在线尝试!


0

R,114字节

function(d){g=gsub
for(i in 1:nchar(d))d=g("/|","//",g("|\\","\\\\",g("/|\\","_",d,f=T),f=T),f=T)
g("_","/|\\",d)}

在线尝试!

返回一个转义的字符串。


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.