Palavras -> Skyline da cidade


40

O desafio

Seu programa ou função aceitará uma entrada de sequência única de STDIN ou um parâmetro de função. Você pode assumir que a entrada conterá apenas caracteres alfabéticos (a-zA-Z), espaços e pontos finais. A entrada não diferencia maiúsculas de minúsculas, portanto, você deve tratar 'a' exatamente da mesma forma que trataria 'A'.

Para cada caractere na sequência, você produzirá uma representação de um edifício conforme a seguinte especificação.

Cada edifício deve ter um telhado, designado por um sublinhado na linha superior, depois uma barra, espaço, barra invertida na segunda linha.

 _
/ \

Você terá um número de andares, correspondendo ao número da letra (a = 1, b = 2, c = 3 etc.) representados por uma parede (|) em cada lado e um espaço no meio. O piso inferior (e somente o piso inferior) deve ter uma base, que é um sublinhado entre as paredes. Como isso...

|_|

Por exemplo, 'b' ficaria assim

 _
/ \
| |
|_|

Agora, sabemos que prédios muito altos e estreitos não podem suportar e devem ficar mais largos na base; portanto, nenhum edifício pode ter mais de três andares sem suporte adicional. Portanto, a cada três níveis (não menos), você deve adicionar uma 'camada de ampliação'. A camada de alargamento consiste em uma barra e uma barra invertida diretamente acima das paredes da seção abaixo dela, e a seção abaixo deve ter dois espaços mais largos que a seção acima. A camada extra não conta para a altura do edifício.

Os edifícios não devem se sobrepor, mas não devem ter espaços desnecessários entre eles, e o chão é sempre plano, portanto todos os edifícios devem ter sua base no mesmo nível.

Por exemplo, 'abcdefga' ficará assim.

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

Os espaços na entrada da string devem ser representados por um espaço duplo.

Paradas completas na entrada de string devem ser representadas por entulhos como este.

/\/\

Outros exemplos

Input = Hello world.

Saída =

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

Input = lorem ipsum

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

Input = a.a.a.x.x.x.a.a.a

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

Regras

  • Claro que isso é código de golfe, a menor pontuação em bytes ganha
  • Aplicam-se regras de brecha padrão
  • Qualquer número de linhas em branco adicionais antes ou depois da saída é permitido
  • Você pode optar por gerar o resultado inteiro em uma sequência ou oferecer a saída como uma matriz em que cada elemento representa uma linha de saída ou enviar para STDOUT

Nota

Este é o meu primeiro post no PPCG, então, vá com calma comigo. Já passou pela caixa de areia. Quaisquer pontos negativos ou possíveis melhorias, por favor poste como comentário e farei o que puder


7
Convertendo [a,z]e [A,Z]to [1,26]parece um requisito inútil. Seria muito melhor usar apenas uma lista de números inteiros como entrada ( 0sendo a entrada para entulho). Além disso, postar seu desafio depois que ele estiver na Sandbox por apenas 21 horas , sem esperar para receber votos ou feedback de mais de um usuário, não conta como se tivesse "passado pela sandbox". É recomendável deixar os desafios no Sandbox por 48 a 72 horas, no mínimo, para dar às pessoas tempo suficiente para analisá-los.
Mego

2
Me lembra isso . Bom primeiro desafio, mas eu sugiro que você considere mudar [a,z], [1.26]partes do Mego mencionado. Tê-lo opcional é muitas vezes a melhor (a menos que seja uma parte fundamental do desafio (não é aqui).
Stewie Griffin

2
Eu direi, este é um primeiro desafio muito bom. Bem vindo ao site!
DJMcMayhem

11
Eu posso entender o ponto sobre o mapeamento az para números inteiros. Fazia sentido na primeira iteração do desafio, mas desde a edição por questões de clareza e brevidade (houve uma história de fundo que removi) as cartas não são mais relevantes. Vou editar apropriadamente o mais rapidamente possível
Darren H

11
Eu prefiro az, espaço, ponto final, pessoalmente.
Isaacg

Respostas:


10

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

Constrói a arte ASCII de forma recursiva, começando com o piso inferior e aplicando várias expressões regulares entre cada estágio:

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

Como funciona

1) Piso inferior

Começamos traduzindo a string de entrada em um piso inferior, como:

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

Onde:

  • y é um alias mais curto para a barra invertida (que requer escape)
  • O dígito ( 0, 1ou 2) logo antes de uma sequência de _é a parede esquerda do edifício. Representa o número de paredes que devem ser colocadas acima dela antes da próxima 'camada de alargamento'.
  • O dígito após uma sequência de _é a parede direita do edifício e está sempre definido como 0.

2) Expressões regulares aplicadas entre cada estágio

O processo recursivo consiste em aplicar 9 substituições no andar anterior, usando as seguintes expressões regulares:

  1. /\/y/g=> " "(remover os escombros)
  2. /_/g=> "x"(substitua a fundação ou a parte superior do edifício por um bloco sólido)
  3. /\/xy/g=> " _ "(substitua a última camada de alargamento pela parte superior do edifício)
  4. /1/g=> "3"(substitua temporariamente 1por 3- veja a última etapa)
  5. /2/g=> "1"(substitua 2por 1)
  6. /\/xx(x+)y/g=> " 2$10 "(substitua uma camada ampliada por uma nova parede mais estreita)
  7. /0(x+)0/g=> "/$1y"(substitua a parte superior da parede por uma camada maior)
  8. /3/g=> "0"(substitua 3por 0)

Por exemplo, aqui estão as transformações sucessivas de 2___0(piso inferior gerado 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 : O topo do edifício é então substituído por a x. Isso não é mostrado no diagrama acima.

3) Expressões regulares aplicadas ao resultado final

A recursão para quando não há mais nada a substituir, o que significa que estamos além do topo do edifício mais alto.

Agora precisamos limpar tudo com mais algumas expressões regulares:

  1. /\d/g=> "|"(substituir dígitos por tubos)
  2. /x/g=> " "(substituir blocos sólidos por espaços)
  3. /y/g=> "\"(substitua ypor barras invertidas)

Por exemplo:

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

Demo

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

Contribuintes:
4 bytes salvos graças a Hedi
8 bytes salvos graças a Not that Charles


Qualquer pessoa que queira ter uma entrada como um inteiro é bem-vindo, mas eu sugiro que tal entrada deve ser não concorrentes
mbomb007

@ mbomb007 - Isso foi corrigido. Minhas otimizações atuais não compensam o custo dos infames .charCodeAt(), no entanto.
Arnauld

Você não precisa new emnew RegExp(e,'g')
Hedi

Eu gosto muito dessa abordagem. Algumas idéias que podem ajudar: 1. use um caractere assim ynão requer escapamento para a barra. 2. Se você usar _para o piso térreo, você ainda pode diferenciar o topo com o regex: /_ /.
Não que Charles

11
@NotthatCharles - Na verdade, eu nunca notei a regra do "espaço duplo". ;) Isso está corrigido.
Arnauld 23/09

7

PHP, 386 376 367 364 362 358 356 bytes

Primeira abordagem; ainda pode ser jogável.

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

abordagem semelhante com uma subfunção:

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

repartição para a segunda abordagem

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, se novas linhas iniciais não forem permitidas:
Substitua echo"$o[$y]\n;por if($s=rtrim($o[$y]))echo"$s\n";.

-3 bytes para qualquer um dos ;<=>?[\]^_{|}~escombros: Substitua 1) ($n=31&ord($c))por $n, 2) $n=28,$w='.'!=$cpor ($n=31&ord($c))<27e 3) 4por ($n=28)/7.

Outro -8 para >, ^ou ~como entulho: Desfazer 3)


11
if(!$n){$o[$y++].=str_pad(_,$w," ",2);}-2 bytes para os colchetes
Jörg Hülsermann 19/09/16

e de saída pode ser feito mais curto 3 bytes: for($y=36;$y--;)echo"$o[$y]\n";; mas eu tenho uma nova abordagem que salva outros 2 bytes.
Titus

11
php.net/manual/en/functions.anonymous.php para a segunda abordagem `function a ($ p, $ r) use ($ o, $ w, $ y) 'em vez de global
Jörg Hülsermann

@ JörgHülsermann: usesó funciona para funções anônimas. economizaria 2 bytes; mas eu precisaria armazenar essa função em uma variável em $a=vez de dar um nome (+3 bytes) e adicionar a $a cada uma das quatro chamadas.
Titus

4

Pitão, 93 79 bytes

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

Experimente online. Suíte de teste.

Explicação

Eu escondi isso por padrão, já que é muito longo.


4

Perl, 147 146 bytes

Inclui +1 para -p

Execute com entrada no STDIN, por exemplo

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 mostrado, mas substitua os \xhhescapes pelo valor literal para obter a pontuação reivindicada. Você pode fazer isso usando esta linha de comando:

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

Eu realmente não explorei outras abordagens, então isso pode ser muito superável ...


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

2

Ruby, 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}

Você permite quantas novas linhas extras quiser, então estou tendo liberdade com isso. Além disso, o processo é o seguinte:

  1. Inicialize uma matriz de saída a.
  2. Para cada caractere:
    1. se é '', adicione  aa[0]
    2. se for '.', adicione /\/\aa[0]
    3. de outra forma:
      1. calcular a altura ( c.upcase.ord + (c.upcase.ord-1)/3)
      2. para cada linha em a:
        1. preencha a linha com espaço em branco. a[t]+=w*(a[0].size-a[t].size)
        2. se formos um acima h, centralize um_
        3. caso contrário, se estamos acima da altura, centralize um 
        4. caso contrário, se estamos abaixo da altura, do centro | |ou / \da largura adequada ( 1+2*((h-t)/4), dependendo seh-t%4==0
        5. adicionar "|___|"da largura certa paraa[0]
  3. Retorna a.reverse

Aposto que posso diminuí-lo se eu resolver as contas para evitar reverse


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,'
');

Uma versão mais legível:

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, '
');
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.