Телескопические скобки

79

Рассмотрим непустую строку правильно сбалансированных скобок:

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

Мы можем представить, что каждая пара скобок представляет собой кольцо в свернутой телескопической конструкции . Итак, давайте расширим телескоп:

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

Другой способ взглянуть на это заключается в том, что скобки на глубине n перемещаются в строку n , сохраняя при этом их горизонтальное положение.

Ваша задача - взять такую ​​строку сбалансированных скобок и создать расширенную версию.

Вы можете написать программу или функцию, используя ввод через STDIN (или ближайший эквивалент), аргумент командной строки или параметр функции и производя вывод через STDOUT (или ближайший эквивалент), возвращаемое значение или параметр функции (out).

Вы можете предположить, что входная строка верна, то есть содержит только круглые скобки, которые правильно сбалансированы.

Вы можете печатать завершающие пробелы в каждой строке, но не больше начальных пробелов, чем необходимо. Всего строки не должны быть длиннее, чем удвоенная длина входной строки. При желании вы можете распечатать один завершающий символ новой строки.

Примеры

В дополнение к приведенному выше примеру, вот еще несколько тестовых случаев (вход и выход разделены пустой строкой).

()

()
(((())))

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

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

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

Связанные проблемы:

  • Топографические строки , которые просят вас произвести то, что по сути является дополнением к выходным данным в этой задаче.
  • Code Explanation Formatter , широкое обобщение идей этой задачи, недавно опубликованное PhiNotPi. (Фактически, оригинальное описание PhiNotPi его идеи было тем, что вдохновило этот вызов.)

Leaderboards

Да, в этом приняли участие довольно много, так что вот фрагмент стека, который генерирует как регулярную таблицу лидеров, так и обзор победителей по языкам.

Чтобы убедиться, что ваш ответ обнаружен, начните его с заголовка, используя следующий шаблон уценки:

# Language Name, N bytes

где Nразмер вашего представления. Если вы улучшите свой счет, вы можете сохранить старые результаты в заголовке, вычеркнув их. Например:

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

Мартин Эндер
источник
17
Альтернативное название: De-Lisp-ify строка. : P
Алекс А.
1
Есть ли какие-либо ограничения по цвету вывода?
Matteo Italia
1
@ MartinBüttner: неважно, я нашел более чистый путь; давайте просто скажем, что моя предыдущая идея побрила бы байт, оставив все закрытые скобки мигающими голубыми над голубым ... :-)
Matteo Italia
8
@ MatteoItalia о боже, я рад, что этого не произошло. ;)
Мартин Эндер
12
@MatteoItalia: опубликовать эту версию! Это стоит увидеть.
user2357112

Ответы:

8

CJam, 17 16 15 байтов

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

Выше приведен обратимый дамп xxd, поскольку исходный код содержит непечатаемые символы VT (0x0b) и CSI (0x9b).

Как и этот ответ , он использует escape-последовательности ANSI , но также использует вертикальные табуляции и печатает управляющие символы напрямую, чтобы избежать использования printf .

Для этого требуется поддерживающий видео текстовый терминал, который включает большинство эмуляторов терминала, отличных от Windows.

Тестовый забег

Мы должны установить переменную оболочки LANG и кодировку эмулятора терминала на ISO 8859-1. Первое достигается путем выполнения

$ LANGsave="$LANG"
$ LANG=en_US

Кроме того, перед выполнением действительного кода мы отключим запрос и очистим экран.

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

Это гарантирует, что вывод отображается правильно.

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

Чтобы восстановить LANG и подсказку, выполните это:

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

Как это устроено

Мы вставляем вертикальную вкладку после каждого ( чтобы переместить курсор вниз и последовательность байтов 9b 41 ( "\x9bA") перед каждым ), чтобы переместить курсор вверх.

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.
Деннис
источник
49

машинный код x86, 39 34 33 30 29 байт

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

Сборка x86 для DOS, с некоторыми хитростями:

    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

Ограничения :

  • он всегда печатается, начиная с нижней части экрана, без стирания первым; clsперед запуском является почти обязательным;
  • цвета уродливы; это является следствием повторного использования следующего символа в качестве цветовых атрибутов, чтобы сохранить два байта здесь и там;
  • код предполагает bh=0и флаг направления сбрасывается при запуске, оба недокументированы; OTOH, bxявно установлен на ноль во всех вариантах DOS, которые я видел (DosBox, MS-DOS 2, FreeDOS), и везде, где я тестировал, флаги уже были в порядке.

введите описание изображения здесь

Matteo Italia
источник
Только что проверил это. Да, это работает. Вы уверены, что вам нужно сделать cld?
FUZxxl
@FUZxxl: на DosBox он отлично работает даже без него, но, глядя на его источники, он говорит, что флаги сохраняются от того, что происходило в DOS и TRS раньше, так что, вероятно, будет необходимо обеспечить его безопасность. В любом случае, это был бы всего один байт, реальным выигрышем было бы уничтожение хотя бы одного из этих больших (= 4 байта каждый) add/ sub.
Matteo Italia
Хм ... понятия не имею, правда.
FUZxxl
Вы можете изменить lopна loop?
mbomb007
@ mbomb007: может быть? Я не уверен, если nasmмежду loopметкой и loopинструкцией по сборке нет различий, поэтому я просто пишу, lopкак и все остальные.
Matteo Italia
28

J, 32 28 байт

Это было весело.

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

объяснение

Вот как это решение работает, в том числе объяснение того, как оно было в гольф.

   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
источник
1
Очень хорошо! Решение полно отличных деталей!
Рандомра
1
(Я обычно добавляю пример вызова функции, чтобы неопытные пользователи тоже могли ее опробовать.)
randomra
Это решение заставляет мою голову болеть:')
Ник Хартли
@QPaysTaxes Я воспринимаю это как комплимент.
FUZxxl
@ FUZxxl Это так. Это также игра слов, основанная на последовательности символов, которая появляется в вашем ответе.
Ник Хартли
15

C, 150 байтов

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

Это было безумно весело для гольфа. Я все еще не убежден, что я закончил с этим.

Мы определяем одну функцию, fкоторая принимает строку в качестве входных данных и выводит в стандартный вывод.

Давайте пройдемся по коду, строка за строкой:

/* 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!
}

Я отвечу на любые ваши вопросы!

Попробуйте тестовую программу онлайн !

BrainSteel
источник
Я хочу помнить, что "char l = strlen (c) +1, o [l * l]" недопустимо, потому что вы не можете определить массив переменного размера, но прошло 15 лет с тех пор, как я попробовал что-нибудь из такого рода в С.
Спарр
@Sparr Мой компилятор даже не выдает предупреждение. Я считаю, что это был «официально» стандарт в C99. Я постараюсь найти ссылку для этого.
BrainSteel
1
@Sparr Вот ссылка.
BrainSteel
Благодарю. Похоже, что в этом отношении ситуация изменилась примерно 15 (давай или бери пару) лет назад :)
Sparr
1
@CoolGuy было бы, но на последующих вызовах f, mбудет не сбрасывается в 0. Это рассчитывает как «нарушение среды,» вне закона здесь .
BrainSteel
15

Retina + Bash, 27 байт (14 + 10 + 3 = 27)

Это использует ANSI Escape:

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

Эквивалент sed -e "s/(/(\\\e[B/g;s/)/\\\e[A)/g". \e[BКод выхода означает перемещение курсора вниз на одну строку, и \e[Aсредство перемещения курсора вверх на одну строку, так что это решение просто вставляет эти коды после того, как и перед началом и в конце каждой вложенной пары скобок. Ввод передается через STDIN.

Вам нужно будет позвонить, printf $(Retina ...)чтобы увидеть результат правильно.

Выход

(((())))
(\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$ 
 (    )()(        )
  ()()    ()(  )()
             ()
user22723
источник
1
Ну не плохо! Если бы вы могли указать конкретный терминал, который не нуждается в printfэтом, было бы здорово. В противном случае, я думаю, было бы справедливо добавить | printfк счетчику байтов.
Мартин Эндер
@ MartinBüttner Это должно быть printf $()или printf $(Retina ).
jimmy23013
1
Что это за ретина?
FUZxxl
2
@FUZxxl Это мой собственный язык программирования на основе регулярных выражений. Смотрите GitHub .
Мартин Эндер
2
Почему \eплюс printf? Вы можете просто поместить управляющие символы в шаблоне замены.
Деннис
15

TI-BASIC, 69 60 56 55 байтов

Это для калькуляторов семейства TI-83 + / 84 +, хотя оно было написано в версии 84+ C Silver Edition.

Программа отображается как более крупная на счету из-за НДС + информация о размере. Также здесь более 56 символов; причина в том, что он составляет 56 байт, потому что все команды, состоящие более чем из одного символа, сжимаются до токенов, размер которых составляет один или два байта.

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

Побрил еще один байт благодаря Томасу-Кве ! (также от него был скачок с 60 до 56.)

М.И. Райт
источник
4
Аааа, мой первый язык программирования. Спасибо за ностальгию, ха-ха.
Алекс Притчард
1
Все еще программируете TI для старших классов по математике, очень полезно иметь встроенные формулы, которые будут рассчитывать на вас на тестах и ​​заданиях.
Элиас Беневедес
1
Если вы перемещаете вещи вокруг, вы можете использовать cos(piAnsхитрость, чтобы сохранить другой байт.
lirtosiast
9

Python 2, 115 байт

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)

Вызовите как f("((()())()(()(())()))"), и вывод на STDOUT.

объяснение

Начнем с n = 0. Для каждого символа в строке ввода:

  • Если символ есть (, мы добавляем nпробелы, то увеличиваемn
  • Если символ есть ), мы уменьшаем, nзатем добавляем nпробелы

Результат затем архивируется и печатается. Обратите внимание, что почтовые zipиндексы Python соответствуют длине самого короткого элемента, например

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

Обычно можно использовать itertools.zip_longest( izip_longest), если они хотят дополнить zipдлину самого длинного элемента.

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

Но в Python 2 это поведение можно смоделировать с помощью отображения None:

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

Python 3, 115 байт

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)

Никакой молнии, просто добавьте соответственно ljust. У этого, кажется, есть некоторый потенциал игры в гольф.

Sp3000
источник
8

R, 151 127 символов

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

С отступами и переводами строки:

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

Использование:

> 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
(                  )
 (    )()(        ) 
  ()()    ()(  )()  
             ()     

Он читает строку как stdin, разбивает ее как вектор из отдельных символов, вычисляет кумулятивную сумму (и) , вычитает первое с последним (с запаздыванием), таким образом вычисляя «уровень» каждой круглой скобки. Затем он выводит на стандартный вывод для каждого уровня либо соответствующие скобки, либо пробел.

Спасибо @MickyT за помощь в значительном сокращении!

plannapus
источник
2
+1 Красивое и элегантное решение. Вы можете сохранить 6, заменив for(i in n)cat(ifelse(D[i]-j," ",S[i]));cat("\n")на X=S;X[which(D!=j)]=' ';cat(X,sep='',fill=T). Тогда nэто на самом деле не требуется, но вам нужно будет немного изменить составную часть. D=c(C(S=="("),0)-c(0,C(S==")"));снижая его до 135.
MickyT
@ MickyT вау спасибо! не думал об этом. whichхотя в этом нет необходимости ( D!=jпоскольку он уже является вектором логических значений, допускающих индексацию). Я не знаю , аргумент fillдля cat, это отличный трюк! Спасибо за то, что заставили меня сократить его на 24 символа!
plannapus
8

C 58 53 52 51 49 байт

Использует escape-последовательности ANSI для перемещения курсора.

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

Если не используется gcc или другой поддерживающий компилятор, \eего можно заменить \x1Bна 2 дополнительных байта.\e[Aперемещает курсор вверх на одну строку и \e[Bперемещает курсор вниз на одну строку. Нет необходимости использовать \e[Bдля перемещения вниз на одну строку, так как для использования символа вертикальной табуляции ASCII на два байта короче0xB или \v.

Предполагается, что входная строка в вопросе состоит только из (сбалансированных) скобок, поэтому проверки четности символа с помощью &1достаточно, чтобы различить (и) .

CL-
источник
7

Пип, 53 байта

Пип является языком код-гольфа моего изобретения. Первая версия была опубликована в субботу, так что я могу официально принять ее за спин! Решение, представленное ниже, не очень конкурентоспособно, поскольку языки игры в гольф идут, но это отчасти потому, что я еще не реализовал такие вещи, как zip и max.

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

Ожидает строку скобок в качестве аргумента командной строки.

"Ungolfed" версия:

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

Объяснение:

В отличие от большинства языков игры в гольф, Pip обязателен для инфиксных операторов, поэтому синтаксис несколько ближе к C и его производным. Он также заимствует идеи из функционального и основанного на массивах программирования. Смотрите хранилище для дальнейшей документации.

Программа сначала генерирует список глубин (сохраняя его z) путем сопоставления функции с входной строкой a. Глобальная переменная vотслеживает текущий уровень. (Переменные a-gв Pip являются функционально-локальными переменными, но h-zявляются глобальными.v Удобно, потому что они предварительно инициализированы в -1.)

Затем мы используем Wцикл hile для генерации и печати каждой строки, пока сгенерированная строка не будет состоять из всех пробелов. vтеперь используется для столбцов и iдля строк. {z@++v=i?as}Функция, неоднократно сопоставляется с исходной входной строки, проверяет , является ли текущая строка iсовпадения линии тока скобка должна быть (как хранится в zсписке). Если это так, используйте скобки ( a); если нет, используйте s(preinitialized to space). Конечным результатом является то, что на каждой итерации oприсваивается список символов, эквивалентный следующей строке вывода.

Чтобы проверить, следует ли нам продолжать цикл, мы проверяем, является ли oсо всеми пробелами RMd пустым. Если нет, выведите его (который по умолчанию объединяет все вместе, как в CJam), сбросьте номер столбца до -1 и увеличьте номер строки.

(Забавный факт: сначала у меня было 51-байтовое решение ... которое не сработало, потому что оно обнаружило ошибку в интерпретаторе.)

DLosc
источник
7

Pyth, 31 байт

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

Попробуйте онлайн.

-/<zk\(/<zhk\): Находит соответствующий уровень для текущей позиции персонажа.

?YqN-/<zk\(/<zhk\)d: Пробел, если соответствующий уровень не является текущим, в противном случае текущий символ.

Js.e?YqN-/<zk\(/<zhk\)dz: Создать строку, сохранить ее в J.

I-JdJ: Если Jне все пробелы, распечатайте его.

Vz: Цикл zраз.

isaacg
источник
6

GNU Bash + coreutils + отступ, 135

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

Ввод / вывод через STDIN / STDOUT:

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

indentделает большую часть тяжелой работы, но должен работать с фигурными скобками вместо паренов. Остальное - модификация этого ответа, чтобы транспонировать вывод indent.

Цифровая травма
источник
5

Python 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)

Печатает построчно. Для данного номера строки i(на самом деле, его отрицание) проходит через входную строку sи создает новую строку, zкоторая содержит только символы sна глубине i. Это делается путем увеличения или уменьшений , iчтобы отслеживать текущую глубину, и добавления текущих символов , когда iэто с 0поправкой на скобку типа, а в противном случае добавления пробела.

Затем печатает и возвращается к следующему, iесли текущая строка не была пробелами. Обратите внимание, что, поскольку парены сбалансированы, iцикл после цикла такой же, как и в начале.

Python 3 будет таким же, за исключением символа для print(z).

XNOR
источник
5

измена :( Retina + TeX, N байт измена :(

Это работает, только если вы отображаете (?) Вывод, используя MathJax или какой-либо другой TeX, который в настоящее время отключен для этого SE :(

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

Каждая строка должна находиться в отдельном файле, но вы можете проверить это с помощью Retina -e "\(" -e "({" -e "\)" -e "})" -e "\{\(" -e "_{("(или эквивалентной команды sed sed -e "s/(/({/g;s/)/})/g;s/{(/_{(/g"). Ввод передается через STDIN.

Это работает, заключая содержимое каждой пары скобок в фигурные скобки, а затем подписывая все элементы внутри них.

Выход

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

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

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

Выход TeX

user22723
источник
1
Я польщен тем, что вы использовали Retina, и это хорошо мыслить нестандартно, но это не совсем то, как должен выглядеть вывод. ;) В частности, это нарушает альтернативную формулировку: «Другой способ взглянуть на это состоит в том, что скобки на глубине n перемещаются в строку n, сохраняя их горизонтальное положение». Я был бы очень впечатлен чистым, совместимым с правилами решением Retina, хотя и мог бы вручить награду за это. ;)
Мартин Эндер
In total the lines must not be longer than twice the length of the input string, Изменение строки 2 на (\,{и строки 4 }\,)означает, что выход соответствует этому (хотя вертикальная глубина по-прежнему неверна: ()
user22723
Что ж, мне удалось сделать совместимое с правилами решение
:)
1
Хорошая работа. Я думаю, это означает, что вы можете удалить обманчивый ответ сейчас. ;)
Мартин Эндер
5

Java, 232 226 224 222 байта

Гольф версия:

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':' ');}

Длинная версия:

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':' '));
}

Входная строка сначала анализируется, ища «(» и «)», чтобы сложить / вычесть счетчик и сохранить его значение, определяющее, как далеко скобки должны идти вниз в массиве, а также отслеживать глубину самого глубокого из них. Затем массив анализируется; круглые скобки с меньшими значениями печатаются первыми и будут продолжать печатать построчно, пока не будет достигнут максимум.

Я, вероятно, найду способ играть в гольф позже.

тротил
источник
5

Javascript / ES6, 97 символов

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

использование

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

объяснение

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
источник
Вместо этого n<m?console.log(o):0вы можете использовать n<m&&console.log(o)который сохраняет 1 байт.
Исмаэль Мигель
4

CJam, 43 41 36 байт

Не слишком удачно (я думаю), но вот моя первая попытка:

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

Как это устроено

Я использую очень удобный факт, что )и (в CJam означают увеличение и уменьшение соответственно. Таким образом, я просто оцениваю скобки, чтобы получить глубину.

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";

Попробуйте онлайн здесь

оптимизатор
источник
4

Октава, 85 символов

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

Это оптимизация наивного подхода, что на самом деле вполне естественно для Matlab и 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;

Таблица t может даже еще не существовать, и мы можем сразу назначить любой элемент, и она преобразуется в наименьшее измерение, необходимое для существования этого элемента, что весьма удобно.

pawel.boczarski
источник
4

Perl, 91 89 88 84 80 79 байт

$t=<>;{$_=$t;s/\((?{$l++})|.(?{--$l})/$^R==$c?$&:$"/ge;print,++$c,redo if/\S/}
  • $ t является входной строкой.
  • $ c - это глубина, которую мы хотим напечатать в текущей строке.
  • $ l - это глубина, на которой мы находимся после встречи с пареном.
  • $ l обновляется во встроенных кодовых блоках regex .
  • $ ^ R - результат самого последнего блока кода.
Helios
источник
4

Haskell, 154 байта

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]]

та же идея, что и у другого решения на Haskell, но несколько короче. - Использование:

echo  '(((())())(()))' | runghc Golf.hs
d8d0d65b3f7cf42
источник
3

J, 46

Не так хорошо, как другие «языки игры в гольф», но в мою защиту: J ужасен со струнами.

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

Принимает строку в качестве входных данных для функции. Там также, вероятно, лучший способ сделать это в J.

Использование:

   f=:[:|:(((,~(' '#~]))"0)(0,2%~[:+/\2+/\1-'(('i.]))~
   f '(()(()())()((())))(())'
(                )(  )
 ()(    )()(    )  () 
    ()()    (  )      
             ()       
ɐɔıʇǝɥʇuʎs
источник
Смотрите мой ответ для другого способа сделать это в J.
FUZxxl
3
Лично я считаю, что J идеально подходит для струнных. Вам просто нужно думать с массивами.
FUZxxl
3

Рубин, 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]}}

Объяснение:

->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
источник
3

Java, 233 214 байт

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]);}

Отступ:

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]);
}

Я думаю, что последний цикл может быть сокращен, но я оставлю это в качестве упражнения для читателя. ;-)


Старый, 233 байта ответа:

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

Отступ:

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
источник
Я знаю, что прошло больше года, но «я думаю, что последний цикл можно было бы сократить, но я оставлю это в качестве упражнения для читателя. ;-)»; ты действительно прав. Его можно изменить с for(x=0;x<l*l;x++)System.out.print((x%l==0?"\n":"")+m[x]);на for(x=0;x<l*l;)System.out.print((x%l==0?"\n":"")+m[x++]);на -1 байт. Кроме того, вы можете сохранить еще 2 байта, удалив их p=x=0и просто используя int p=0,x=0,при инициализации полей. Всего становится 211 байт .
Кевин Круйссен
3

C #, 195 байт

Сначала попробуйте в гольф - кричите, если я сделал что-то не так.

Альтернативная версия C #, использующая SetCursorPosition и работающая слева направо, принимающая ввод в качестве аргумента командной строки.

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++;}}}

Я подумал, что было бы интересно отрегулировать положение записи, основываясь на парене открытия / закрытия, а не на полных строках. Close paren перемещает позицию вверх перед записью; open paren перемещает его вниз после записи. Действие SetCursorPosition сохраняет пять байтов. Перемещение курсора на следующую строку после вывода заняло бы немного больше.

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++;
        }
    }
}
Джереми Мюррей
источник
3

Партия, 356 335 байт

Я знаю, что уже существует пакетное решение для этой задачи, но это значительно больше и кажется, что он использует другой подход. Что наиболее важно, другое пакетное решение содержит по крайней мере одну команду powershell; этого решения нет.

@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.)

На U+0008последней второй строке, следующей за точкой, стоит символ возврата ( ) (строка 12, столбец 57). Это не видно в коде, размещенном здесь, но включено в число байтов.

Анк-Морпорка
источник
Кто-то еще отправляет ответ в Пакетном режиме - Хороший +1.
unclemeat
3

Пакетный, 424 байта

@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!

Un-golfed:

@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!

Пример:

h:\>par.bat (((())())(()))
 (            )
  (      )(  )
   (  )()  ()
    ()
unclemeat
источник
3

C 118 117 байт

Еще один ответ на С, но мой короче.

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("");}}

Безголовая версия:

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("");
    }
}

И это работает!

% ./telescope '()(())((()))(())()'
()(  )(    )(  )()
   ()  (  )  ()
        ()
% ./telescope '((()())()(()(())()))'
(                  )
 (    )()(        )
  ()()    ()(  )()
             ()
MarcDefiant
источник
1
Довольно элегантное решение, однако putchar(c-d?32:*p)на один символ короче putchar(c==d?*p:32).
pawel.boczarski
2

Haskell, 227 байт

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
Джереми Лист
источник
1
Вы можете сохранить несколько пробелов с помощью операторов: например, n#[]вместо m n [].
Фрэнки
2

Perl, 76 байт

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

Нет use strictздесь :)

александр-Brett
источник
2

Lex, 94 байта

Зависит от консольных кодов Linux. С помощью gcc вы можете вырезать четыре байта, заменив оба экземпляра \33фактическим escape-символом.

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

Чтобы скомпилировать и запустить:

$ flex -o telescopic.c telescopic.l
$ gcc -o telecopic telescopic.c -lfl
$ ./telescopic
(()(()())()((())))(())
(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()
--- type ctrl-D ---
RICi
источник