Construyeme una ciudad


34

Los codificadores siempre están tratando de aplanar matrices en entidades aburridas unidimensionales y eso me entristece.

Su tarea es desplegar una cadena arbitraria de caracteres, generando un hermoso paisaje urbano.

Considere la cadena: aaabbbbbccqrrssstttttttPPw

Se ve mucho mejor así:

            tt
            tt
  bb        tt
  bb        tt
aabb      sstt
aabbcc  rrssttPP
aabbccqqrrssttPPww

(Ok, sí, las letras están duplicadas para que se vea más ciudad-horizonte-ery).

¡Toma una cadena de entrada, duplica cada subsección de caracteres coincidentes (no necesariamente letras alfabéticas) y construye una ciudad para mí!

Los bytes de código más cortos ganan.

De hecho, pensé que tenía los requisitos establecidos, pero para responder algunas preguntas:

  • debe estar en el suelo
  • puede tener cielo adicional si lo desea (líneas en blanco iniciales, espacio en blanco circundante), pero no entre los edificios
  • las letras se pueden reutilizar dentro de la cadena (misma arquitectura, ubicación diferente)
  • se supone que las letras son ASCII, pero se dará más estilo a quienes admitan codificaciones adicionales (UTF8, etc.)

3
¿Podemos sacar el paisaje urbano rotado 90 grados?
Okx

66
¿Volverán a repetirse los personajes, es decir aaabbbbaa?
TheLethalCoder

14
@Okx ¿alguna vez has visto una ciudad girada 90 grados, eso se vería muy tonto! ;)
Tom

77
Rod

10
Bienvenido en el sitio! Para futuros desafíos, recomiendo publicarlos primero en el Sandbox donde puede obtener comentarios de la comunidad antes de publicarlo como un desafío.
Dada

Respuestas:


11

05AB1E , 6 bytes

γ€DζR»

Pruébalo en línea!

En una versión más nueva que el desafío, ζse ha agregado como reemplazo para.Bø

05AB1E , 8 bytes

γ€D.BøR»

Explicación:

γ            Convert into a list of consecutive equal elements
 €D          Duplicate each element
   .B        Squarify; pad each element with spaces so that they are the length of the longest element
     ø       Transpose
      R      Reverse (otherwise the city would be upside-down)
       »     Join by newlines

Pruébalo en línea!


1
Curiosamente, Jelly tiene z⁶para .Bø... pero también tiene Œgx'2para γ€D> _>
Erik the Outgolfer

γ.BD)ø˜øR»era lo que tenía sin mirar, €Des mucho mejor; Sin embargo, creo que a los dos nos falta la solución de 1 byte para la duplicación en línea.
Magic Octopus Urn

3
@MagicOctopusUrn Espera, ¿resolviste el desafío sin siquiera mirarlo?
Okx

@Okx Bueno, es aconsejable no mirar las respuestas antes, ya que toda la diversión de jugar golf por ti mismo podría interrumpirse.
Erik the Outgolfer

@EriktheOutgolfer Fue una broma, y ​​lo que quiero decir es que lo resolvió sin mirar el contenido del desafío.
Okx

6

CJam , 23 bytes

qe`::*:__:,:e>f{Se[}zN*

Pruébalo en línea!

Explicación:

qe`::*:__:,:e>f{Se[}zN* Accepts (multi-line?) input
q                       Take all input
 e`::*                  Split into groups of equal elements
      :_                Duplicate each
        _:,:e>          Push maximal length without popping
              f{Se[}    Left-pad each to that length with space strings (NOT space chars, although not a problem here)
                    z   Zip
                     N* Join with newlines

Wow, una respuesta de CJam> _>
Sr. Xcoder

6

Jalea , 9 bytes

Œgx'2z⁶ṚY

Pruébalo en línea!

Explicación:

Œgx'2z⁶ṚY  Main Link
Œg         Group runs of equal elements
  x        Repeat
   '              the lists
    2                       twice without wrapping
     z⁶    Zip (transpose), filling in blanks with spaces
       Ṛ   Reverse the whole thing so it's upside-down
        Y  Join by newlines

1
¿Podría agregar una explicación por favor milord? No puedo entender lo que está pasando aquí: o
Nathan


@HyperNeutrino Buena explicación ...
Erik the Outgolfer

Solo para estar seguro, ¿es correcto? : P
HyperNeutrino

@HyperNeutrino Well, that wasn't entirely the intention for ', which was to repeat the lists themselves and not the items inside them, but overall it's good. :)
Erik the Outgolfer

6

Python 3, 155 136 134 132 bytes

-19 bytes thanks to @LeakyNun
-2 bytes thanks to @officialaimm
-1 byte thanks to @Wondercricket

s=input()+'+'
k=' '*len(s)
a=[]
c=b=''
while s:
 while c in b:b+=c;c,*s=s
 a+=b+k,b+k;b=c
for r in[*zip(*a)][:0:-1]:print(*r,sep='')

Try it online!



5

Java 8, 412 400 330 324 312 319 bytes

-6 bytes thanks to VisualMelon
-12 bytes thanks to Kevin Cruijssen
but +19 bytes because I forgot to include the imports in the byte count.

import java.util.*;x->{Map m=new HashMap(),n;int l=x.length(),i=l,v,y,h=0,d=1;char c,k;for(;i-->0;m.put(c,d=m.get(c)!=null?d+1:1),h=d>h?d:h)c=x.charAt(i);for(y=h;y>0;y--){n=new HashMap(m);for(i=0;i<l;i++)if(n.get(k=x.charAt(i))!=null){v=(int)m.get(k);System.out.print((y>v?"  ":k+""+k)+(i==l-1?"\n":""));n.remove(k);}}}

Try it online!


1
Golfing Java and C# (my department) is great fun! Keep at it! Not tested, but I think you can save a few bytes by rejigging the for loops: you can pre-assign i=0, or better, i=l, and count down for(;i-->0;h=d>h?d:h) (and stuff the h= bit in there). The same back-counting will work for the inner loop also. The inner if also has no need for the braces {}. And always be weary of <= or >=, you can turn the ternary around with > and save a byte.
VisualMelon

Thanks, I could shave another 6 bytes off the code thanks to your tips. Well, I think I'm going to stay with Java Golfing since I actually like it ;).
Twometer

1
Welcome to PPCG! I'm afraid you'll have to increase the byte-count to 329 (+19 bytes due to the required import java.util.*; for Map and HashMap, imports are part of the byte-count; and -1 by removing trailing semi-colon, which isn't part of the byte-count).
Kevin Cruijssen


1
Summary of the changes: HashMap<>HashMap; Map n=,n and n=; m.put(c,d=m.get(c)!=null?d+1:1); inside the for-loop to get rid of the brackets; k=x.charAt(i) inside the if(n.get(k)!=null) to get rid of the semi-colon and for-loop's brackets. Again, welcome and great answer! +1 from me. Also, in case you haven't seen it yet: Tips for golfing in Java and Tips for golfing in <any language> might be interesting to read through.
Kevin Cruijssen

5

Japt, 19 18 15 13 12 bytes

Includes trailing spaces on each line.

ò¦
íU c ·z w

Test it


Explanation

         :Implicit input of string U
ò        :Split U to an array by ...
¦        :   checking for inequality between characters.
í        :Pair each item in U with...
U        :   The corresponding item in U (i.e, duplicate each string)
c        :Flatten the array (í creates an array of arrays).
·        :Join to a string with newlines.
z        :Rotate 90 degrees.
w        :Reverse.
         :Implicit output of resulting string.

4

Mathematica, 150 bytes

(z=Characters[v=#];f=CharacterCounts[v][#]&/@(d=Union@z);Row[Column/@Map[PadLeft[#,Max@f,""]&,Table[Table[d[[i]]<>d[[i]],f[[i]]],{i,Length@d}],{1}]])&

4

R, 135 bytes

e=rle(sub('(.)','\\1\\1',strsplit(scan(,''),'')[[1]]));write(sapply(sum(e$l|1):1,function(x)ifelse(e$l>=x,e$v,'  ')),'',sum(e$l|1),,'')

Try it online!

reads from stdin, writes to stdout (with a trailing newline).

Explanation:

  • rle finds the lengths of the streaks of characters, the heights of each tower.
  • the sub expression replaces each character with its double (so I didn't have to muck about with setting adjacent indices together)
  • sapply returns an array (in this case a matrix):
    • sum(e$l|1) is the number of distinct characters; we go from top to bottom
    • ifelse( ... ) is a vectorized if...else allowing us to build a matrix of towers and double spaces
    • write writes to console, with a few options to format.



2

MATL, 15 bytes

'(.)\1*'XXtvc!P

Try it online!

Explanation

'(.)\1*' % Push string to be used as regexp pattern
XX       % Implicit input. Regexp matching. Pushes row cell array of matching substrings
t        % Duplicate
v        % Concatenate vertically
c        % Convert to char. This reads cells in column-major order (down, then across)
         % and produces a 2D char array, right-padding with spaces
!        % Transpose
P        % Flip vertically. Implicitly display

2

Charcoal, 40 bytes:

A⟦⟦ω⟧⟧λFθ¿⁼ι§§λ±¹¦⁰⊞§λ±¹ι⊞λ⟦ι⟧FλF²↑⁺⪫ιω¶

Try it online! Link is to verbose version of code. I originally tried a simple loop over the input string to print an oblong every time the letter changed, but I switched to this list-building method as it saved 5 bytes. Explanation: The variable l contains a nested list of the input letters. Characters that match the current last list elements get pushed onto the last list otherwise a new sublist is created for that character. It then remains to join the letters in each sublist so that they can be printed vertically twice.


2

C, 259 231 Bytes

Golfed Code

#define v a[1][i
i,k,l,x,h,w;main(char*s,char**a){for(;v];w+=2*!x,s=v++],h=x>h?x:h)x=(s==v])*(x+1);h++;s=malloc((x=h++*++w+1)+w);memset(s,32,h*w);for(i=k;v];s[x+1]=s[x]=k=v++],x=k==v]?x-w:(h-1)*w+l++*2+3)s[i*w]=10;printf("%s",s);}

Verbose Code

//Variable Explanations:
//i - increment through argument string, must beinitialized to 0
//k - increment through argument string, must be initialized to 0
//l - record x coordinate in return value, must be initialized to 0
//x - record the actual character position within the return string
//arrheight - the height of the return string
//arrwidth - the width of the return string
//arr - the return string
//argv - the string containing the arguments
#define v argv[1][i

i,k,l,x,arrheight,arrwidth;

main(char*arr,char**argv){
  for(;v];                                 //For Length of input
    arrwidth+=2*!x,                        //increment width by 2 if this char is not the same as the last
    arr=v++],                              //set arr to current char
    arrheight=x>arrheight?x:arrheight      //see if x is greater than the largest recorded height
  )x=(arr==v])*(x+1);                     //if this character is the same as the last, increment x (using arr to store previous char)
  arrheight++;                             //increment height by one since its 0 indexed
  arr=malloc((x=arrheight++*++arrwidth+1)+arrwidth); //create a flattened array widthxheight and set x to be the bottom left position
  memset(arr,32,arrheight*arrwidth);       //fill array with spaces
  for(i=k;v];                              //For Length of input
    arr[x+1]=arr[x]=k=v++],                //set x and x+1 positions to the current character, store current character in i
    x=k==v]?x-arrwidth:(arrheight-1)*arrwidth+l++*2+3 //if next char is same as current move vertically, else set x to bottom of next column
  )arr[i*arrwidth]=10;                     //Add new lines to string at end of width

  printf("%s",arr);                        //output string

}

Compiled with GCC, no special Flags

Edit

Saved 28 bytes thanks to adelphus. His change allowed me to create a define. And I made the while loops into for loops to save 2 bytes each by rearranging the loop. I also fixed an issue where the code would break when the last character in input wasn't singleton. The code will fail if there is only one unique letter but should work in all other cases.


Nice! But the golfed version doesn't seem to work with arbitrary input for some reason. Removing the final "w" from the sample input appears to lose the q's and repeat the string. Sure it's something small...
adelphus

also while (i < strlen(argv[1])) can be shortened to while (argv[1][i]) - loop until null character
adelphus

@adelphus Interesting, I'll try it out tomorrow when I get a chance. I did not test anything other than the given test case (lazy I know).
dj0wns

That actually helped a ton, I was able to fix the problem and reduce by almost 30 bytes!
dj0wns

1

Pip, 22 bytes

21 bytes of code, +1 for -l flag.

Ya@`(.)\1*`RV:yWVyZDs

Try it online!

Explanation

                       a is 1st cmdline arg; s is space (implicit)
 a@`(.)\1*`            Using regex, create list of runs of same character in a
Y                      Yank that into y variable
              yWVy     Weave (interleave) y with itself to duplicate each item
                  ZDs  Zip to transpose, with a default character of space filling gaps
           RV:         Reverse the resulting list (with the compute-and-assign
                        meta-operator : being abused to lower the precedence)
                       Auto-print, one sublist per line (implicit, -l flag)

1

QuadS, 15 + 1 = 16 bytes

+1 byte for the 1 flag.

⊖⍵
(.)\1*
2/⍪⍵M

Try it online!

⊖⍵ post-process by flipping upside down

(.)\1* runs of identical characters

2/⍪⍵M duplicate the columnified Match

The 1 flag causes the results to be merged together.


1

Haskell, 144 bytes

f s=let x=groupBy(==)s;l=length;m=maximum(map l x)in concatMap(++"\n")$reverse$transpose$concat[[z,z]|z<-(map(\y->y++(replicate(m-(l y))' '))x)]

I'm pretty confident I can do better than this, but this is the best I can come up with for the time being.


1
Bad news first: you use functions from Data.List which is not in scope by default. You have to either add the import Data.List to the byte count or specify a Haskell environment which does include it by default (e.g. change the language from Haskell to Haskell (lambdabot). -- Some tips: a) use pattern guards to bind variables instead of let and/or declare helper functions directly: l=length;f s|x<-groupBy(==)s,m<-... =concatMap. b) map l x is l<$>x, c) concatMap("++\n" is unlines. d) groupBy(==) is just group. e) concat is id=<<. You use m only once, so inline it
nimi

1
... f) no need for () around l y, replicate ... ' ' and map ... x. All in all: import Data.List;l=length;f s|x<-group s=unlines$reverse$transpose$id=<<[[z,z]|z<-map(\y->y++replicate(maximum(l<$>x)-l y)' ')x].
nimi

1
groupBy(==)=group, altough I'm not sure whether one is in Prelude and the other isn't. concatMap can be written >>=, and map can be infixed as <$>, and concat[[z,z]|z<-…] might be (replicate 2)=<<… or (\z->[z,z])=<<…
Bergi

You can shave off one more byte from @Bergi's excellent tip: (\z->[z,z]) is (:)<*>pure, i.e. ...transpose$(:)<*>pure=<<map(\y...)x
nimi




0

q/kdb+, 53 bytes

Solution:

{(|)(+)(,/)(max(#:)each c)$(+)2#(,)c:((&)differ x)_x}

Example:

 q){(|)(+)(,/)(max(#:)each c)$(+)2#(,)c:((&)differ x)_x}"BBPPPPxxGGGGKKKKKKKkkkkEEeeEEEeeEEEEEOOO8####xxXXX"
 "        KK                      "
 "        KK                      "
 "        KK          EE          "
 "  PP  GGKKkk        EE    ##    "
 "  PP  GGKKkk    EE  EEOO  ##  XX"
 "BBPPxxGGKKkkEEeeEEeeEEOO  ##xxXX"
 "BBPPxxGGKKkkEEeeEEeeEEOO88##xxXX"

Explanation:

{reverse flip raze (max count each c)$flip 2#enlist c:(where differ x)_x} / ungolfed function
{                                                                       } / lambda function
                                                      (where differ x)    / indices where x differs
                                                                      _   / cut at these points aabbbc -> "aa","bbb","c"
                                                    c:                    / save in variable c
                                             enlist                       / put this list in another list
                                           2#                             / take two from this list (duplicate)
                                      flip                                / rotate columns/rows
                   (max count each c)                                     / find the longest run of characters
                                     $                                    / whitespace pad lists to this length
              raze                                                        / reduce down lists
         flip                                                             / rotate columns/rows
 reverse                                                                  / invert so buildings are on the ground

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.