Ayuda a los arquitectos a visualizar el horizonte


29

Como parte de un proyecto de planificación de la ciudad, se le asignó la tarea de crear un programa o función que muestre el horizonte de la ciudad, dado algunos aportes de los arquitectos. El proyecto solo está en la fase de inicio, por lo que un boceto muy aproximado es suficiente. El enfoque más fácil es, por supuesto, simplemente dibujar el horizonte en el arte ASCII.

Todos los edificios estarán junto al río, por lo tanto, todos están alineados. Los arquitectos darán la altura de cada edificio como entrada, y su código debe mostrar el horizonte.

La aportación de los arquitectos será un número entero o medio entero. Si el número es un entero, el edificio tendrá un techo plano, mientras que un medio entero dará como resultado un techo inclinado. Un cero solo será terreno plano. Las paredes de un edificio están separadas por 3 caracteres, mientras que un cero será de un solo carácter de ancho. Los edificios adyacentes comparten paredes.

Para obtener detalles y aclaraciones sobre la salida, consulte los ejemplos a continuación:

N = 3
 ___
|   |
|   |
|___|

N = 3.5
  _      
 / \
|   |
|   |
|___|

N = 6
 ___
|   |
|   |
|   |
|   |
|   |
|___|

n = 0
_

Entrada de ejemplo: 3 3.5 0 2

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

Entrada de ejemplo: 0 0 2.5 3 0 4 1

             ___
    _  ___  |   |
   / \|   | |   |
  |   |   | |   |___
__|___|___|_|___|___|

Louisville ,0 2 1 3.5 0 4 2 4 2 4 6 1 6 0 5 1

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

Los caracteres ASCII utilizados son: nueva línea, espacio y /\_|(puntos de código 10, 32, 47, 92, 95, 124).

Reglas:

  • Es opcional hacer un programa que solo tome enteros como entrada, multiplicando todos los números por dos. Entonces, en lugar de tomar 3 3.5 2, su programa puede tomar 6 7 4. Si se elige el segundo formato de entrada, una entrada de 6 debería resultar en un edificio de 3 pisos, 7 debería ser un edificio de 3 pisos con techos inclinados, etc.
  • El resultado debe ser exactamente como se describe anteriormente, pero los espacios finales y las nuevas líneas están bien.
  • El formato exacto de la entrada es opcional. Lo que sea mejor en tu idioma.
  • El resultado debe mostrarse en la pantalla, para que los arquitectos puedan verlo.
  • Puede suponer que habrá al menos un número entero dado, y que solo se proporcionará una entrada válida.

Este es codegolf, por lo que gana el código más corto en bytes.


1
¿Cómo sería un edificio de altura 0.5?
Tom Carpenter

No lo he pensado realmente. La opción más obvia sería un techo inclinado, casi como un hobbit :-) pero eres libre de elegir, o puedes asumir que la entrada nunca será 0.5 ...
Stewie Griffin

1
En este momento suceden cosas extrañas, ya que no hay paredes (supuse que no existía 0.5 alto), así que tendré que trabajar un poco en mi respuesta.
Tom Carpenter

Acabo de probar su código con una altura de 0.5, y estoy de acuerdo, "extraño" es una palabra muy descriptiva = PI no lo ha explicado en detalle, así que no estoy seguro de lo que está pasando ... De todos modos, su respuesta es perfectamente válido, puede suponer que no hay 0.5 edificios ...
Stewie Griffin

Respuestas:


5

Python 2, 199 193 188 185 bytes

a=map(int,raw_input().split())
l=max(a)+1|1
while~l:print''.join((x%2*'/  _\\ '[x<l::2]*(x<=l<x+4)or'_ '[x|1!=l>1]*3)[x<1:x+2]+'| '[x<=l>=y]*(x+y>0)for x,y in zip([0]+a,a+[0]))[1:];l-=2

Este es un programa completo que acepta enteros como entrada. Ejemplo de entrada .


¡maravilloso! Tengo que robar algunos de estos trucos para futuros campos de golf ...
quintopia

5

MATLAB, 219209203 bytes

i=input('');x=1;c=0;m(1:4*numel(i))='_';for a=i;b=fix(a);m(1:b,x)='|';s=95;if a~=b;m(b+2,x+2)=95;s='/ \';end;m(b+1,x+(1:3))=s;x=x+(a>0)*3+1;m(1:b,x)='|';x=x+(a<1&c>0);c=a;end;disp(flipud(m(:,1:x-(a<1))))

Esto desafortunadamente no funciona en Octave . No estoy completamente seguro de por qué, parece tener algo que ver con el bit disp / flipud que se rompe.

Además, actualmente no hay una definición de cómo se ve un edificio de 0.5 de altura, ni ninguna mención de ellos, por lo que en este código supongo que están prohibidos.

El siguiente es el código de una manera un poco más legible:

i=input(''); %e.g. [0 0 2 1 3.5 0 4 2 4 2 4 6 1 6 0 5 1 0 0 1 0]
x=1;
c=0;
m(1:4*numel(i))='_';
for a=i;
    b=fix(a);
    m(1:b,x)='|';
    s=95;
    if a~=b;
        m(b+2,x+2)=95;
        s='/ \';
    end;
    m(b+1,x+(1:3))=s;
    x=x+(a>0)*3+1;
    m(1:b,x)='|';
    x=x+(a<1&c>0);
    c=a;
end;
disp(flipud(m(:,1:x-(a<1))))

Primero tomamos una entrada como una matriz y hacemos algunas inicializaciones variables.

i=input(''); %e.g. [0 0 2 1 3.5 0 4 2 4 2 4 6 1 6 0 5 1]
x=1;
c=0;

Debido a que los edificios de altura cero son una molestia: básicamente terminan con un ancho que depende de lo que están al lado (aunque lo que está impreso no cambia), simplificamos las cosas al dibujar suficiente terreno para todos los edificios. Suponemos que cada edificio tendrá 4 caracteres de ancho (porque los edificios adyacentes se fusionan): los de altura cero no lo son, pero el exceso se recortará más adelante.

m(1:4*numel(i))='_';

Ahora sacamos cada edificio a su vez.

for a=i

Primero obtenemos la parte entera de la altura, ya que esto determinará cuántos '|' necesitamos.

    b=fix(a);

Ahora dibuje en el muro de este edificio: si hay dos edificios adyacentes, el muro de este nuevo estará en la misma columna que el muro del último.

    m(1:b,x)='|';

Verifique si se trata de un edificio de media altura. Si es así, entonces el techo será diferente. Para las medias alturas, el techo será / \mientras que las de altura completa serán ___(Matlab replicará esto implícitamente desde un guión bajo, así que guarde un par de bytes allí). Hay un poco más de techo una fila más arriba para los edificios de media altura, por lo que también se agrega.

    s=95;
    if a~=b;
        m(b+2,x+2)=95;
        s='/ \';
    end;

Dibujar en el techo

    m(b+1,x+(1:3))=s;

Ahora vaya al inicio del próximo edificio y dibuje en el muro compartido (si el muro es demasiado corto en este punto, se agrandará cuando se dibuje el siguiente edificio). Tenga en cuenta que los edificios de altura cero son de 1 ancho, los edificios normales tienen 4 de ancho, por lo que simplificamos lo que de otro modo sería un if-else tratando (a> 0) como un número decimal y no un booleano.

    x=x+(a>0)*3+1;
    m(1:b,x)='|';

Luego viene un poco de piratería informática para trabajar con edificios de altura cero. Básicamente, lo que dice esto es que si este edificio era de altura cero, y el anterior no era así, significa que el lugar del próximo edificio necesita incrementarse en 1 porque un edificio de altura cero intercalado entre otros dos edificios es efectivamente dos veces más ancho. representa el muro adicional que normalmente se comparte con un edificio adyacente. También hacemos un seguimiento de esta altura del edificio para hacer esta verificación la próxima vez.

    x=x+(a<1&c>0);
    c=a;
end;

Una vez hecho esto, voltea la matriz de construcción para que esté en la posición correcta y muéstrala. Tenga en cuenta que aquí también recortamos cualquier exceso de terreno.

disp(flipud(m(:,1:x-(a<1))))

Entonces, cuando ejecutamos este script, se nos pide nuestra entrada, por ejemplo:

[0 0 2 1 3.5 0 4 2 4 2 4 6 1 6 0 5 1 0 0 1 0]

Luego genera el edificio y muestra el resultado. Para la entrada anterior, se genera lo siguiente:

                                     ___     ___                   
                                    |   |   |   |  ___             
            _    ___     ___     ___|   |   |   | |   |            
           / \  |   |   |   |   |   |   |   |   | |   |            
   ___    |   | |   |___|   |___|   |   |   |   | |   |            
  |   |___|   | |   |   |   |   |   |   |___|   | |   |___    ___  
__|___|___|___|_|___|___|___|___|___|___|___|___|_|___|___|__|___|_

¡Muy bien hecho!
Stewie Griffin

4

Kotlin, 447 442 bytes

val a={s:String->val f=s.split(" ").map{it.toFloat()}.toFloatArray();val m=(f.max()!!+1).toInt();for(d in m downTo 0){var l=0f;for(c in f){val h=c.toInt();print(if(h==d&&d!=0)if(h<l-0.5)"|" else{" "}+if(c>h)"/ \\" else "___" else if(h<d)if(d<l-0.5)"|" else{" "}+if(h==0)" " else if((c+0.5).toInt()==d)" _ " else "   " else{if(h==0)if(l<1)"  " else "| " else "|   "}.replace(' ',if(d==0)'_' else ' '));l=c;};if(d<l-0.5)print("|");println();}}

Versión sin golf:

val ungolfed: (String) -> Unit = {
    s ->

    val floats = s.split(" ").map { it.toFloat() }.toFloatArray()
    val maxH = (floats.max()!! + 1).toInt()

    for (drawHeight in maxH downTo 0) {
        var lastBuildingH = 0f
        for (f in floats) {
            val buildingH = f.toInt()
            if (drawHeight == 0) {
                // Baseline
                if (buildingH == 0)
                    if (lastBuildingH.toInt() == 0) print("__")
                    else print("|_")
                else print("|___")
            } else if (buildingH == drawHeight) {
                // Ceiling
                if (buildingH < lastBuildingH - 0.5) print("|")
                else print(" ")
                if (f > buildingH) print("/ \\")
                else print("___")
            } else if (buildingH < drawHeight) {
                // Above building
                if (drawHeight < lastBuildingH - 0.5) print("|")
                else print(" ")
                if (buildingH == 0) print(" ")
                else {
                    if ((f + 0.5).toInt() == drawHeight) print(" _ ")
                    else print("   ")
                }
            } else {
                if (buildingH == 0) print("| ")
                else print("|   ")
            }
            lastBuildingH = f;
        }
        if (drawHeight < lastBuildingH - 0.5) print("|")
        println()
    }
}

3

Python 2, 357 306 299 294 287 281 276 bytes

def s(l):
 d=len(l)+1;l=[0]+l+[0];h=(max(l)+3)/2;o=''
 for i in range(d*h):
  a=l[i%d+1];c=l[i%d];b=2*(h-1-i/d);o+="|"if(a>b+1)+(c>b+1)else" "*(a+c>0);o+=" _/__  _\\"[a-b+1::3]if b*(1>=abs(a-b))else" "*(1+2*(a>0))
  if b==0:o=o.replace(" ","_")
  if i%d==d-1:print o[:-1];o=''

Esto utiliza la codificación "duplicada", que se pasa a la función como una lista. Editar: bytes afeitados rehaciendo parte del gran condicional como un selector de matriz y cambiando a la codificación duplicada. Afeitó más bytes reorganizando aún más el condicional y convirtiendo más lógica a aritmética.

EDITAR: xsot es mejor

Explicación:

d=len(l)+1;l=[0]+l+[0];m=max(l);h=m/2+m%2+1;o=''

des 1 más que la longitud de la matriz, porque vamos a agregar ceros en cada extremo de la lista desde el segundo elemento hasta el cero que agregamos al final. hes la altura del dibujo. (Tenemos que dividir por 2 en este cálculo porque estamos usando la representación duplicada, que usamos específicamente para evitar tener que lanzar flotadores a las entradas por todo el lugar. También agregamos 1 antes de dividir alturas tan extrañas - edificios puntiagudos-- obtener un poco más de espacio libre que el tipo normal.) oes la cadena de salida.

 for i in range(d*h):

Un truco estándar para contraer un doble bucle for en un solo bucle for. Una vez que lo hagamos:

  a=l[i%d+1];c=l[i%d];b=2*(h-1-i/d)

ahora hemos logrado lo mismo que:

for b in range(2*h-2,-2,-2):
 for j in range(d):
  a=l[j+1];c=l[j]

pero de una manera que nos proporciona diez bytes guardados (incluido el espacio en blanco en las siguientes líneas).

  o+="|"if(a>b+1)+(c>b+1)else" "*(a+c>0)

Pegue una pared en cualquier momento en que la altura del edificio actual o del edificio anterior sea más alta que la línea actual, siempre que haya al menos un límite de edificio aquí. Es el equivalente del siguiente condicional:

  o+=("|" if a>b+1 or c>b+1 else " ") if a or c else ""

donde b es la altura de exploración actual, a es la altura actual del edificio y c es la altura anterior del edificio. La última parte del condicional evita poner muros entre los espacios del suelo.

  o+=" _/__  _\\"[a-b+1::3]if b*(1>=abs(a-b))else" "*(1+2*(a>0))

Esta es la parte que dibuja el techo correcto, seleccionando las partes del techo comparando la altura del edificio con la altura de escaneo actual. Si un techo no va aquí, imprime un número apropiado de espacios (3 cuando es un edificio real, por ejemplo, a> 0, de lo contrario 1). Tenga en cuenta que cuando estamos a nivel del suelo, nunca intenta dibujar un techo, lo que significa que los edificios de tamaño 0.5 no tienen techos puntiagudos. Oh bien.

  if b==0:o=o.replace(" ","_")

Cuando estamos a nivel del suelo, queremos guiones bajos en lugar de espacios. Simplemente los reemplazamos todos a la vez aquí.

  if i%d==d-1:print o[:-1];o=''

Justo antes de comenzar a procesar la siguiente línea, imprima la actual y borre la línea de salida. Cortamos el último carácter porque es la "_" correspondiente al espacio de tierra que agregamos agregando un cero al comienzo de la función. (Agregamos ese cero para que no tengamos que agregar un caso especial para insertar una pared derecha, si existe, que agregaría mucho más código del que agregamos agregando el 0 y cortando el "_".)


Auto-golf. Guau. (Además, +1)
aplaude el

2

Python 3

725 bytes

608 bytes

Código de golf:

import sys,math;
m,l,w,s,bh,ls,ins,r,a="|   |","___","|"," ",0,[],[],range,sys.argv[1:]
def ru(n):return math.ceil(n)
def bl(h,n):
    if(n>ru(h)):return(s*5,s)[h==0]
    if(h==0):return"_"
    if(n==0):return w+l+w
    if(n<h-1):return m
    return("  _  "," / \ ")[n==ru(h)-1]if(h%1)else(s+l+s,m)[n==h-1]
for arg in a:
    f=ru(float(arg))
    if(bh<f):bh=f
for i in r(bh,-1,-1):
    ln=""
    for bld in a:ln+=bl(float(bld),i)
    ls.append(ln)
for i in r(len(ls[-1])-1):
    if(ls[-1][i]==ls[-1][i+1]==w):ins.append(i-len(ins))
for ln in ls:
    for i in ins:ln=(ln[:i]+ln[i+1:],ln[:i+1]+ln[i+2:])[ln[i]==w]
    print(ln)

Aquí está el código sin golf. Hay algunos comentarios, pero la idea básica es crear edificios con paredes dobles, de modo que el resultado final sea el siguiente:

_|___||___|_|___||___|

Luego, para obtener índices de esas paredes dobles y eliminar esas columnas, obtenemos:

_|___|___|_|___|___|

Código:

import sys
import numbers
import math

mid="|   |";
l="___";
w="|";
s=" ";

def printList(lst):
    for it in lst:
        print(it);

# h = height of building
# l = line numeber starting at 0
def buildingline(h,n):
    #if (h==0):
    #   return " " if(n>math.ceil(h)) else "   ";
    if(n>math.ceil(h)):
        return s if(h == 0) else s*5;
    if(h==0): return "_";
    if(n==0): return w+l+w;
    if(n<h-1): return mid;
    if(h.is_integer()):
        return mid if(n==h-1) else  s+l+s;
    else:
        return " / \ " if (n==math.ceil(h)-1) else "  _  "; 
# max height
bh=0;

for arg in sys.argv[1:]:
    f = math.ceil(float(arg));
    if(bh<f):bh=f;

# lines for printing
lines = []

for i in range(bh,-1,-1):
    line="";
    for bld in sys.argv[1:]:
        bld=float(bld);
        line += buildingline(bld,i);
        #lh = bld;
    lines.append(line);

#for line in lines:
#   print(line);
#printList(lines);


# column merging
#find indexes for merging (if there are | | next to each other)
indexes = [];
for i in range(len(lines[-1])-1):
    if (lines[-1][i]=='|' and lines[-1][i+1] == '|'):
        indexes.append(i-len(indexes));

#printList(indexes);

#index counter
for line in lines:
    newLine = line;
    for i in indexes:
        if newLine[i] == '|' :
            newLine=newLine[:i+1] + newLine[i+2:];
        else : newLine = newLine[:i] + newLine[i+1:];
    print(newLine);

¡Es hora de jugar al golf!


Es posible que desee echar un vistazo aquí . Creo que hay mucho potencial de golf aquí =) Solo conozco Python básico, así que no puedo sugerir nada específico, me temo ...
Stewie Griffin

Me parece que eliminó los espacios y acortó los nombres de las variables, pero mantuvo el resto sin cambios. Debería intentar encontrar formas inteligentes de, por ejemplo, deshacerse de algunos bucles, usar menos comparaciones, etc. Por supuesto, cosas ru(n):return math.ceil(n)como el golf, pero aún así ... Por favor, no tome esto de manera negativa, no soy un buen golfista, y seguro que no un buen programador. Te sugiero que trates de mejorarlo un poco ... Es realmente divertido una vez que te das cuenta de que logras acortarlo. Pasé de muchos muchos a 120 a 55 hace unos días. Entonces es posible incluso si eres nuevo en eso.
Stewie Griffin

@StewieGriffin ¡Gracias por ese enlace! Realmente soy un novato en el código de golf, así que se trata más de completar la tarea real que de hacer código de golf por mí. Pero es sorprendente descubrir las posibilidades de varios idiomas
Cajova_Houba

FTR: Para algunos de los desafíos más complejos, como este, me encantaría terminarlo yo mismo =)
Stewie Griffin

2

PHP, 307 297 293 bytes

<?$r=str_pad("",$p=((max($argv)+1)>>1)*$w=4*$argc,str_pad("\n",$w," ",0));for(;++$i<$argc&&$r[$p++]=_;$m=$n)if($n=$argv[$i]){$q=$p+=!$m;eval($x='$r[$q-1]=$r[$q]=$r[$q+1]=_;');for($h=$n>>1;$h--;$q-=$w)$r[$q-2]=$r[$q+2]="|";$n&1?($r[$q-1]="/")&($r[$q-$w]=_)&$r[$q+1]="\\":eval($x);$p+=3;}echo$r;

Toma argumentos * 2 de la línea de comando. guardar en archivo, ejecutar con php <filename> <parameters>.

Descompostura

// initialize result    
$r=str_pad("",              // nested str_pad is 3 bytes shorter than a loop
    $p=                     // cursor=(max height-1)*(max width)=(start of last line)
    ((max($argv)+1)>>1)     // max height-1
    *
    $w=4*$argc              // we need at least 4*($argc-1)-1, +1 for newline
    ,
    // one line
    str_pad("\n",$w," ",0)  // (`str_pad("",$w-1)."\n"` is one byte shorter,
);                          // but requires `$w+1`)

// draw skyline
for(;
    ++$i<$argc              // loop through arguments
    &&$r[$p++]=_                // 0. draw empty ground and go one forward
    ;
    $m=$n                       // 7. remember value
)
    if($n=$argv[$i])            // if there is a house
    {
        $q=                         // 2. copy $p to $q
        $p+=!$m;                    // 1. go one forward if there was no house before this
        // offset all further positions by -2 (overwrite empty ground, share walls)
        eval($x=                    // 3. draw floor
        '$r[$q-1]=$r[$q]=$r[$q+1]=_;'
        );
        for($h=$n>>1;$h--;$q-=$w)   // 4. draw walls
            $r[$q-2]=$r[$q+2]="|";
        $n&1                        // 5. draw roof
            ?($r[$q-1]="/")&($r[$q-$w]=_)&$r[$q+1]="\\"
            :eval($x)               // (eval saved 7 bytes)
        ;                           // (ternary saved 6 bytes over `if`)
        $p+=3;                      // 6. go three forward (5-2)
    }

// output
echo$r;

1

C ++, sin golf

(o tal vez no golfable)

Suponiendo que hay menos de 100 elementos y cada elemento es menor que 100. ses el número de edificios (requerido en la entrada).

#include <iostream>
using namespace std;
int main()
{
float a[100];
int i,j,s;
cin>>s;
for(i=0;i<s;++i)
 cin>>a[i];
for(i=100;i>=1;--i)
{
for(j=0;j<s;++j)
{
if((a[j]>=i)||(a[j-1]>=i))
 cout<<"|";
else
 cout<<" ";
if(i==1)
 cout<<"___";
else if(a[j]+1==i)
 cout<<"___";
else if(a[j]+1.5==i)
 cout<<" _ ";
else if(a[j]+0.5==i)
 cout<<"/ \\";
else cout<<"   ";
}
if(a[s-1]>=i)
 cout<<"|";
cout<<endl;
}
}

Hay algunos errores en la salida ... El terreno tiene 3 caracteres de ancho (solo debe ser 1) y falta el último muro.
Stewie Griffin

@StewieGriffin Todavía estaba resolviendo los errores cuando publiqué esto. 1. He agregado el último muro. 2. El terreno debe tener 3 caracteres de ancho, porque el techo inclinado / _ \ tiene 3 caracteres de ancho.
ghosts_in_the_code

1
* El suelo entre los edificios, no dentro.
Stewie Griffin

Si todavía está trabajando en ello, es posible que desee esperar, pero puede deshacerse de muchos bytes si elimina las nuevas líneas y la sangría. No he solucionado el problema de tierra, pero esto funciona .346 bytes en lugar de 401.
Stewie Griffin

@StewieGriffin En realidad no tengo la intención de enviar una respuesta de golf ya que de todos modos es demasiado tiempo. Puedo apostar a que existen mejores idiomas donde se hace en menos de 100 bytes. Entonces mi código es más una solución de referencia para otros.
ghosts_in_the_code
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.