Paréntesis telescópicos

79

Considere una cadena no vacía de paréntesis correctamente equilibrados:

(()(()())()((())))(())

Podemos imaginar que cada par de paréntesis representa un anillo en una construcción telescópica colapsada . Entonces extendamos el telescopio:

(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()

Otra forma de verlo es que los paréntesis en la profundidad n se mueven a la línea n , manteniendo su posición horizontal.

Su tarea es tomar una cadena de paréntesis equilibrados y producir la versión extendida.

Puede escribir un programa o función, tomando la entrada a través de STDIN (o equivalente más cercano), argumento de línea de comando o parámetro de función, y produciendo salida a través de STDOUT (o equivalente más cercano), valor de retorno o parámetro de función (out).

Puede suponer que la cadena de entrada es válida, es decir, consta solo de paréntesis, que están correctamente equilibrados.

Puede imprimir espacios finales en cada línea, pero no más espacios iniciales de los necesarios. En total, las líneas no deben ser más largas que el doble de la longitud de la cadena de entrada. Opcionalmente, puede imprimir una nueva línea final.

Ejemplos

Además del ejemplo anterior, aquí hay algunos casos de prueba más (la entrada y la salida están separadas por una línea vacía).

()

()
(((())))

(      )
 (    )
  (  )
   ()
()(())((()))(())()

()(  )(    )(  )()
   ()  (  )  ()
        ()
((()())()(()(())()))

(                  )
 (    )()(        )
  ()()    ()(  )()
             ()

Desafíos relacionados:

  • Cadenas topográficas , que le pide que produzca lo que es esencialmente el complemento de la salida en este desafío.
  • Code Explanation Formatter , una amplia generalización de las ideas en este desafío, publicado recientemente por PhiNotPi. (De hecho, la descripción original de PhiNotPi de su idea fue lo que inspiró este desafío).

Tablas de clasificación

Huh, esto tuvo mucha participación, así que aquí hay un Fragmento de pila para generar una tabla de clasificación regular y una descripción general de los ganadores por idioma.

Para asegurarse de que su respuesta se muestre, comience con un título, utilizando la siguiente plantilla de Markdown:

# Language Name, N bytes

¿Dónde Nestá el tamaño de su envío? Si mejora su puntaje, puede mantener los puntajes antiguos en el título, tachándolos. Por ejemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Martin Ender
fuente
17
Título alternativo: De-Lisp-ify una cadena. : P
Alex A.
1
¿Hay alguna restricción en el color de la salida?
Matteo Italia
1
@ MartinBüttner: no importa, encontré una forma más limpia; digamos que mi idea anterior habría afeitado un byte dejando todos los paréntesis cerrados parpadeando en azul sobre cian ... :-)
Matteo Italia
8
@MatteoItalia oh dios, me alegro de que no haya sucedido. ;)
Martin Ender
12
@MatteoItalia: ¡Publica esa versión! Vale la pena verlo.
user2357112

Respuestas:

8

CJam, 17 16 15 bytes

0000000: 72 3a 69 22 28 0b 20 9b 41 29 22 53 2f 66 3d     r:i"(. .A)"S/f=

Lo anterior es un volcado xxd reversible, ya que el código fuente contiene los caracteres no imprimibles VT (0x0b) y CSI (0x9b).

Al igual que esta respuesta , usa secuencias de escape ANSI , pero también usa pestañas verticales e imprime los caracteres de control directamente para evitar usar printf .

Esto requiere un terminal de texto de video compatible, que incluye la mayoría de los emuladores de terminales que no son de Windows.

Prueba de funcionamiento

Tenemos que configurar la variable de shell LANG y la codificación del emulador de terminal en ISO 8859-1. Lo primero se logra ejecutando

$ LANGsave="$LANG"
$ LANG=en_US

Además, antes de ejecutar el código real, deshabilitaremos el mensaje y borraremos la pantalla.

$ PS1save="$PS1"
$ unset PS1
$ clear

Esto asegura que la salida se muestre correctamente.

echo -n '()(())((()))(())()' | cjam <(base64 -d <<< cjppIigLIJtBKSJTL2Y9)
()(  )(    )(  )()
   ()  (  )  ()
        ()

Para restaurar LANG y la solicitud, ejecute esto:

$ LANG="$LANGsave"
$ PS1="$PS1save"

Cómo funciona

Insertamos una pestaña vertical después de cada uno ( para mover el cursor hacia abajo y la secuencia de bytes 9b 41 ( "\x9bA") antes de cada uno ) para mover el cursor hacia arriba.

r         e# Read a whitespace-separated token from STDIN.
:i        e# Replace each character by its code point.
          e#   '(' -> 40, ')' -> 41
"(. .A)"  e# Push the string "(\v \x9bA)".
S/        e# Split at spaces into ["(\v" "\x9bA)"].
f=        e# Select the corresponding chunks.
          e# Since arrays wrap around in CJam, ["(\v" "\x9bA)"]40= and 
          e# ["(\v" "\x9bA)"]41= select the first and second chunk, respectively.
Dennis
fuente
49

código de máquina x86, 39 34 33 30 29 bytes

00000000  68 c3 b8 07 31 ff be 82  00 b3 a0 ad 4e 3c 28 7c  |h...1.......N<(||
00000010  f0 77 05 ab 01 df eb f3  29 df ab eb ee           |.w......)....|
0000001d

Ensamblaje x86 para DOS, con algunos trucos:

    org 100h

section .text

start:
    ; point the segment ES to video memory
    ; (c3 is chosen so that it doubles as a "ret")
    push 0b8c3h
    pop es
    ; di: output pointer to video memory
    xor di,di
    ; si: input pointer from the command line
    mov si,82h
    ; one row=160 bytes (assume bh=0, as should be)
    mov bl,160
lop:
    ; read & increment si (assume direction flag clean)
    ; we read a whole word, so that later we have something nonzero to
    ; put into character attributes
    lodsw
    ; we read 2 bytes, go back 1
    dec si
    ; check what we read
    cmp al,'('
    ; less than `(`: we got the final `\n` - quit
    ; (we jump mid-instruction to get a c3 i.e. a ret)
    jl start+1
    ; more than `(`: assume we got a `)`
    ja closed
    ; write a whole word (char+attrs), so we end
    ; one position on the right
    stosw
    ; move down
    add di,bx
    ; rinse & repeat
    jmp lop
closed:
    ; move up
    sub di,bx
    ; as above
    stosw
    jmp lop

Limitaciones :

  • siempre imprime comenzando en la parte inferior de la pantalla, sin borrar primero; a clsantes de correr es casi obligatorio;
  • los colores son feos; esa es la consecuencia de reciclar el siguiente carácter como atributos de color para guardar dos bytes aquí y allá;
  • el código asume bh=0y el indicador de dirección se borra al inicio, ambos indocumentados; OTOH, bxse establece explícitamente en cero en todas las variantes de DOS que vi (DosBox, MS-DOS 2, FreeDOS), y en todos los lugares donde probé los indicadores ya estaban bien.

ingrese la descripción de la imagen aquí

Matteo Italia
fuente
Acabo de verificar esto. Si, funciona. ¿Estás seguro de que necesitas hacer cld?
FUZxxl
@FUZxxl: en DosBox funciona bien incluso sin él, pero mirando sus fuentes dice que las banderas se conservan de lo que sucedió en DOS y en TRSs antes, por lo que probablemente sea necesario jugarlo de forma segura. De todos modos, eso sería solo un byte, la verdadera recompensa sería matar al menos uno de esos grandes (= 4 bytes cada uno) add/ sub.
Matteo Italia
Hm ... no tengo idea, de verdad.
FUZxxl
¿Se puede cambiar lopa loop?
mbomb007
@ mbomb007: ¿tal vez? No estoy seguro si nasmdesambigua entre loopuna etiqueta y loopla instrucción de ensamblaje, así que escribo lopcomo todos los demás.
Matteo Italia
28

J, 32 28 bytes

Esto fue divertido.

0|:')(('&(i.-<:@+/\@i:){."0]

Explicación

Así es como funciona esta solución, incluida una explicación de cómo se ha jugado al golf.

   NB. Let a be a test case
   a =. '((()())()(()(())()))'

   NB. level alterations
   _1 + ').(' i. a
1 1 1 _1 1 _1 _1 1 _1 1 1 _1 1 1 _1 _1 1 _1 _1 _1

   NB. absolute levels
   +/\ _1 + ').(' i. a
1 2 3 2 3 2 1 2 1 2 3 2 3 4 3 2 3 2 1 0

   NB. adjusted levels
   (+/\ _1 + ').(' i. a) - ')(' i. a
0 1 2 2 2 2 1 1 1 1 2 2 2 3 3 2 2 2 1 0

   NB. take level from end of each item of a and transpose
   |: a {."0~ _1 - (+/\ _1 + ').(' i. a) - ')(' i. a
(                  )
 (    )()(        ) 
  ()()    ()(  )()  
             ()     

   NB. code as a tacit verb
   [: |: ] {."0~ _1 - ([: +/\ _1 + ').(' i. ]) - ')(' i. ]

   NB. subtractions pulled into the prefix insert
   [: |: ] {."0~ (')(' i. ]) - [: <:@+/\ ').(' i. ]

   NB. i: instead of i. so we can use the same string constant
   [: |: ] {."0~ (')((' i. ]) - [: <:@+/\ ')((' i: ]

   NB. get rid of the caps
   0 |: ] {."0~ (')((' i. ]) - ')((' <:@+/\@i: ]

   NB. join the two usages of ')((' into a single dyadic phrase
   0 |: ] {."0~ ')((' (i. - <:@+/\@i:) ]

   NB. bond ')((' and flip arguments to {."0
   0 |: ')(('&(i. - <:@+/\@i:) {."0 ]
FUZxxl
fuente
1
¡Muy agradable! ¡La solución está llena de grandes partes!
randomra
1
(Yo suelo añadir un ejemplo de invocación de la función de los usuarios por lo que no experimentados podrían probarlo también.)
randomra
Esta solución me duele la cabeza:')
Nic Hartley
@QPaysTaxes Tomo esto como un cumplido.
FUZxxl
@FUZxxl lo es. También es un juego de palabras basado en una secuencia de caracteres que aparece en tu respuesta.
Nic Hartley
15

C, 150 bytes

t;f(char*c){char l=strlen(c)+1,o[l*l],*A=o,m=0;for(t=1;t<l*l;t++)o[t-1]=t%l?32:10;for(t=-1;*c;c++)A++[l*(*c-41?++t>m?m=t:t:t--)]=*c;A[m*l]=0;puts(o);}

Esta era una locura divertida de golf. Todavía no estoy convencido de que haya terminado con eso.

Definimos una sola función, fque toma la cadena como entrada y salida a stdout.

Veamos el código, línea por línea:

/* t will represent the current depth of a parentheses. It must be an int. */
t;
f(char*c){
    //Our variables:
    char l=strlen(c)+1,    //The length of each row of output, including newlines
         o[l*l],           //The output string. It's way larger than it needs to be.
         *A=o,             //We need another pointer to keep track of things.
         m=0;              //The maximum depth recorded thus far.

    for(t=1;t<l*l;t++)     //For each character in our output...
        o[t-1]=t%l?32:10;  //If it's at the end of a line, make it '\n'. Else, ' '.
    for(t=-1;*c;c++)       //While we have an input string...
        //Perhaps a personal record for ugliest warning-less line...
        A++[l*(*c-41?++t>m?m=t:t:t--)]=*c;
    /* 
        A breakdown:
        A++        --> Go to the next *column* of output, after writing. 
                   --> There will only ever be one parentheses per output column.
        [l*(...)]  --> A[l*X] is the character in the current column at depth X.
        (*c-41?    --> If the character is a '('...    
        ++t>m?     --> Increment t *before* we write it. If this is a new highest depth
        m=t:       --> Set m to t, and set the whole expression to t.
        t:         --> If it's not a new highest depth, don't set m.
        t--)       --> If the character was a ')', decrement t *after* we write it.
        =*c        --> Write our output character to whatever the input read.
    */    

    A[m*l]=0; //The last character of the maximum-depth line should be null terminated.
    puts(o);  //Output!
}

¡Contestaré cualquier pregunta que pueda tener!

¡Pruebe un programa de prueba en línea !

BrainSteel
fuente
Quiero recordar que "char l = strlen (c) +1, o [l * l]" no es válido porque no puedes definir una matriz de tamaño variable como esa, pero han pasado 15 años desde que probé algo de ese tipo en C.
Sparr
@Sparr Mi compilador ni siquiera lanza una advertencia. Creo que esto era "oficialmente" estándar en C99. Trataré de encontrar una referencia para esto.
BrainSteel
1
@Sparr Aquí hay una referencia.
BrainSteel
Gracias. Parece que las cosas cambiaron alrededor de 15 (más o menos un par) hace años a este respecto :)
Sparr
1
@CoolGuy Lo haría, pero en llamadas posteriores de f, mno se restablecería a 0. Esto cuenta como "romper su entorno", prohibido aquí .
BrainSteel
15

Retina + Bash, 27 bytes (14 + 10 + 3 = 27)

Esto hace uso de ANSI Escapes:

\(
(\e[B
\)
\e[A)

Equivalente a sed -e "s/(/(\\\e[B/g;s/)/\\\e[A)/g". El \e[Bcódigo de escape significa mover el cursor hacia abajo una fila, y los \e[Amedios mover el cursor hacia arriba una fila, por lo que esta solución simplemente inserta esos códigos después y antes del inicio y el final de cada par de paréntesis anidados. La entrada se pasa a través de STDIN.

Tendrá que llamarlo printf $(Retina ...)para ver la salida correctamente.

Salida

(((())))
(\e[B(\e[B(\e[B(\e[B\e[A)\e[A)\e[A)\e[A)
^C
amans:~ a$ printf "(\e[B(\e[B(\e[B(\e[B\e[A)\e[A)\e[A)\e[A)"
(      )amans:~ a$ 
 (    )
  (  )
   ()

((()())()(()(())()))
(\e[B(\e[B(\e[B\e[A)(\e[B\e[A)\e[A)(\e[B\e[A)(\e[B(\e[B\e[A)(\e[B(\e[B\e[A)\e[A)(\e[B\e[A)\e[A)\e[A)
^C
amans:~ a$ printf "(\e[B(\e[B(\e[B\e[A)(\e[B\e[A)\e[A)(\e[B\e[A)(\e[B(\e[B\e[A)(\e[B(\e[B\e[A)\e[A)(\e[B\e[A)\e[A)\e[A)"
(                  )amans:~ a$ 
 (    )()(        )
  ()()    ()(  )()
             ()
usuario22723
fuente
1
¡Bien no está mal! Si pudieras apuntar a un terminal específico que no necesita printf, sería genial. De lo contrario, creo que sería justo agregar | printfal conteo de bytes.
Martin Ender
@ MartinBüttner Debería ser printf $()o printf $(Retina ).
jimmy23013
1
¿Qué es esa cosita Retina?
FUZxxl
2
@FUZxxl Es mi propio lenguaje de programación basado en expresiones regulares. Ver GitHub .
Martin Ender
2
¿Por qué \emás printf? Simplemente puede poner los caracteres de control en el patrón de reemplazo.
Dennis
15

TI-BASIC, 69 60 56 55 bytes

Esto es para la familia de calculadoras TI-83 + / 84 +, aunque fue escrito en una edición 84+ C Silver.

El programa aparece como mayor en calc debido a que se incluye información de IVA + tamaño. Además, hay más de 56 caracteres aquí; la razón por la que son 56 bytes es porque todos los comandos que tienen más de un carácter se comprimen en tokens que tienen uno o dos bytes de tamaño.

Input Str1
1→B
For(A,1,length(Str1
sub(Str1,A,1→Str2
Ans="(
Output(B+Ans,A,Str2
B-1+2Ans→B
End

¡Afeitado otro byte gracias a thomas-kwa ! (también de él fue el salto de 60 a 56.)

MI Wright
fuente
44
Ahhh, mi primer lenguaje de programación. Gracias por la nostalgia, jaja.
Alex Pritchard
1
Todavía estoy programando TI para la clase de matemáticas de la escuela secundaria, muy útil para tener fórmulas integradas que se calcularán por ti en las pruebas y tareas.
Elias Benevedes
1
Si cambia las cosas, puede usar el cos(piAnstruco para guardar otro byte.
lirtosiast
9

Python 2, 115 bytes

def f(L,n=0,O=()):
 for c in L:n-=c>"(";O+=" "*n+c,;n+=c<")"
 for r in map(None,*O):print"".join(c or" "for c in r)

Llama como f("((()())()(()(())()))"), y la salida es STDOUT.

Explicación

Comenzamos con n = 0. Para cada carácter en la línea de entrada:

  • Si el carácter es (, anteponemos nespacios y luego incrementamosn
  • Si el carácter es ), decrementamos ny anteponemos nespacios

El resultado se comprime e imprime. Tenga en cuenta que las zipcremalleras de Python coinciden con la longitud del elemento más corto , p. Ej.

>>> zip([1, 2], [3, 4], [5, 6, 7])
[(1, 3, 5), (2, 4, 6)]

Por lo general, uno usaría itertools.zip_longest( izip_longest) si quisieran ziprellenar a la longitud del elemento más largo .

>>> import itertools
>>> list(itertools.izip_longest([1, 2], [3, 4], [5, 6, 7]))
[(1, 3, 5), (2, 4, 6), (None, None, 7)]

Pero en Python 2, este comportamiento se puede simular mediante la asignación None:

>>> map(None, [1, 2], [3, 4], [5, 6, 7])
[(1, 3, 5), (2, 4, 6), (None, None, 7)]

Python 3, 115 bytes

L,d,*O=input(),0
for i,c in enumerate(L):b=c>"(";O+="",;O[d-b]=O[d-b].ljust(i)+c;d-=b*2-1
for l in O:l and print(l)

Sin cremallera, solo rellenando adecuadamente con ljust. Este parece tener cierto potencial de golf.

Sp3000
fuente
8

R, 151127 caracteres

S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}

Con sangrías y nuevas líneas:

S=strsplit(scan(,""),"")[[1]]
C=cumsum
D=c(C(S=="("),0)-c(0,C(S==")"))
for(j in 1:max(D)){
    X=S
    X[D!=j]=' '
    cat(X,sep='',fill=T)
    }

Uso:

> S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}
1: ()(())((()))(())()
2: 
Read 1 item
()(  )(    )(  )()
   ()  (  )  ()   
        ()        
> S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}
1: ((()())()(()(())()))
2: 
Read 1 item
(                  )
 (    )()(        ) 
  ()()    ()(  )()  
             ()     

Lee la cadena como stdin, la divide como un vector de caracteres individuales, calcula la suma acumulativa de (y ), resta la primera con la segunda (con un retraso) calculando así el "nivel" de cada paréntesis. Luego imprime en stdout, para cada nivel, los paréntesis correspondientes o un espacio.

¡Gracias a @MickyT por ayudarme a acortarlo considerablemente!

plannapus
fuente
2
+1 Solución agradable y elegante. Puede guardar 6 reemplazando for(i in n)cat(ifelse(D[i]-j," ",S[i]));cat("\n")con X=S;X[which(D!=j)]=' ';cat(X,sep='',fill=T). Entonces nno es realmente necesario, pero necesitaría cambiar un poco la parte de cumsum. D=c(C(S=="("),0)-c(0,C(S==")"));reduciéndolo a 135.
MickyT
@MickyT wow gracias! No pensé en eso. whichSin embargo, no es realmente necesario aquí ( D!=jya que es un vector de booleanos que permite la indexación). No sabía argumento fillpara cat, eso es un truco ingenioso! ¡Gracias por hacerme acortarlo por la asombrosa cantidad de 24 caracteres!
plannapus
8

C, 58 53 52 51 49 bytes

Utiliza secuencias de escape ANSI para mover la posición del cursor.

f(char*s){while(*s)printf(*s++&1?"\e[A)":"(\v");}

Si no usa gcc u otro compilador que lo admita \e, puede reemplazarlo \x1Bpor un total de 2 bytes adicionales. \e[Amueve el cursor hacia arriba una fila y \e[Bmueve el cursor hacia abajo una fila. No es necesario usar\e[B para moverse hacia abajo una fila, ya que son dos bytes más cortos para usar el carácter de tabulación vertical ASCII 0xBo \v.

Se supone que la cadena de entrada, a partir de la pregunta, consiste solo en paréntesis (equilibrados), por lo que verificar la paridad del carácter, con &1, es suficiente para distinguir entre (y ).

CL-
fuente
7

Pip, 53 bytes

Pip es un lenguaje de código de golf de mi invención. La primera versión se publicó el sábado, ¡así que puedo probarla oficialmente! La solución a continuación no es tan competitiva como los idiomas de golf, pero eso se debe en parte a que todavía no he implementado cosas como zip y max.

z:{aEQ'(?++v--v+1}MaW(o:{z@++v=i?as}Ma)RMs{Pov:-1++i}

Espera la cadena de paréntesis como argumento de línea de comando.

Versión "sin golf":

z:{
   a EQ '( ?
    ++v
    --v+1
  } M a
W (o:{
      z @ ++v = i ?
       a
       s
     } M a
  ) RM s
{
 P o
 v:-1
 ++i
}

Explicación:

A diferencia de la mayoría de los lenguajes de golf, Pip es imprescindible con los operadores de infijo, por lo que la sintaxis está algo más cerca de C y sus derivados. También toma prestadas ideas de la programación funcional y basada en arreglos. Consulte el repositorio para obtener más documentación.

El programa primero genera una lista de profundidades (almacenándola z) al asignar una función a la cadena de entrada a. La variable global vrastrea el nivel actual. (Las variables a-gen Pip son variables locales de función, pero h-zson globales. vEs útil porque está preinicializado a -1).

Luego, usamos un Wbucle hile para generar e imprimir cada línea, hasta que la línea generada consista en todos los espacios. vahora se usa para columnas y ipara filas. La {z@++v=i?as}función, asignada repetidamente a la cadena de entrada original, prueba si la línea actual icoincide con la línea en la que se supone que está el paréntesis actual (como se almacena en la zlista). Si es así, use el paréntesis ( a); si no, use s(preinicializado al espacio). El resultado final es que en cada iteración,o se le asigna una lista de caracteres equivalente a la siguiente línea de la salida.

Para probar si debemos continuar haciendo un bucle, verificamos si ocon todos los espacios RM'd está vacío. De lo contrario, imprímalo (que de forma predeterminada concatena todo junto como en CJam), restablezca el número de columna a -1 e incremente el número de fila.

(Dato curioso: al principio tenía una solución de 51 bytes ... que no funcionó porque apareció un error en el intérprete).

DLosc
fuente
7

Pyth, 31 bytes

VzJs.e?YqN-/<zk\(/<zhk\)dzI-JdJ

Pruébalo en línea.

-/<zk\(/<zhk\): Encuentra el nivel apropiado para la posición actual del personaje.

?YqN-/<zk\(/<zhk\)d: Un espacio si el nivel apropiado no es el nivel actual, de lo contrario, el personaje actual.

Js.e?YqN-/<zk\(/<zhk\)dz: Genere la cadena, guárdela J.

I-JdJ: Si Jno hay todos los espacios, imprímalo.

Vz: zTiempos de bucle .

isaacg
fuente
6

GNU Bash + coreutils + sangría, 135

eval paste "`tr '()' {}|indent -nut -i1 -nbap|sed 's/.*/<(fold -1<<<"&")/'|tr '
' \ `"|expand -t2|sed 'y/{}/()/;s/\(.\) /\1/g;s/ \+$//'

Entrada / salida a través de STDIN / STDOUT:

$ ./telescopic.sh <<< "(()(()())()((())))(())"
(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()
$ 

indentrealiza la mayor parte del trabajo pesado, pero necesita trabajar con aparatos ortopédicos en lugar de parens. El resto es modificación de esta respuesta para transponer la salida de indent.

Trauma digital
fuente
5

Pitón 2, 92

def f(s,i=0,z=''):
 for x in s:b=x>'(';z+=[' ',x][i==b];i-=2*b-1
 if'('in z:print z;f(s,i-1)

Imprime línea por línea. Para un número de línea dado i(en realidad, su negación), pasa por la cadena de entrada sy crea una nueva cadena zque solo contiene los caracteres de sprofundidad i. Esto se hace incrementando o decrementando ipara rastrear la profundidad actual, y agregando los caracteres actuales cuando ise 0ajusta para el tipo de par, y de lo contrario agregando un espacio.

Luego, imprime y vuelve a la siguiente, a imenos que la línea actual fuera todos los espacios. Tenga en cuenta que, dado que los parens están equilibrados, el iciclo posterior es el mismo que al principio.

Python 3 sería el mismo excepto por un personaje para print(z).

xnor
fuente
5

trampa :( Retina + TeX, N bytes trampa :(

Esto solo funciona si representa (?) La salida usando MathJax o algún otro TeX, que actualmente está deshabilitado para este SE :(

\(
({
\)
})
\{\(
_{(

Cada línea debe estar en un archivo diferente, pero puede probarla usando Retina -e "\(" -e "({" -e "\)" -e "})" -e "\{\(" -e "_{("(o el comando sed equivalente sed -e "s/(/({/g;s/)/})/g;s/{(/_{(/g"). La entrada se pasa a través de STDIN.

Esto funciona al encerrar entre paréntesis el contenido de cada par de paréntesis y luego suscribir todos los elementos dentro de ellos.

Salida

(((())))
(_{(_{(_{({})})})})

()(())((()))(())()
({})(_{({})})(_{(_{({})})})(_{({})})({})

((()())()(()(())()))
(_{(_{({})({})})({})(_{({})(_{({})})({})})})

Salida TeX

usuario22723
fuente
1
Me siento halagado de que hayas usado Retina, y este es un buen pensamiento fuera de la caja, pero eso no es exactamente lo que se supone que debería ser la salida. ;) En particular, esto viola la formulación alternativa "Otra forma de verlo es que los paréntesis en profundidad n se mueven a la línea n, manteniendo su posición horizontal". Sin embargo, estaría muy impresionado con una solución Retina pura y que cumpla con las reglas, y podría entregar una recompensa por ello. ;)
Martin Ender
In total the lines must not be longer than twice the length of the input string. Cambiar la línea 2 (\,{y la línea 4 }\,)significa que la salida se ajusta a esto (aunque la profundidad vertical sigue siendo incorrecta: ()
user22723
Bueno, logré hacer una solución que cumpla con las reglas
:)
1
Buen trabajo. Supongo que eso significa que puede eliminar la respuesta engañosa ahora. ;)
Martin Ender
5

Java, 232 226 224 222 bytes

Versión de golf:

int i,j,k,l,m,a[];void f(String s){a=new int[s.length()];j=a.length;for(k=0;k<j;){a[k]=s.charAt(k++)<41?i++:--i;m=m<i?i:m;}for(k=0;k<m;k++)for(l=0;l<j;)System.out.print(k==a[l++]?i++%2<1?'(':l==j?")\n":')':l==j?'\n':' ');}

Versión larga:

int i, j, k, l, m, a[];
void f(String s) {
    a = new int[s.length()];
    j = a.length;
    for (k = 0; k < j;) {
        a[k] = s.charAt(k++) < 41 ? i++ : --i;
        m = m < i ? i : m;
    }
    for (k = 0; k < m; k++)
        for (l = 0; l < j;)
            System.out.print(k == a[l++] ? (i++ % 2 < 1 ? '(' : (l == j ? ")\n" : ')')) : (l == j ? '\n':' '));
}

La cadena de entrada se analiza primero, buscando "(" y ")" para sumar / restar un contador y almacenar su valor determinando qué tan abajo deben ir los paréntesis en una matriz y al mismo tiempo realizar un seguimiento de cuán profundo es el más profundo. Luego se analiza la matriz; los paréntesis con valores menores se imprimen primero y continuarán imprimiendo línea por línea hasta alcanzar el máximo.

Probablemente encontraré formas de jugar al golf más adelante.

TNT
fuente
5

Javascript / ES6, 97 caracteres

f=s=>{for(n in s){m=o=d='';for(c of s)o+=n==(c<')'?d++:--d)?c:' ',m=m<d?d:m;n<m&&console.log(o)}}

Uso

f("(()(()())()((())))(())")

Explicación

fn=str=>{                          // accepts string of parenthesis
  for(line in str){                // repeat process n times where n = str.length
    max=output=depth='';           // max: max depth, output: what to print, depth: current depth
    for(char of str)               // iterate over chars of str
      output+=
        line==(char<')'?depth++:--depth)? // update depth, if line is equal to current depth
        char:' ',                  // append either '(', ')', or ' '
        max=max<depth?depth:max;   // update max depth
    line<max&&console.log(output)  // print if current line is less than max depth
  }
}
Dendrobium
fuente
En lugar de n<m?console.log(o):0, puede usar n<m&&console.log(o)que ahorra 1 byte.
Ismael Miguel
4

CJam, 43 41 36 bytes

No demasiado golf (creo), pero aquí va mi primer intento:

l:L,{)L<)_')=@~zS*\+}%_$0=,f{Se]}zN*

Cómo funciona

Estoy usando el hecho muy útil de que )y (en CJam significan incremento y decremento respectivamente. Por lo tanto, simplemente evalúo los corchetes para obtener la profundidad.

l:L,{)L<)_')=@~zS*\+}%_$0=,f{Se]}zN*
l:L,{                    }%                "Store input line in L and iterate over [0,L)";
     )L<                                   "substr(L, 0, iterator + 1)";
        )                                  "Slice off the last character to stack";
         _')=                              "Put 0 on stack if the sliced character is (,
                                            else 1 if sliced character is )";
             @~                            "bring forth the remaining
                                            brackets after slicing and evaluate them";
               zS*                         "Stack has negative depth number, take absolute
                                            value and get that many spaces";
                  \+                       "Prepend to the sliced character";
                      _$0=,                "Get the maximum depth of brackets";
                           f{Se]}          "Pad enough spaces after each string to match
                                            the length of each part";
                                 zN*       "Transpose and join with new lines";

Pruébalo en línea aquí

Optimizador
fuente
4

Octava, 85 caracteres

function r=p(s)i=j=0;for b=s k=b==40;k&&++j;t(j,++i)=9-k;k||--j;r=char(t+32);end;end

Es una optimización del enfoque ingenuo, que en realidad es bastante natural para Matlab y Octave:

function r=p(s)
i=j=1;
for b=s
 if b=='(' t(++j,i++)='(' else t(j--,i++)=')' end; end; t(~t)=' '; r=char(t);
end;

Es t posible que la tabla aún no exista, y podemos asignar a cualquier elemento de inmediato, y da nueva forma a la dimensión más pequeña que se requiere para que exista este elemento, lo cual es bastante conveniente.

pawel.boczarski
fuente
4

Perl, 91 89 88 84 80 79 bytes

$t=<>;{$_=$t;s/\((?{$l++})|.(?{--$l})/$^R==$c?$&:$"/ge;print,++$c,redo if/\S/}
  • $ t es la cadena de entrada.
  • $ c es la profundidad que queremos imprimir en la línea actual.
  • $ l es la profundidad a la que nos encontramos después de encontrarnos con un par.
  • $ l se actualiza en bloques de código incrustados regex .
  • $ ^ R es el resultado del bloque de código más reciente.
Helios
fuente
4

Haskell, 154 bytes

f h('(':s)=h:f(h+1)s;f h(')':s)=(h-1):f(h-1)s;f _ _=[]
main=interact$ \s->unlines[[if i==h then c else ' '|(c,i)<-zip s l]|let l=f 0 s,h<-[0..maximum l]]

misma idea que la otra solución de Haskell, pero algo más corta. - Uso:

echo  '(((())())(()))' | runghc Golf.hs
d8d0d65b3f7cf42
fuente
3

J, 46

No es tan bueno como los otros 'idiomas de golf', pero en mi defensa: J es terrible con las cuerdas.

[:|:(((,~(' '#~]))"0)(0,2%~[:+/\2+/\1-'(('i.]))~

Toma la cadena como entrada para una función. Probablemente también haya una mejor manera de hacerlo en J.

Uso:

   f=:[:|:(((,~(' '#~]))"0)(0,2%~[:+/\2+/\1-'(('i.]))~
   f '(()(()())()((())))(())'
(                )(  )
 ()(    )()(    )  () 
    ()()    (  )      
             ()       
ɐɔıʇǝɥʇuʎs
fuente
Vea mi respuesta para otra forma de hacerlo en J.
FUZxxl
3
Personalmente, creo que J es perfectamente adecuado para cuerdas. Solo necesitas pensar con matrices.
FUZxxl
3

Ruby, 119 115 114

->s{r=[""]*s.size
d=0
s.chars.map{|l|r.map!{|s|s+" "}
b=l>"("?1:0
d-=b
r[d][-1]=l
d+=1-b}.max.times{|i|puts r[i]}}

Explicación:

->s{r=[""]*s.size  # Take an array of strings big enough
d=0                # This will contain the current depth
s.chars.map{|l|r.map!{|s|s+" "}  # Add a new space to every array
b=l>"("?1:0       # Inc/Dec value of the depth
d-=b               # Decrement depth if we are at a closing paren
r[d][-1]=l         # Set the corresponding space to the actual open/close paren
d+=1-b             # Increment the depth if we are at a opening paren
}.max.times{|i|puts r[i]}}  # Print only the lines up to the max depth
rorlork
fuente
3

Java, 233 214 bytes

void f(String s){int p,x,d,l=s.length();char c,m[]=new char[l*l];java.util.Arrays.fill(m,' ');p=x=0;while(x<l){d=(c=s.charAt(x))==40?p++:--p;m[d*l+x++]=c;}for(x=0;x<l*l;x++)System.out.print((x%l==0?"\n":"")+m[x]);}

Sangrado:

void f(String s){
    int p, x, d, l = s.length();
    char c, m[] = new char[l * l];
    java.util.Arrays.fill(m, ' ');
    p = x = 0;
    while (x < l){
        d = (c = s.charAt(x)) == 40
                ? p++
                : --p;
        m[d * l + x++] = c;
    }
    for (x = 0; x < l * l; x++)
        System.out.print((x % l == 0 ? "\n" : "") + m[x]);
}

Supongo que el ciclo final podría acortarse, pero lo dejaré como un ejercicio para el lector. ;-)


Antigua respuesta de 233 bytes:

void f(String s){int y=s.length(),x=0;char[][]m=new char[y][y];for(char[]q:m)java.util.Arrays.fill(q,' ');y=0;for(char c:s.toCharArray())if(c=='(')m[y++][x++]=c;else m[--y][x++]=c;for(char[]q:m)System.out.println(String.valueOf(q));}

Sangrado:

static void f(String s) {
    int y = s.length(), x = 0;
    char[][] m = new char[y][y];
    for(char[] q : m)
        java.util.Arrays.fill(q, ' ');
    y = 0;
    for(char c : s.toCharArray())
        if(c == '(')
            m[y++][x++] = c;
        else
            m[--y][x++] = c;
    for(char[] q : m)
        System.out.println(String.valueOf(q));
}
ArturoTena
fuente
Sé que ha pasado más de un año, pero "Creo que el ciclo final podría acortarse, pero lo dejaré como un ejercicio para el lector. ;-)"; De hecho tienes razón. Se puede cambiar de for(x=0;x<l*l;x++)System.out.print((x%l==0?"\n":"")+m[x]);a for(x=0;x<l*l;)System.out.print((x%l==0?"\n":"")+m[x++]);por -1 byte. Además, puede guardar 2 bytes más al eliminarlos p=x=0y simplemente utilizarlos int p=0,x=0,en la inicialización de los campos. En total se convierte en 211 bytes .
Kevin Cruijssen
3

C #, 195 bytes

Primero intente en el golf - grite si hice algo mal.

Versión alternativa de C # usando SetCursorPosition y trabajando de izquierda a derecha tomando la entrada como una línea de comando arg.

using System;class P{static void Main(string[] a){Action<int,int>p=Console.SetCursorPosition;int r=0,c=0;foreach(var x in a[0]){r+=x==')'?-1:0;p(c,r);Console.Write(x);r+=x=='('?1:0;p(c,r);c++;}}}

Pensé que sería divertido ajustar la posición de escritura en función del par abierto / cerrado y no de las líneas completas. Cerrar paren mueve la posición hacia arriba antes de escribir; abrir paren lo mueve hacia abajo después de escribir. La acción SetCursorPosition ahorra cinco bytes. Mover el cursor a la siguiente línea después de la salida tomaría bastante más.

using System;
class P
{
    static void Main(string[] a)
    {
        Action<int, int> p = Console.SetCursorPosition;
        int r = 0, c = 0;
        foreach (var x in a[0])
        {            
            r += x == ')' ? -1 : 0;
            p(c, r);
            Console.Write(x);
            r += x == '(' ? 1 : 0;
            p(c, r);
            c++;
        }
    }
}
Jeremy Murray
fuente
3

Lote, 356 335 bytes

Sé que ya existe una solución Batch para este desafío, pero esta se juega mucho más y parece tener un enfoque diferente. Lo más importante, la otra solución por lotes contiene al menos un comando de PowerShell; Esta solución no.

@echo off
setlocal enabledelayedexpansion
set p=%1
set p=%p:(="(",%
set p=%p:)=")",%
set c=0
for %%a in (%p%)do (if ")"==%%a set/ac-=1
set d=!d!,!c!%%~a
if "("==%%a set/ac+=1&if !c! GTR !m! set m=!c!)
set/am-=1
for /l %%a in (0,1,!m!)do (for %%b in (!d!)do (set t=%%b
if "%%a"=="!t:~0,-1!" (cd|set/p=!t:~-1!)else (cd|set/p=. ))
echo.)

Hay un carácter de retroceso ( U+0008) en la penúltima línea que sigue al punto (línea 12, columna 57). Esto no es visible en el código publicado aquí, pero está incluido en el recuento de bytes.

ankh-morpork
fuente
Alguien más está enviando una respuesta en Batch - Nice one +1.
unclemeat
3

Lote, 424 bytes.

@echo off
setLocal enableDelayedExpansion
set s=%1
set a=1
:c
if defined s (set/ac+=1
set "z="
if "%s:~0,1%"=="(" (set "1=(")else (set/aa-=1
set "1=)")
for %%a in (!a!)do for /f usebackq %%b in (`powershell "'!l%%a!'".Length`)do (set/ay=!c!-%%b
for /l %%a in (1,1,!y!)do set z= !z!
set "l%%a=!l%%a!!z!!1!")
if "%s:~0,1%"=="(" set/aa+=1
if !a! GTR !l! set/al=!a!-1
set "s=%s:~1%"
goto c)
for /l %%a in (1,1,!l!)do echo !l%%a!

Sin golf:

@echo off
setLocal enableDelayedExpansion

set s=%1
set a=1
set c=0
set l=0

:c
if defined s (
    set /a c+=1
    set "z="
    if "%s:~0,1%"=="(" (
        set "1=("
    ) else (
        set /a a-=1
        set "1=)"
    )
    for %%a in (!a!) do for /f usebackq %%b in (`powershell "'!l%%a!'".Length`) do (
        set /a y=!c!-%%b
        for /l %%a in (1,1,!y!) do set z= !z!
        set "l%%a=!l%%a!!z!!1!"
    )
    if "%s:~0,1%"=="(" set /a a+=1
    if !a! GTR !l! set /a l=!a!-1
    set "s=%s:~1%"
    goto c
)

for /l %%a in (1,1,!l!) do echo !l%%a!

Ejemplo:

h:\>par.bat (((())())(()))
 (            )
  (      )(  )
   (  )()  ()
    ()
carne sin carne
fuente
3

C, 118 bytes

Otra respuesta en C, pero la mía es más corta.

c;d;main(m,v)int**v;{while(d++<m){char*p=v[1];while(*p)c+=*p==40,putchar(c-d?*p:32),m=c>m?c:m,c-=*p++==41;puts("");}}

Versión sin golf:

c; /* current depth */
d; /* depth to print in current row */
main(m,v)int**v;{
    while(d++<m) {
        char*p=v[1];
        while(*p){
            c+=*p==40;           /* 40 = '(' */
            putchar(c-d?*p:32); /* 32 = ' ' (space) */
            m=c>m?c:m;           /* search maximum depth */
            c-=*p++==41;         /* 41 = ')' */
        }
        puts("");
    }
}

¡Y funciona!

% ./telescope '()(())((()))(())()'
()(  )(    )(  )()
   ()  (  )  ()
        ()
% ./telescope '((()())()(()(())()))'
(                  )
 (    )()(        )
  ()()    ()(  )()
             ()
MarcDefiant
fuente
1
Una solución bastante elegante, sin embargo, putchar(c-d?32:*p)es un personaje más corto que putchar(c==d?*p:32).
pawel.boczarski
2

Haskell, 227 bytes

n _ []=[]
n h ('(':r)=('(',h):n(h+1)r
n d (')':r)=let h=d-1 in(')',h):n h r
m n []=n
m n ((_,h):r)=m(max h n)r
p s=let v=n 0 s;h=m 0 v;in map(\d->map(\(b,l)->if l==d then b else ' ')v)[0..h]
main=fmap p getLine>>=mapM_ putStrLn
Jeremy List
fuente
1
Puede guardar algunos espacios con operadores: por ejemplo, en n#[]lugar de m n [].
Franky
2

Perl, 76 bytes

$a[/\(/?$l++:--$l][$i++]=$_ for split//,<>;print map{$_||' '}@$_,"\n"for@a

No use strictaquí :)

alexander-brett
fuente
2

Lex, 94 bytes

Depende de los códigos de la consola de Linux. Con gcc, puede cortar cuatro bytes reemplazando ambas instancias \33por un carácter de escape real.

%%
 int p[2]={0};
\( printf("(\33D");++p[!*p];
\) printf("\33M)");--*p;
\n while(p[1]--)ECHO;

Para compilar y ejecutar:

$ flex -o telescopic.c telescopic.l
$ gcc -o telecopic telescopic.c -lfl
$ ./telescopic
(()(()())()((())))(())
(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()
--- type ctrl-D ---
rici
fuente