Derribar algunas fichas de dominó!

22

Gracias a esta pregunta por alguna inspiración

En este desafío representaremos una línea de dominó como una cadena de |, /y \. Se le dará una serie de fichas de dominó como entrada y deberá determinar cómo se verán cuando se hayan asentado. Aquí están las reglas sobre cómo se caen las fichas de dominó

  • Un dominó de pie |, a la izquierda de un dominó caído a la izquierda \, también se convertirá en un dominó caído a la izquierda.

  • Un dominó de pie |, derecho de un dominó caído a la derecha /, también se convertirá en un dominó caído a la derecha.

  • Si un dominó parado está entre un dominó caído a la izquierda \y uno derecho /, permanecerá en pie.

Estas reglas se aplican repetidamente hasta que la disposición ya no cambie.

Aquí hay un ejemplo de cómo una sola entrada podría llegar a su conclusión.

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

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

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

Su tarea es escribir código que encuentre y genere el resultado final de una entrada. Puede suponer que la entrada siempre es válida y contiene al menos 2 caracteres.

Este es el por lo que las respuestas se puntuarán en bytes, con menos bytes mejor.

Casos de prueba

|||/||||  -> |||/////
|||\||||  -> \\\\||||
|/||||\|  -> |///\\\|
||/|||\|  -> ||//|\\|
||\|||/|  -> \\\|||//
Asistente de trigo
fuente
66
Backslash escapando ahoy! (¿Podemos usar otros símbolos?)
Arnauld
1
@Arnauld No, deberías usar las barras.
Wheat Wizard el
1
No puedo ... averiguar qué escapar y qué no.
Totalmente humano el
¿La entrada será alguna vez la cadena vacía o un solo carácter?
Pomo de la puerta
3
Me molesta más de lo que debería que cosas como `//////// | \ se consideren estables.
MooseBoys

Respuestas:

13

Retina , 32 bytes

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

Pruébalo en línea!

Explicación

El +le dice a Retina que ejecute el reemplazo en un bucle hasta que no pueda cambiar la cadena. Cada reemplazo calcula un paso las fichas de dominó que caen. El reemplazo en sí es realmente tres reemplazos en uno, pero esto asegura que sucedan simultáneamente:

(/.\\)...
$1

Esto solo coincide /|\(así como /\\y /\\, pero eso no importa) y lo reinserta sin cambios. El propósito de esto es saltar |con fichas de dominó caídas en ambos lados, porque esto es más corto que descartar aquellos casos con miradas separadas en los otros dos casos.

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

Esto coincide /|y lo convierte en //.

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

Esto coincide |\y lo convierte en \\.

Martin Ender
fuente
No puedo decir que no lo vi venir. La retina es ciertamente una buena herramienta para el trabajo.
Wheat Wizard
@WheatWizard Es fácil de resolver, pero probablemente aún demasiado detallado con todos los escapes y eso $1$2$2$3$3para vencer a los idiomas de golf.
Martin Ender
5

Python 2 , 115 114 111 108 98 95 bytes

-1 byte gracias a ovs

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

Pruébalo en línea!

Barra
fuente
114 bytes usando cadenas r.
ovs
¡Puede eliminar b=0;y reemplazar las ocurrencias de bby idpara guardar dos bytes!
Lynn
4

V , 23 bytes

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

Pruébalo en línea!

Realmente, esto es muy similar a la respuesta de la retina, solo que se ve más feo. Utiliza compresión regex.

Hexdump:

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

Explicación:

òle dice a V que se ejecute hasta que la cadena no cambie. El resto es una expresión regular comprimida. Convirtámoslo en el 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
fuente
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

Pruébalo en línea!

Gracias a la respuesta de Python de Rod por la idea de la condición de detención con una segunda variable para ver los cambios en lugar de probarlos 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
fuente
3

Haskell , 114107 bytes

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

Pruébalo en línea! La primera línea define una función anónima.

Explicación:

  • until=<<((==)=<<)$ges una función de punto fijo (vea aquí una explicación) que aplica la función ga la cadena de entrada hasta que el resultado ya no cambie.
  • zip3('|':s)s(tail s++"|")crea para cada dominó, es decir, el carácter de la cadena s, un triple con el dominó anterior y posterior, rellenando con |los bordes. Por ejemplo, se /\|convierte [(|,/,\),(/,\,|),(\,|,|)](ignorando el escape).
  • Luego, la función tse aplica a cada uno de los triples para calcular la nueva posición de la pieza central del triple.
Laikoni
fuente
2

Prólogo (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).

Pruébalo en línea!

Este programa define un predicado +/2que es verdadero si el segundo argumento es la versión establecida del primero. Ambos argumentos son listas de códigos de caracteres.

Explicación

Esta solución utiliza un DCG para determinar cuál es el siguiente paso y luego calcula repetidamente el siguiente paso hasta que el siguiente paso sea el mismo que el paso actual.

El DCG

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

Estas cinco líneas de código definen una regla DCG (Gramática de cláusula definida) +que se utiliza en el programa para calcular un solo paso de derribo del dominó. Los DCG en Prolog funcionan encontrando el primer caso de la regla cuyo lado derecho coincide con la cadena y determinando el argumento de la regla en el lado izquierdo a través de ese proceso. Si un caso no coincide, retrocederá e intentará un caso posterior.

+[]-->[].

Esta línea representa el caso base de la +regla. Simplemente establece que si no hay fichas de dominó actualmente, en el siguiente paso todavía no habrá fichas de dominó.

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

Desde este programa se ocupa exclusivamente de las listas de códigos de caracteres es importante tener en cuenta que los códigos de caracteres para /, \y |son 47, 92, y 124, respectivamente. Este caso de la +regla maneja la /|\cadena.

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

Este estuche maneja un dominó que cae a la derecha y derriba el dominó a la derecha. Como viene después del caso para el manejo /|\, no se usará para esa posibilidad.

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

Maneja el caso de un dominó que cae a la izquierda que derriba el dominó a su izquierda.

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

Este es el caso comodín. Como nada más cambia además de lo descrito anteriormente, siempre que quede texto en la cadena de entrada, simplemente lo copiará a la salida siempre que no coincida con ninguno de los casos anteriores.

El predicado

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

El predicado principal toma dos argumentos, el primero es la configuración inicial del dominó, el segundo es el dominó establecido. Como se trata de Prolog, el segundo puede ser indeterminado y el programa lo calculará. El predicado en sí mismo es bastante simple, +(N,X,[])llama al DCG y calcula el siguiente paso de las fichas de dominó que lo almacenan N. (X=N,Y=N;N+Y)comprueba si el siguiente paso de las fichas de dominó es el mismo que el actual y si es así Y, ya que las fichas de dominó deben haberse asentado y si no es así, vuelve a aparecer, llamando al mismo predicado con el siguiente paso de las fichas Nde dominó en lugar de X.

0 '
fuente
1

cara , 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*>

Toma la entrada como un argumento de línea de comando y las salidas a STDOUT. Esto solo funciona en commit 86494f6 y posteriores debido a una corrección de errores en ese commit.

Envuelto para la 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*>

Y sin golf / comentado:

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

Aquí hay algunos trucos sutiles que reducen algunos bytes adicionales, como

  • el nombramiento de las variables | y /, a cuyos valores ASCII se accede mediante introspección más adelante en el código

  • la '|en la primera línea del bucle principal, que se llama allí en vez de en la segunda línea con el fin de establecer el | puntero para usar en la segunda sección del bucle principal

Pomo de la puerta
fuente
1

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

-6 bytes gracias a mik

Probablemente no sea lo mejor para Perl, pero es lo que se me ocurrió.

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

Explicación

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
)

Pruébalo en línea!

Geoffrey H.
fuente
-pen lugar de -aelimina la necesidad de print;; usar whilecomo sufijo a una expresión ficticia (por ejemplo 0) ahorrará otros 2 bytes
mik
Gracias @mik, no conocía esos trucos. También me doy cuenta de que podría delimitar la expresión regular con algo más para guardar algunos bytes. Podría llegar a eso más tarde.
Geoffrey H.
1

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

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

Pruébalo en línea!

Explicación

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
fuente
0

Ruby , 83 bytes

Técnicamente barato con 9.times, o incluso solo 999.timespero no tengo ganas de ser barato :)

Todavía tiene un gran potencial de golf. (Nota: y while undonees mucho más largo que x.size.times)

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

Pruébalo en línea!

Unihedron
fuente
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)}

Pruébalo en línea!

Devuelve una cadena escapada.

Giuseppe
fuente
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));}

Pruébalo en línea!

Jonathan Frech
fuente