Chaînes topographiques

23

Voici quelques exemples d'entrée, donc je peux expliquer quel est le problème:

((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))

Considérez cette ligne de texte comme une carte topographique de certaines montagnes. Chaque jeu de parenthèses illustre une unité d'altitude.

Si nous «voyons» cela de côté, pour voir les montagnes verticalement, nous verrons:

          4 5                cherries    woohoo  
  1 2  3       moo       lik          e
                      i

Étant donné l'une de ces cartes topographiques, sortez la carte, mais à une échelle verticale, comme la sortie ci-dessus. Séparez les différents éléments de la carte avec le nombre de caractères de l'élément suivant. Par exemple, il y a 4 espaces dans la sortie entre mooet i. De même, il y a 4 caractères dans l'entrée entre mooet i.

Le code qui fait cela dans le moins de caractères gagne.

beary605
la source
Est-il sûr de supposer que les hauteurs seront toujours positives? Par exemple, l'entrée ((1 2))))))))))3doit être invalide si les hauteurs négatives sont interdites.
Cristian Lupascu
@ w0lf: oui, les parenthèses correspondront toujours.
beary605

Réponses:

10

J, 87 79 72 70 67 57 56 caractères

'( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '$~[)"0])1!:1[1

Prend l'entrée du clavier. Exemple:

   '( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '$~[)"0])1!:1[1
((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))
          4 5                cherries    woohoo
  1 2  3       moo       lik          e
                      i

Explication:

Cette explication est basée sur la première version de mon programme:

|.|:('( ) 'charsub x)((' '$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1

x=.1!:1[1prendre l'entrée du clavier et la mettre xpour plus tard

(('('&([:+/=)-')'&([:+/=))\,.i.@#)crée une liste de tous les indéces dans la chaîne ( i.@#) et la coud ( ,.) avec le résultat du (('('&([:+/=)-')'&([:+/=))\verbe.

(('('&([:+/=)-')'&([:+/=))\ce verbe est appliqué à tous les préfixes de la chaîne (donc sur l' entrée hellos'appliquerait à h, he, hel, hellet hello. Il est une fourchette , qui compte le nombre de supports ouverts ('('&([:+/=)et soustrait alors le nombre de crochets proches ')'&([:+/=). Cela me donne la liste d'indéces dans la chaîne et le niveau auquel le caractère à cet index doit être dans la sortie. Sur une entrée simple, cela me donne ce qui suit:

   (('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))
1  0
1  1
1  2
1  3
2  4
2  5
2  6
2  7
3  8
3  9
3 10
3 11
3 12
3 13
2 14
1 15
0 16

((' '$~{.@]),[{~{:@])"1c'est un verbe qui prend la liste que je viens de générer et aussi la sortie de ('( ) 'charsub x)(qui fait juste un remplacement de chaîne pour remplacer tous les crochets par des espaces x). Il prend la queue de chaque élément de la liste {:@]et l'utilise comme index dans la chaîne pour obtenir le caractère [{~{:@]. Il le préfixe ensuite ,avec le nombre d'espaces indiqué par le titre de chaque élément de la liste (' '$~{.@]). Dans l'exemple précédent, cela me donne:

   ('( ) 'charsub x)((' '$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))

 o
 n
 e

  t
  w
  o

   t
   h
   r
   e
   e

Je transpose ensuite le tableau |:et l'inverse |.pour obtenir la sortie souhaitée.

Gareth
la source
6

GolfScript 69

0:§;{.'()'?))3%(.§+:§' ':s*\@s\if\n}%n/.{,}%$)\;:μ;{.,μ\-s*\+}%zip n*

Démo en ligne ici .

Explication:

0:§;                # declare the variable §, representing the 
                    # current vertical level and initialize it at 0

{                   # iterate for each char in the string:

    .'()'?))3% (    # add on the stack the amount by which
                    # the current vertical level should be 
                    # adjusted:
                    #   * +1 if the character is '('
                    #   * -1 if the character is ')'
                    #   * 0 otherwise

    .§+:§           # adjust the value of §

    ' ':s*          # add as many spaces as § tells us
                    # and save the space in variable s

    \@s\if\         # return current char, if it's printable,
                    # or a space if it's '(' or ')'

    n               # add a newline char

}%

n/                  # split by newline char; now we have 
                    # an array of strings on the stack.
                    # Each string is a vertical line of the
                    # final output.

.{,}%$)\;:μ;        # Iterate through the strings and find the
                    # maximum length

{
    .,μ\-s*\+       # Add spaces at the end to make all the strings 
                    # the same length
}%

zip                 # Transpose the strings

n*                  # Join the transposed strings by newline characters
Cristian Lupascu
la source
@Gareth Oui, nous le faisons tous les deux :)
Cristian Lupascu
Voulez-vous ajouter une explication sur la façon dont cela fonctionne?
Timwi
@Timwi J'ai modifié ma réponse pour inclure une explication
Cristian Lupascu
5

APL (59)

⊖↑{⊃,/T\¨⍨⍵×P=0}¨R∘=¨(⍴T)∘⍴¨⍳⌈/R←1++\P←+/¨1 ¯1∘ר'()'∘=¨T←⍞

J'ai supposé que la «base» devait également être utilisable. (c'est-à (a(b))c(d)- dire est valide). Si cela n'est pas nécessaire, deux caractères peuvent être enregistrés.

Explication:

  • T←⍞: stocker une ligne d'entrée dans T
  • '()'∘=¨T: pour chaque caractère en T, voyez s'il s'agit d'une parenthèse ouvrante ou fermante. Cela donne une liste de listes de booléens.
  • 1 ¯1∘ר: multipliez le deuxième élément de chacune de ces listes par -1 (donc une parenthèse ouvrante vaut 1, une parenthèse fermante vaut -1 et tout autre caractère vaut 0).
  • +/¨: prendre la somme de chaque liste intérieure. Nous avons maintenant la valeur ∆y pour chaque caractère.
  • P←: magasin en P.
  • R←1++\P: prendre un total cumulé de P, donnant la hauteur de chaque personnage. Ajoutez un à chaque caractère afin que les caractères en dehors des parenthèses soient sur la première ligne.
  • (⍴T)∘⍴¨⍳⌈/R: pour chaque valeur y possible, faites une liste aussi longue que T, composée uniquement de cette valeur. (c.-à-d. 1111 ..., 2222 ...., etc.)
  • R∘=¨: pour chaque élément de cette liste, voyez s'il est égal à R. (Pour chaque niveau, nous avons maintenant une liste de zéros et de uns correspondant à la présence ou non d'un personnage sur ce niveau).
  • ⍵×P=0: pour chacune de ces listes, mettez-la à zéro si P n'est pas nul à cet endroit. Cela supprime les caractères avec un delta-y non nul, ce qui supprime les parenthèses.
  • ⊃,/T\¨⍨: pour chaque profondeur, sélectionnez parmi T les caractères qui doivent apparaître.
  • ⊖↑: créez une matrice et placez-la à l'endroit.
marinus
la source
Quelle implémentation APL utilisez-vous? C'est gratuit?
FUZxxl
@FUZxxl J'utilise Dyalog APL, la version Windows peut être téléchargée gratuitement.
marinus
5

Tcl, 50

puts \33\[9A[string map {( \33\[A ) \33\[B} $argv]

Sorte de tricherie, mais bon ..

J'utilise des séquences d'échappement ascii pour obtenir la différence de ligne, ^[[Asignifie déplacer la ligne du curseur 1 vers le haut, ^[[Bc'est déplacer la ligne du curseur 1 vers le bas.

Johannes Kuhn
la source
5

APL, 41 caractères / octets *

{⊖⍉⊃(↑∘''¨-⌿+/¨p∘.=,\⍵),¨⍵/⍨1-2×⍵∊p←'()'}

Testé sur Dyalog, avec un environnement ⎕IO←1et ⎕ML←3. C'est une fonction qui prend l'entrée requise et renvoie la sortie. Étant donné le libellé de la question, je pense que c'est acceptable. Dans le cas contraire, voici une version qui lit depuis stdin et écrit dans stdout, pour 4 caractères de plus:

⍞←⊖⍉⊃(↑∘''¨-⌿+/¨'()'∘.=,\a),¨a/⍨1-2×'()'∊⍨a←⍞

Explication :

{                                 p←'()'}  p is the string made of two parentheses
                                ⍵∊ ______  check which characters from ⍵ are parens
                            1-2× ________  -1 for every par., 1 for every other char
                         ⍵/⍨ ____________  replace () with spaces in the orig. string
    (                 ),¨ _______________  append every char to the following items
                   ,\⍵ _____________________  for every prefix of the original string
               p∘.= ________________________  check which chars are '(' and which ')'
            +/¨ ____________________________  sum: compute the number of '(' and ')'
          -⌿ _______________________________  subtract the no. of ')' from that of '('
     ↑∘''¨ _________________________________  generate as many spaces as that number
 ⊖⍉⊃ ____________________________________  make it into a table, transpose and flip

Exemples:

topo '((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))'
          4 5                cherries    woohoo   
  1 2  3       moo       lik          e           
                      i                           

 

topo 'a  (  b ( c(d)e ) f  )  g'
            d            
          c   e          
      b           f      
a                       g

*: APL peut être enregistré dans une variété de jeux de caractères hérités à un octet qui mappent les symboles APL aux 128 octets supérieurs. Par conséquent, dans le but de jouer au golf, un programme qui utilise uniquement des caractères ASCII et des symboles APL peut être noté comme chars = octets.

Tobia
la source
Je recherche le jeu de caractères APL ici et je ne trouve pas le symbole. Cela ressemble à une combinaison des caractères ¨et ~?
Gareth
Salut @Gareth Non, ce n'était pas dans IBM APL2. Vous pouvez le trouver dans Dyalog (commercial, mais il y a une version nagware enterrée dans leur site Web, et c'est assez bon pour le golf; IMHO le meilleur APL disponible aujourd'hui), Nars2000 (meilleur APL open source), GNU APL et APL de ngn , parmi autres.
Tobia
@Gareth Graphiquement, c'est la combinaison de ~et ¨, bien que ce soit un caractère différent des deux. C'est un opérateur appelé Commute . Dans sa forme dyadique il renverse les arguments de la fonction dyadique il est appliqué à: (5-2)=(2-⍨5). En tant que l' opérateur monadique il transforme une fonction dyadique en monadique, dupliquer l'argument droit: (2*2)=(*⍨2). Il est principalement utilisé pour écrire un flux ininterrompu de fonctions de droite à gauche, sans avoir à mettre de parenthèses autour de grandes expressions et à sauter les yeux autour d'elles. Au golf, c'est utile parce qu'il 3*⍨1-2y a un caractère de moins que (1-2)*3:-)
Tobia
2
C'est donc l'équivalent de ~dans J alors.
Gareth
3

J, 56 caractères

'( ) 'charsub|.|:((,~#&' ')"0[:+/\1 _1 0{~'()'&i.)1!:1]1

Une autre solution J 56 caractères ... je compte la profondeur en traduisant (en ⁻1, )en 1 et tous les autres personnages dans 0, puis en prenant la somme en cours d' exécution de celle - ci: [: +/\ 1 _1 0 {~ '()'&i.. Le reste est largement similaire à la solution de @ Gareth.

Luciole
la source
2

Python, 161 caractères

S=raw_input()
R=range(len(S))
H=[S[:i].count('(')-S[:i].count(')')for i in R]+[0]
for h in range(max(H),0,-1):print''.join((' '+S[i])[H[i]==H[i+1]==h]for i in R)
Keith Randall
la source
2

Python, 130

a=[""]*9
l=8
i=0
for c in raw_input():o=l;l+=c==')';l-=c=='(';a[l]=a[l].ljust(i)+c*(o==l);i+=1
print"\n".join(filter(str.strip,a))
grc
la source
2

Rubis 1,9 (129)

Lit à partir de stdin.

l=0
$><<gets.split('').map{|c|x=[?(]*99;x[l+=c==?(?-1:c==?)?1:0]=c;x}.transpose.map(&:join).*(?\n).tr('()',' ').gsub(/^\s+\n/,'')
Paul Prestidge
la source
3
Agréable! vous avez découvert un bug dans le surligneur Ruby :)
Cristian Lupascu
J'ai testé et la mise en évidence SQL fonctionne mieux pour votre programme.
Cristian Lupascu
@ w0lf ha, vous avez raison. J'ai changé //à ce ''qui maintient le nombre de caractères identiques et évite le bug dans le surligneur.
Paul Prestidge
2

C, 132 caractères

char*p,b[999];n;
main(m){for(p=gets(memset(b,32,999));*p;++p)*p-41?*p-40?p[n*99]=*p:++n>m?m=n:0:--n;
for(;m;puts(b+m--*99))p[m*99]=0;}

La description ne précisait pas la quantité de données que la soumission devait accepter pour être acceptée, j'ai donc choisi des limites qui correspondaient le mieux à mes besoins en golf (tout en travaillant avec la seule entrée donnée en exemple). Permettez-moi de saisir cette occasion pour rappeler aux gens que c'est souvent une bonne idée de spécifier des maximums minimum dans vos descriptions de défis.

Il y a deux boucles principales dans le code. La première boucle regroupe tous les caractères non parenthèses sur la ligne de sortie appropriée et la deuxième boucle imprime chaque ligne.

boite à pain
la source
1

C, 149 caractères

#define S for(i=0;c=v[1][i++];)h+=a=c-'('?c-')'?0:-1:1,
c,i,h=0,m=0;main(int a,char**v){S m=h>m?h:m;for(;m;m--){S putchar(a||h-m?32:c);putchar(10);}}

exécuter avec arg cité, egaout "((1 2) (3 (4 5) moo)) (i (lik (cerises) e (woohoo)))"

bébé-lapin
la source
0

Octave, 128

Très similaire à ma dernière réponse ...

p=1;x=[0];y=input(0);for j=1:numel(y);p-=(y(j)==")");x(p,j)=y(j);p+=(y(j)=="(");end;x(x==40)=x(x==41)=x(x==0)=32;char(flipud(x))

Tester

Contribution: "((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))"

Sortie:

          4 5 cerises woohoo   
  1 2 3 moo lik e           
                      je                           
sudo rm -rf slash
la source
0

C #, 229 octets

S'il n'y a aucune restriction sur l'espace vertical de tête, vous pouvez l'utiliser (en retrait pour plus de clarté). Il initialisera le curseur d'une ligne pour chaque élément (trouvé avant l'impression, puis déplacera le curseur de haut en bas pendant la lecture des crochets.

using C=System.Console;
class P{
    static void Main(string[]a){
        int l=a[0].Length,i=l;
        while(i>0)
            if(a[0][--i]=='(')C.CursorTop++;
        while(++i<l){
            char c=a[0][i];
            if(c=='('){
                c=' ';
                C.CursorTop--;
            }
            if(c==')'){
                c=' ';
                C.CursorTop++;
            }
            C.Write(c);
        }
    }
}
Hand-E-Food
la source
0

PowerShell , 120 119 octets

(($h=($c=$args|% t*y)|%{($l+=(1,-1)[$_-40])})|sort)[-1]..0|%{$x=0;$y=$_
-join($c|%{"$_ "[$h[$x++]-ne$y-or$_-in40,41]})}

Essayez-le en ligne!

Effets secondaires: Caractère &et 'change la hauteur au fur (et à mesure ), mais s'affiche. Comparez les résultats pour:

&$f "((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))"
&$f "&&1 2'&3 &4 5' moo'' &i &lik&cherries'e &woohoo'''"

Moins golfé:

$chars=$args|% toCharArray

$heights=$chars|%{
    $level+=(1,-1)[$_-40]       # 40 is ASCII for '(', 41 is ASCII for ')'
    $level
}

$maxHeight=($heights|sort)[-1]

$maxHeight..0|%{
    $x=0;$y=$_
    $line=$chars|%{
        "$_ "[$heights[$x++]-ne$y -or $_-in40,41]
    }
    -join($line)
}
mazzy
la source
-1

VB.net (pour S&G)

Pas le plus joli du code.

Module Q
 Sub Main(a As String())
  Dim t = a(0)
  Dim h = 0
  For Each m In (From G In (t.Select(Function(c)
                                     h += If(c = "(", 1, If(c = ")", -1, 0))
                                     Return h
                                   End Function).Select(Function(y, i) New With {.y = y, .i = i}))
             Group By G.y Into Group
             Order By   y Descending
            Select Group.ToDictionary(Function(x) x.i)
               ).Select(Function(d) New String(
                          t.Select(Function(c,i)If(d.ContainsKey(i),If(c="("c Or c=")"c," "c,c)," "c)).ToArray))
   Console.WriteLine(m)
  Next
 End Sub
End Module
Adam Speight
la source