Derrube alguns dominós!

22

Obrigado a esta pergunta por alguma inspiração

Neste desafio, representaremos uma linha de dominó como uma sequência de |, /e \. Você receberá uma sequência de dominós como entrada e deverá determinar como eles se parecerão quando se estabelecerem. Aqui estão as regras de como os dominós caem

  • Um dominó em pé |, à esquerda de um dominó caído à esquerda \, também se tornará um dominó caído à esquerda.

  • Um dominó em pé |, à direita de um dominó caído à direita /, também se tornará um dominó caído à direita.

  • Se um dominó em pé estiver entre um dominó caído à esquerda \e um /dominó caído à direita , ele permanecerá em pé.

Essas regras são aplicadas repetidamente até que o arranjo não seja mais alterado.

Aqui está um exemplo de como uma única entrada pode chegar à sua conclusão

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

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

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

Sua tarefa é escrever um código que encontre e produz o resultado final de uma entrada. Você pode assumir que a entrada é sempre válida e contém pelo menos 2 caracteres.

Isso é então as respostas serão pontuadas em bytes, com menos bytes sendo melhores.

Casos de teste

|||/||||  -> |||/////
|||\||||  -> \\\\||||
|/||||\|  -> |///\\\|
||/|||\|  -> ||//|\\|
||\|||/|  -> \\\|||//
Assistente de Trigo
fonte
6
Barra invertida escapando ahoy! (Que possamos usar outros símbolos?)
Arnauld
1
@ Arnauld Não, você deve usar as barras.
Assistente de trigo
1
Eu não posso ... descobrir o que escapar e o que não.
totallyhuman
A entrada será uma string vazia ou um único caractere?
Maçaneta
3
Incomoda-me mais do que deveria que coisas como `//////// | | sejam consideradas estáveis.
MooseBoys

Respostas:

13

Retina , 32 bytes

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

Experimente online!

Explicação

Ele +informa ao Retina para executar a substituição em um loop até que ele não mude a string. Cada substituição calcula uma etapa dos dominós em queda. A substituição em si é realmente três substituições em uma, mas isso garante que elas ocorram simultaneamente:

(/.\\)...
$1

Isso apenas corresponde /|\(bem como /\\e /\\, mas não importa) e reinsere-o inalterado. O objetivo disso é pular |com dominó caído de ambos os lados, porque isso é mais curto do que excluir os casos com olhares separados nos outros dois casos.

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

Isso corresponde /|e o transforma //.

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

Isso corresponde |\e o transforma \\.

Martin Ender
fonte
Não posso dizer que não vi isso chegando. A retina é certamente uma boa ferramenta para o trabalho.
Assistente de trigo
@WheatWizard É fácil de resolver, mas provavelmente ainda é muito detalhado com todos os elementos que escapam e que $1$2$2$3$3superam os idiomas do golfe.
Martin Ender
5

Python 2 , 115 114 111 108 98 95 bytes

-1 byte graças a ovs

a=input()
for i in range(4)*len(a):a=a.replace('//|x||\ \\'[i::4],'/\/x|\/ \\'[3-i::4])
print a

Experimente online!

Cajado
fonte
114 bytes usando strings-r.
ovs 05/01
Você pode remover b=0;e substituir ocorrências de bpor idpara salvar dois bytes!
Lynn
4

V , 23 bytes

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

Experimente online!

Realmente, isso é muito semelhante à resposta da retina, apenas que parece mais feia. Usa compactação regex.

Hexdump:

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

Explicação:

òdiz ao V para executar até que a string não mude. O restante é um regex compactado. Vamos convertê-lo no equivalente 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
DJMcMayhem
fonte
4

SNOBOL4 (CSNOBOL4) , 117 115 112 111 bytes

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

Experimente online!

Agradecemos à resposta python de Rod pela idéia da condição de parada com uma segunda variável para ver as alterações em vez de testar 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
Giuseppe
fonte
3

Haskell , 114 107 bytes

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

Experimente online! A primeira linha define uma função anônima.

Explicação:

  • until=<<((==)=<<)$gé uma função de ponto de correção (veja aqui para obter uma explicação) que aplica a função gà sequência de entrada até que o resultado não seja mais alterado.
  • zip3('|':s)s(tail s++"|")cria para cada dominó, que é caractere na sequência s, um triplo com o dominó anterior e posterior, preenchendo |as bordas. Por exemplo, /\|torna-se [(|,/,\),(/,\,|),(\,|,|)](ignorando a fuga).
  • Em seguida, a função té aplicada a cada um dos triplos para calcular a nova posição da peça central do triplo.
Laikoni
fonte
2

Perl 5 , 39 + 1 ( -p) = 40 bytes

s%(?<!/)\|(\\)|(/)\|(?!\\)%$+$+%g&&redo

Experimente online!

Xcali
fonte
2

Prolog (SWI) , 132 bytes

+[]-->[].
+[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).

Experimente online!

Este programa define um predicado +/2verdadeiro se o segundo argumento for a versão estabelecida do primeiro. Ambos os argumentos são listas de códigos de caracteres.

Explicação

Esta solução usa um DCG para descobrir qual é o próximo passo e, em seguida, calcula repetidamente o próximo passo até que o próximo seja o mesmo que o passo atual.

O DCG

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

Essas cinco linhas de código definem uma regra DCG (gramática de cláusula definida) +usada no programa para calcular uma única etapa de tombamento do dominó. Os DCGs do Prolog trabalham localizando o primeiro caso da regra cujo lado direito corresponde à sequência e determinando o argumento da regra no lado esquerdo durante esse processo. Se um caso não corresponder, ele retornará e tentará um caso posterior.

+[]-->[].

Esta linha representa o caso base da +regra. Simplesmente afirma que, se não houver dominó atualmente, na próxima etapa ainda não haverá dominó.

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

Uma vez que este programa trata exclusivamente com listas de códigos de caracteres, é importante notar que os códigos de caracteres para /, \e |são 47, 92, e 124, respectivamente. Este caso da +regra lida com a /|\sequência.

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

Este gabinete lida com um dominó caindo à direita, derrubando o dominó à sua direita. Como vem após o caso de manuseio /|\, não será usado para essa possibilidade.

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

Lida com o caso de um dominó caindo à esquerda, derrubando o dominó à esquerda dele.

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

Este é o caso curinga. Como nada mais muda além do descrito acima, enquanto houver texto na string de entrada, ele será copiado para a saída, desde que não corresponda a nenhum dos casos acima.

O Predicado

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

O predicado principal recebe dois argumentos, o primeiro é a configuração inicial do dominó, o segundo é o dominó estabelecido. Como este é o Prolog, o segundo pode ser indeterminado e o programa o calculará. O predicado em si é bastante simples: +(N,X,[])chama o DCG e calcula a próxima etapa dos dominós que o armazenam N. (X=N,Y=N;N+Y)verifica se o próximo passo do dominó é o mesmo que o atual e se for definido Y, pois os dominós devem ter se estabelecido e, se não for, ele se repete, chamando o mesmo predicado com o próximo passo do dominó em Nvez de X.

0 '
fonte
1

face , 166 bytes

\|/,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*>

Recebe a entrada como argumento da linha de comando e gera para STDOUT. Isso funciona apenas na confirmação 86494f6 e além devido a uma correção de bug nessa confirmação.

Embrulhado para estética:

\|/,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*>

E ungolfed / comentou:

\|/,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 )

Há alguns truques sutis aqui que eliminam alguns bytes extras, como

  • a nomeação das variáveis ​​| e /, cujos valores ASCII são acessados ​​via introspecção posteriormente no código

  • o '|na primeira linha do loop principal, que é chamado lá em vez de na segunda linha para definir o | ponteiro para uso na segunda seção do loop principal

Maçaneta da porta
fonte
1

Perl 5 , 52 + 1 (-p) = 53 bytes

-6 bytes graças a mik

Provavelmente não é o melhor possível para Perl, mas é o que eu poderia fazer.

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

Explicação

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
)

Experimente online!

Geoffrey H.
fonte
-pem vez de -aeliminar a necessidade print;; utilizando whilecomo um sufixo de uma expressão simulado (por exemplo 0) irão poupar mais 2 bytes
Mik
Obrigado @mik, eu não conhecia esses truques. Também sei que poderia delimitar o regex com outra coisa para salvar alguns bytes. Pode chegar a isso mais tarde.
Geoffrey H.
1

Perl 5 , 44 (código) + 1 ( -p) = 45 bytes

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

Experimente online!

Explicação

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 \\
mik
fonte
1

Limpo , 98 bytes

import StdEnv
$['/|':t]=['//': $t]
$['|\\':t]=['\\\\': $t]
$[h:t]=[h: $t]
$e=e
f=until(\e=e== $e)$

Experimente online!

Furioso
fonte
0

Ruby , 83 bytes

Tecnicamente enganável com 9.times, ou mesmo apenas, 999.timesmas não sinto vontade de ser barato :)

Ainda tem um enorme potencial de golfe. (Nota: y while undoneé muito mais longo que x.size.times)

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

Experimente online!

Unihedron
fonte
0

R , 114 bytes

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

Experimente online!

Retorna uma string de escape.

Giuseppe
fonte
0

C (gcc) , 183 bytes

D,i;f(char*S){char*s=malloc(-~strlen(S));for(D=1;D--;strcpy(S,s))for(strcpy(s,S),i=0;s[i];i++)s[i]>92&&(S[-~i]==92&&S[~-i]!=47&&(s[i]=92,D=1)||S[~-i]==47&&S[-~i]!=92&&(s[i]=47,D=1));}

Experimente online!

Jonathan Frech
fonte