Palabras -> Skyline de la ciudad

40

El reto

Su programa o función aceptará una sola entrada de cadena de STDIN o un parámetro de función. Puede suponer que la entrada contendrá solo caracteres alfabéticos (a-zA-Z), espacios y puntos completos. La entrada no distingue entre mayúsculas y minúsculas, por lo que debe tratar 'a' exactamente igual que trataría 'A'.

Para cada carácter en la cadena, generará una representación de un edificio según la siguiente especificación.

Cada edificio debe tener un techo, designado por un guión bajo en la línea superior y luego una barra oblicua, espacio, barra invertida en la segunda línea.

 _
/ \

Luego tendrá una serie de pisos, que coinciden con el número de letra (a = 1, b = 2, c = 3, etc.) que están representados por una pared (|) en cada lado y un espacio en el medio. El piso inferior (y solo el piso inferior) debe tener una base, que es un guión bajo entre las paredes. Me gusta esto...

|_|

Entonces, por ejemplo, 'b' se vería así

 _
/ \
| |
|_|

Ahora, sabemos que los edificios muy altos y estrechos no pueden sostenerse y deben ensancharse en la base, por lo que ningún edificio puede tener más de tres pisos de altura sin algún soporte adicional. Por lo tanto, cada tres niveles (no menos) debe agregar una 'capa de ampliación'. La capa de ensanchamiento consiste en una barra oblicua y una barra invertida directamente encima de las paredes de la sección debajo de esta, y la sección de abajo debe ser dos espacios más ancha que la sección de arriba. La capa adicional no cuenta para la altura del edificio.

Los edificios no deben superponerse, pero no deben tener espacios innecesarios entre ellos, y el suelo siempre es plano, por lo que todos los edificios deben tener su base en el mismo nivel.

Por ejemplo, 'abcdefga' se verá así.

                           _
                          / \
                     _    | |
                _   / \   | |
           _   / \  | |   | |
          / \  | |  | |  /   \
       _  | |  | |  | |  |   |
    _ / \ | |  | | /   \ |   |
 _ / \| | | | /   \|   | |   |  _
/ \| || |/   \|   ||   |/     \/ \
|_||_||_||___||___||___||_____||_|

Los espacios en la entrada de cadena deben estar representados por un doble espacio.

Las paradas completas en la entrada de la cadena deben representarse con escombros como este.

/\/\

Ejemplos adicionales

Entrada = Hello world.

Salida =

                                                   _                                                  
                                                  / \                                                 
                                                  | |                                                 
                                                  | |                                                 
                                                  | |                                                 
                                                 /   \                                                
                                                 |   |                                                
                                                 |   |                       _                        
                                                 |   |                      / \                       
                                                /     \                     | |                       
                                                |     |                     | |                       
                                   _            |     |          _          | |                       
                                  / \           |     |         / \        /   \                      
                                  | |          /       \        | |        |   |                      
                                  | |          |       |        | |        |   |                      
                _        _        | |          |       |        | |        |   |        _             
               / \      / \      /   \         |       |       /   \      /     \      / \            
               | |      | |      |   |        /         \      |   |      |     |      | |            
               | |      | |      |   |        |         |      |   |      |     |      | |            
               | |      | |      |   |        |         |      |   |      |     |      | |            
   _          /   \    /   \    /     \       |         |     /     \    /       \    /   \           
  / \         |   |    |   |    |     |      /           \    |     |    |       |    |   |           
  | |         |   |    |   |    |     |      |           |    |     |    |       |    |   |           
  | |         |   |    |   |    |     |      |           |    |     |    |       |    |   |           
  | |    _   /     \  /     \  /       \     |           |   /       \  /         \  /     \          
 /   \  / \  |     |  |     |  |       |    /             \  |       |  |         |  |     |   _      
 |   |  | |  |     |  |     |  |       |    |             |  |       |  |         |  |     |  / \     
 |   |  | |  |     |  |     |  |       |    |             |  |       |  |         |  |     |  | |     
 |   |  | | /       \/       \/         \   |             | /         \/           \/       \ | |     
/     \/   \|       ||       ||         |  /               \|         ||           ||       | | |     
|     ||   ||       ||       ||         |  |               ||         ||           ||       |/   \    
|_____||___||_______||_______||_________|  |_______________||_________||___________||_______||___|/\/\

Entrada = lorem ipsum

                                                                                             _                  
                                                                                            / \                 
                                                                              _             | |                 
                                                                             / \            | |                 
                          _                                                  | |            | |                 
                         / \                                                 | |           /   \                
                         | |                                    _            | |           |   |                
                         | |                                   / \          /   \          |   |                
              _          | |                                   | |          |   |          |   |                
             / \        /   \                                  | |          |   |         /     \               
             | |        |   |              _                   | |          |   |         |     |         _     
             | |        |   |             / \                 /   \        /     \        |     |        / \    
    _        | |        |   |             | |                 |   |        |     |        |     |        | |    
   / \      /   \      /     \            | |                 |   |        |     |       /       \       | |    
   | |      |   |      |     |            | |                 |   |        |     |       |       |       | |    
   | |      |   |      |     |           /   \               /     \      /       \      |       |      /   \   
   | |      |   |      |     |           |   |        _      |     |      |       |      |       |      |   |   
  /   \    /     \    /       \          |   |       / \     |     |      |       |     /         \     |   |   
  |   |    |     |    |       |          |   |       | |     |     |      |       |     |         |     |   |   
  |   |    |     |    |       |         /     \      | |    /       \    /         \    |         |    /     \  
  |   |    |     |    |       |         |     |      | |    |       |    |         |    |         |    |     |  
 /     \  /       \  /         \   _    |     |     /   \   |       |    |         |   /           \   |     |  
 |     |  |       |  |         |  / \   |     |     |   |   |       |    |         |   |           |   |     |  
 |     |  |       |  |         |  | |  /       \    |   |  /         \  /           \  |           |  /       \ 
 |     |  |       |  |         |  | |  |       |    |   |  |         |  |           |  |           |  |       | 
/       \/         \/           \ | |  |       |   /     \ |         |  |           | /             \ |       | 
|       ||         ||           |/   \ |       |   |     | |         |  |           | |             | |       | 
|       ||         ||           ||   |/         \  |     |/           \/             \|             |/         \
|_______||_________||___________||___||_________|  |_____||___________||_____________||_____________||_________|

Entrada = a.a.a.x.x.x.a.a.a

                             _                    _                    _                             
                            / \                  / \                  / \                            
                            | |                  | |                  | |                            
                            | |                  | |                  | |                            
                            | |                  | |                  | |                            
                           /   \                /   \                /   \                           
                           |   |                |   |                |   |                           
                           |   |                |   |                |   |                           
                           |   |                |   |                |   |                           
                          /     \              /     \              /     \                          
                          |     |              |     |              |     |                          
                          |     |              |     |              |     |                          
                          |     |              |     |              |     |                          
                         /       \            /       \            /       \                         
                         |       |            |       |            |       |                         
                         |       |            |       |            |       |                         
                         |       |            |       |            |       |                         
                        /         \          /         \          /         \                        
                        |         |          |         |          |         |                        
                        |         |          |         |          |         |                        
                        |         |          |         |          |         |                        
                       /           \        /           \        /           \                       
                       |           |        |           |        |           |                       
                       |           |        |           |        |           |                       
                       |           |        |           |        |           |                       
                      /             \      /             \      /             \                      
                      |             |      |             |      |             |                      
                      |             |      |             |      |             |                      
                      |             |      |             |      |             |                      
                     /               \    /               \    /               \                     
 _      _      _     |               |    |               |    |               |     _      _      _ 
/ \    / \    / \    |               |    |               |    |               |    / \    / \    / \
|_|/\/\|_|/\/\|_|/\/\|_______________|/\/\|_______________|/\/\|_______________|/\/\|_|/\/\|_|/\/\|_|

Reglas

  • Por supuesto, este es el código de golf, gana la puntuación más baja en bytes
  • Se aplican las reglas de laguna legal estándar
  • Se permite cualquier cantidad de líneas en blanco adicionales antes o después de la salida
  • Puede elegir generar el resultado completo en una cadena u ofrecer la salida como una matriz donde cada elemento representa una línea de salida, o enviar a STDOUT

Nota

Esta es mi primera publicación en PPCG, así que, por favor, ve con calma. Ha pasado por la caja de arena. Cualquier punto negativo o posibles mejoras, publíquelo como comentario y haré lo que pueda

Darren H
fuente
77
La conversión [a,z]y [A,Z]al [1,26]parece un requisito inútil. Sería mucho mejor usar solo una lista de enteros como entrada (teniendo que 0ser la entrada para los escombros). Además, publicar su desafío después de haber estado en el Sandbox durante solo 21 horas , sin esperar a recibir más votos o comentarios de más de un usuario, no cuenta como si hubiera "pasado por el sandbox". Se recomienda dejar los desafíos en el Sandbox durante 48-72 horas como mínimo, para darles a las personas suficiente tiempo para revisarlos.
Mego
2
Me recuerda a esto . Buen primer desafío, pero yo sugeriría que considerar el cambio del [a,z], [1.26]partes del Mego mencionados. Tenerlo opcional es a menudo lo mejor (a menos que sea una parte clave del desafío (no está aquí).
Stewie Griffin
2
Diré, este es un primer desafío muy agradable. Bienvenido al sitio!
DJMcMayhem
1
Puedo entender el punto sobre el mapeo az a los enteros. Tenía sentido en la primera iteración del desafío, pero desde la edición para mayor claridad y brevedad (había una historia de fondo que he eliminado) las letras ya no son relevantes. Editaré apropiadamente lo antes posible
Darren H
1
Prefiero az, espacio, punto, personalmente.
isaacg

Respuestas:

10

JavaScript (ES6), 330 326 ... 315 309 bytes

Construye el arte ASCII de forma recursiva, comenzando con el piso inferior y aplicando varias expresiones regulares entre cada etapa:

(a,l,R=(E,b)=>E.split`:`.map((e,i)=>l=(l||a).replace(RegExp(e,'g'),b?b.split`:`[i]:n=>(x=(n.charCodeAt()-65)%32)<0?x+1?'/y/y':n+n:x%3+'_'.repeat((x/3<<1)+1)+0)))=>(L=l)?(R('/y:_:/xy:1:2:/xx(x+)y:0(x+)0:3','  :x: _ :3:1: 2$10 :/$1y:0'),L==l?(l=a.join`
`,R('\\d:x:y','|: :\\'),l):f([l].concat(a),l)):f(R('.'),l)

Cómo funciona

1) piso inferior

Comenzamos traduciendo la cadena de entrada en un piso inferior como:

"ab cd.df.hcab"  -->  "0_01_0  2_00___0/y/y0___02___0/y/y1_____02_00_01_0"

dónde:

  • y es un alias más corto para la barra diagonal inversa (que requiere escapar)
  • El dígito ( 0, 1o 2) justo antes de una secuencia de _es la pared izquierda del edificio. Representa el número de muros que se deben colocar encima antes de la próxima 'capa de ampliación'.
  • El dígito después de una secuencia de _es la pared derecha del edificio y siempre se establece en 0.

2) Expresiones regulares aplicadas entre cada etapa

El proceso recursivo consiste en aplicar 9 reemplazos en el piso anterior, usando las siguientes expresiones regulares:

  1. /\/y/g=> " "(quitar los escombros)
  2. /_/g=> "x"(reemplace la base o la parte superior del edificio con un bloque sólido)
  3. /\/xy/g=> " _ "(reemplace la última capa de ampliación con la parte superior del edificio)
  4. /1/g=> "3"(reemplazar temporalmente 1con 3- ver el último paso)
  5. /2/g=> "1"(reemplazar 2con 1)
  6. /\/xx(x+)y/g=> " 2$10 "(reemplace una capa de ensanchamiento con una pared nueva y más estrecha)
  7. /0(x+)0/g=> "/$1y"(reemplace la parte superior de la pared con una capa de ensanchamiento)
  8. /3/g=> "0"(reemplazar 3con 0)

Por ejemplo, aquí están las transformaciones sucesivas de 2___0(piso inferior generado por a 'f'):

"2___0" > "1xxx0" > "0xxx0" > "/xxxy" > " 2x0 " > " 1x0 " > " 0x0 " > " /xy " > "  _  "

                                                                                   _   
                                                                        /xy       /xy  
                                                              0x0       0x0       0x0  
                                                    1x0       1x0       1x0       1x0  
                                          2x0       2x0       2x0       2x0       2x0  
                               /xxxy     /xxxy     /xxxy     /xxxy     /xxxy     /xxxy 
                     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0 
           1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0 
 2___0     2___0     2___0     2___0     2___0     2___0     2___0     2___0     2___0 

NB : la parte superior del edificio se reemplaza por a x. Esto no se muestra en el diagrama anterior.

3) Expresiones regulares aplicadas al resultado final

La recursión se detiene cuando no hay nada más que reemplazar, lo que significa que estamos más allá de la parte superior del edificio más alto.

Ahora necesitamos limpiar todo con otras expresiones regulares:

  1. /\d/g=> "|"(reemplazar dígitos con tuberías)
  2. /x/g=> " "(reemplazar bloques sólidos con espacios)
  3. /y/g=> "\"(reemplazar ycon barras invertidas)

Por ejemplo:

  _            _  
 /xy          / \ 
 0x0          | | 
 1x0          | | 
 2x0   -->    | | 
/xxxy        /   \
0xxx0        |   |
1xxx0        |   |
2___0        |___|

Manifestación

let f =

(a,l,R=(E,b)=>E.split`:`.map((e,i)=>l=(l||a).replace(RegExp(e,'g'),b?b.split`:`[i]:n=>(x=(n.charCodeAt()-65)%32)<0?x+1?'/y/y':n+n:x%3+'_'.repeat((x/3<<1)+1)+0)))=>(L=l)?(R('/y:_:/xy:1:2:/xx(x+)y:0(x+)0:3','  :x: _ :3:1: 2$10 :/$1y:0'),L==l?(l=a.join`
`,R('\\d:x:y','|: :\\'),l):f([l].concat(a),l)):f(R('.'),l)

console.log(f('ab cd.df.hcab'));

Colaboradores:
4 bytes guardados gracias a Hedi
8 bytes guardados gracias a Not that Charles

Arnauld
fuente
Cualquier persona que quiera tomar una entrada como un número entero es bienvenido, pero sugeriría que tal entrada no sea competitiva
mbomb007
@ mbomb007: esto se ha solucionado. Sin .charCodeAt()embargo, mis optimizaciones actuales no compensan el costo de los infames .
Arnauld
No necesita new ennew RegExp(e,'g')
Hedi
Me gusta mucho este enfoque. Algunas ideas que pueden ayudar: 1. usar un personaje como yese no requiere escapar para su barra diagonal. 2. si se utiliza _para la planta baja, todavía se puede diferenciar la parte superior con la expresión regular: /_ /.
No es que Charles
1
@NotthatCharles: en realidad nunca noté la regla del "doble espacio". ;) Esto está arreglado.
Arnauld
7

PHP, 386 376 367 364 362 358 356 bytes

primer enfoque; aún puede ser golfable.

foreach(str_split($argv[1])as$c)for($n=28,$w='.'!=$c?1+2*ceil(1/3*$n=31&ord($c)):4,$p=$y=0;$y<36;){$s=str_pad("",$w,$y||!$n?" ":_);if($n>26&&!$y){$s="/\\/\\";$n=-1;}elseif($n-->0){$s[$p]=$s[$w-$p-1]="|";if($n%3<1){$o[$y++].=$s;$s=str_pad("",$w);$s[$p]="/";$s[$w-++$p]="\\";}}$o[$y++].=$s;if(!$n)$o[$y++].=str_pad(_,$w," ",2);}for($y=36;$y--;)echo"$o[$y]
";

PHP, 366 362 361 360 357 bytes

enfoque similar con una subfunción:

function a($p,$r){global$o,$w,$y;$o[$y++].=str_pad(str_pad($r[0],2*$p,$r[1]).$r[2],$w," ",2);}foreach(str_split($argv[1])as$i=>$c)for($n=28,$w='.'!=$c?1+2*$p=ceil(1/3*$n=31&ord($c)):$p=4,$y=0;$y<36;)if($n>26&&!$y)$o[$n=$y++].="/\\/\\";elseif($n-->0){a($p,$y?"| |":"|_|");if($n%3<1)a($p--,"/ \\");if(!$n)a(1," _");}else a(0,"");for($y=36;$y--;)echo"$o[$y]
";

desglose para el segundo enfoque

function a($p,$r)
{
    global$o,$w,$y;
    $o[$y++].=                  // 3. add result to current line, increase line counter
        str_pad(                // 2. pad ...
        str_pad($r[0],2*$p,$r[1]).$r[2]     // 1. A + inner width(=2*$p-1) times B + C
        ,$w," ",2);             // ... to $w with blanks on both sides # 2==STR_PAD_BOTH
}

foreach(str_split($argv[1])as$i=>$c)
    for(
    $n=28,
    $w='.'!=$c                          // $w=total width
        ?1+2*$p=ceil(1/3*$n=31&ord($c)) // $n=storey count, $p=(inner width+1)/2
        :$p=4                           // $n=28, $p <= $w=4 for rubble
    ,
    $y=0;$y<36;)                        // $y=line counter
        if($n>26&&!$y)
            $o[$n=$y++].="/\\/\\";      // bottom line=rubble, $n=0
        elseif($n-->0)
        {
            a($p,$y?"| |":"|_|");       // add storey
            if($n%3<1)a($p--,"/ \\");   // add widening layer/roof
            if(!$n)a(1," _");           // add roof top
        }
        else
            a(0,"");                    // idk why str_pad doesn´t yield a warning here

for($y=36;$y--;)if($s=rtrim($o[$y]))echo"$s\n"; // output

+16 bytes si no se permiten nuevas líneas iniciales:
Reemplace echo"$o[$y]\n;con if($s=rtrim($o[$y]))echo"$s\n";.

-3 bytes para cualquiera de los ;<=>?[\]^_{|}~escombros: Reemplace 1) ($n=31&ord($c))con $n, 2) $n=28,$w='.'!=$ccon ($n=31&ord($c))<27y 3) 4con ($n=28)/7.

Otro -8 para >, ^o ~como escombros: Deshacer 3)

Titus
fuente
1
if(!$n){$o[$y++].=str_pad(_,$w," ",2);}-2 Bytes para los corchetes
Jörg Hülsermann
y la salida se puede hacer 3 bytes más corto: for($y=36;$y--;)echo"$o[$y]\n";; pero tengo un nuevo enfoque que guarda otros 2 bytes.
Tito
1
php.net/manual/en/functions.anonymous.php para el segundo enfoque `function a ($ p, $ r) use ($ o, $ w, $ y) 'en lugar de global
Jörg Hülsermann
@ JörgHülsermann: usesolo funciona para funciones anónimas. ahorraría 2 bytes; pero tendría que almacenar esa función en una variable en $a=lugar de darle un nombre (+3 bytes) y agregar un $a cada una de las cuatro llamadas.
Tito
4

Pyth, 93 79 bytes

K"/\\"j_.tsm?hJxGdC_m.[hyNk\ +\_mj*hy/k4?nkJ\ \_?%k4"||"Kh=+J=Nh/J3[F*2|@d;Krz0

Pruébalo en línea. Banco de pruebas.

Explicación

Escondí esto por defecto ya que es demasiado largo.

PurkkaKoodari
fuente
4

Perl, 147146 bytes

Incluye +1 para -p

Ejecutar con entrada en STDIN, p. Ej.

citysky.pl <<< " abcdefgxyz."

citysky.pl:

#!/usr/bin/perl -p
s%.%@{[map chr~-ord(lc$&)*4/3-4*(abs||-9),-9..9]}%g;y/M\xa248
A|-\xc6\0-\xff/MA||
A}-\xc6A/d,$a=(lc$a).$_ for($_)x36;*_=a;s/\x9f.*?\K\x9f/\xa3/g;y%A\xc6\x9f-\xa3\x0b-\xff%__/|||\\ %

Funciona como se muestra, pero reemplaza los \xhhescapes por su valor literal para obtener la puntuación reclamada. Puede hacerlo usando esta línea de comando:

perl -0pi -e 's/\\x(..)/chr hex $1/eg;s/\n$//' citysky.pl

Realmente no he explorado ningún otro enfoque, por lo que esto puede ser muy fácil de superar ...

Ton Hospel
fuente
2

Haskell, 289 bytes

c?l=c++l++c
c%s=("|"?(drop 2(r s)>>c)):s
g 46=["/\\"?""]
g 32=["  "]
g x="_"%h(mod x 32)
h 1=["/ \\"," _ "]
h x=(" "%h(x-1))!x
v!x|mod x 3/=1=v|z<-'/':r v++"\\"=z:map(" "?)v
r v=v!!0>>" "
f t|l<-map(g.fromEnum)t,m<-maximum(map length l)-1=unlines[l>>= \x->(x++cycle[r x])!!i|i<-[m,m-1..0]]
Damien
fuente
2

Rubí, 245

->s{a=['']*36
w=' '
s.chars{|c|a[u=0]+=c<?!?w*2:c<?/?"/\\"*2:(h=c.upcase.ord-64
1.upto(1+h+=(h-1)/3){|t|u=[u,l=1+2*((f=h-t)/4)].max
a[t]+=w*(a[0].size-a[t].size)+(f<-1?w:f<0??_:(f%4<1?[?/,?\\]:[?|]*2)*(w*l)).center(u+2)}
"|#{?_*u}|")}
a.reverse}

Usted permite tantas líneas nuevas adicionales como desee, así que me estoy tomando la libertad con eso. Aparte de eso, el proceso es el siguiente:

  1. Inicializar una matriz de salida a.
  2. Para cada char:
    1. si es '', agregue  aa[0]
    2. si es '.', agregue /\/\aa[0]
    3. de otra manera:
      1. calcular la altura ( c.upcase.ord + (c.upcase.ord-1)/3)
      2. para cada fila en a:
        1. rellena la fila con espacios en blanco. a[t]+=w*(a[0].size-a[t].size)
        2. si somos uno arriba h, centre un_
        3. de lo contrario, si estamos por encima de la altura, centre un 
        4. de lo contrario, si estamos por debajo de la altura, el centro | |o / \del ancho adecuado ( 1+2*((h-t)/4), dependiendo de sih-t%4==0
        5. agregar "|___|"del ancho correcto aa[0]
  3. regreso a.reverse

Apuesto a que puedo hacerlo más pequeño si hago cálculos matemáticos para evitar reverse

No que Charles
fuente
2

PHP, 297 bytes

foreach(str_split($argv[1])as$c)for($j=0,$h=ord($c)-64,$g=$h+$f=ceil($h/3),$w=$v=$h<0?$h<-18?2:4:2*$f+1;$j<36;$j++,$g--,$v-=$h>0&&$v>1?($g%4||!$j)?0*$n="|$s|":2+0*$n="/$s\\":$v+0*$n=['','_','',0,'/\/\\'][$v],$o[$j].=str_pad($n,$w,' ',2))$s=str_repeat($j?' ':'_',$v-2);krsort($o);echo join($o,'
');

Una versión más legible:

foreach (str_split($argv[1]) as $character) {
    for (
        $line = 0,
        $buildingHeight = ord($character) - 64,
        $floorsLeft = $buildingHeight + $supportFloors = ceil($buildingHeight / 3),
        $buildingWidth = $widthOnThisFloor = $buildingHeight < 0
            ? $buildingHeight < -18
                ? 2
                : 4
            : 2 * $supportFloors + 1;

        $line < 36;

        // The body of the for-loop is executed between these statements

        $line++,
        $floorsLeft--,
        $widthOnThisFloor -= $buildingHeight > 0 && $widthOnThisFloor > 1
            ? ($floorsLeft % 4 || !$line)
                ? 0 * $floorString = "|$middleSpacing|"
                : 2 + 0 * $floorString = "/$middleSpacing\\"
            : $widthOnThisFloor + 0 * $floorString = ['', '_', '', 0, '/\/\\'][$widthOnThisFloor],
        $outputArray[$line] .= str_pad($floorString, $buildingWidth, ' ', 2)
    ) {
        $middleSpacing = str_repeat($line ? ' ' : '_', $widthOnThisFloor - 2);
    }
}
krsort($outputArray);
echo join($outputArray, '
');
chocochaos
fuente