Aidez les architectes à visualiser l'horizon

29

Dans le cadre d'un projet d'urbanisme, vous avez obtenu la tâche de créer un programme ou une fonction qui affichera les toits de la ville, compte tenu de la contribution des architectes. Le projet est seulement en phase de démarrage, donc un croquis très grossier est suffisant. L'approche la plus simple est bien sûr de simplement dessiner la ligne d'horizon en ASCII-art.

Tous les bâtiments seront au bord de la rivière, ils sont donc tous alignés. Les architectes donneront la hauteur de chaque bâtiment en entrée, et votre code devrait afficher l'horizon.

L'entrée des architectes sera soit un entier soit un demi-entier. Si le nombre est un entier, le bâtiment aura un toit plat, tandis qu'un demi-entier donnera un toit en pente. Un zéro sera juste un terrain plat. Les murs d'un bâtiment sont séparés par 3 caractères, tandis qu'un zéro sera large d'un seul caractère. Les bâtiments adjacents partagent des murs.

Pour plus de détails et des clarifications concernant la sortie, veuillez consulter les exemples ci-dessous:

N = 3
 ___
|   |
|   |
|___|

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

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

n = 0
_

Exemple d'entrée: 3 3.5 0 2

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

Exemple d'entrée: 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

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

Les caractères ASCII utilisés sont: nouvelle ligne, espace et /\_|(points de code 10, 32, 47, 92, 95, 124).

Règles:

  • Il est facultatif de créer un programme qui ne prend que des entiers en entrée, en multipliant tous les nombres par deux. Ainsi, au lieu de prendre 3 3.5 2, votre programme peut prendre 6 7 4. Si le deuxième format d'entrée est choisi, une entrée de 6 devrait se traduire par un bâtiment de 3 étages, 7 devrait être un bâtiment de 3 étages avec des toits en pente, etc.
  • La sortie doit être exactement comme décrit ci-dessus, mais les espaces de fin et les retours à la ligne sont OK.
  • Le format exact de l'entrée est facultatif. Tout ce qui est le mieux dans votre langue.
  • Le résultat doit être affiché à l'écran, afin que les architectes puissent le consulter.
  • Vous pouvez supposer qu'il y aura au moins un entier donné et que seule une entrée valide sera donnée.

C'est codegolf, donc le code le plus court en octets gagne.

Stewie Griffin
la source
1
À quoi ressemblerait un bâtiment de hauteur 0,5?
Tom Carpenter
Je n'y ai pas vraiment pensé. Le choix le plus évident serait juste un toit en pente, presque comme une maison de hobbit :-) mais vous êtes libre de choisir, ou vous pouvez supposer que l'entrée ne sera jamais de 0,5 ...
Stewie Griffin
1
Pour le moment, des choses étranges se produisent car il n'y a pas de murs (je supposais que 0,5 de haut n'existait pas), donc je vais devoir travailler un peu sur ma réponse.
Tom Carpenter
Je viens d'essayer votre code avec une hauteur de 0,5, et je suis d'accord, "bizarre" est un mot très descriptif = PI ne l'a pas parcouru en détail, donc je ne suis pas sûr de ce qui se passe ... Quoi qu'il en soit, votre réponse est parfaitement valide, vous pouvez supposer qu'il n'y a pas de 0,5 bâtiment ...
Stewie Griffin

Réponses:

5

Python 2, 199 193 193 188 185 octets

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

Il s'agit d'un programme complet qui accepte des entiers en entrée. Exemple d'entrée .

xsot
la source
merveilleux! je dois voler certaines de ces astuces pour les futurs golfs ...
quintopie
5

MATLAB, 219 209 203 octets

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

Cela ne fonctionne malheureusement pas sur Octave . Je ne sais pas vraiment pourquoi, semble être quelque chose à voir avec le bit disp / flipud qui se casse.

De plus, il n'y a actuellement aucune définition de ce à quoi ressemble un bâtiment de 0,5 hauteur, ni aucune mention d'eux, donc dans ce code, je suppose qu'ils sont interdits.

Ce qui suit est le code d'une manière légèrement plus lisible:

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

D'abord, nous prenons une entrée comme un tableau et faisons une initialisation variable.

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;

Parce que les bâtiments de hauteur zéro sont pénibles - ils se retrouvent essentiellement avec une largeur qui dépend de ce qu'ils sont à côté (bien que ce qui est imprimé ne change pas), nous simplifions les choses en dessinant suffisamment de terrain pour tous les bâtiments. Nous supposons que chaque bâtiment aura une largeur de 4 caractères (car les bâtiments adjacents fusionnent) - ceux de hauteur nulle ne le sont pas, mais l'excédent sera coupé plus tard.

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

Maintenant, nous dessinons tour à tour chaque bâtiment.

for a=i

Nous obtenons d'abord la partie entière de la hauteur, car cela déterminera le nombre de «|» nous avons besoin.

    b=fix(a);

Maintenant, dessinez le mur de ce bâtiment - s'il y a deux bâtiments adjacents, le mur de ce nouveau sera dans la même colonne que le mur du dernier.

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

Vérifiez s'il s'agit d'un bâtiment à mi-hauteur. Si c'est le cas, le toit sera différent. Pour les demi-hauteurs, le toit sera identique à celui de / \toute la hauteur ___(Matlab le reproduira implicitement à partir d'un seul trait de soulignement, économisez donc quelques octets). Il y a un peu plus de toit une rangée plus haut pour les bâtiments à mi-hauteur, ce qui est également ajouté.

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

Dessinez dans le toit

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

Déplacez-vous maintenant au début du bâtiment suivant et dessinez dans le mur partagé (si le mur est trop court à ce stade, il sera agrandi lorsque le bâtiment suivant sera dessiné). Notez que les bâtiments de hauteur nulle ont une largeur de 1, les bâtiments normaux ont une largeur de 4, nous simplifions donc ce qui serait autrement un if-else en traitant (a> 0) comme un nombre décimal et non comme un booléen.

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

Vient ensuite un peu de piratage pour travailler avec des bâtiments de hauteur nulle. Fondamentalement, ce que cela dit, c'est que si ce bâtiment était de hauteur zéro, et celui qui ne l'était pas auparavant, cela signifie que l'emplacement du bâtiment suivant doit être incrémenté de 1, car un bâtiment de hauteur zéro pris en sandwich entre deux autres bâtiments est effectivement deux fois plus large - ce représente le mur supplémentaire qui est normalement partagé avec un bâtiment adjacent. Nous gardons également une trace de cette hauteur de bâtiment pour effectuer cette vérification la prochaine fois.

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

Une fois cela fait, retournez la matrice de construction pour être dans le bon sens et affichez-la. Notez que nous supprimons également tout excédent de sol ici également.

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

Ainsi, lorsque nous exécutons ce script, on nous demande notre entrée, par exemple:

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

Il génère ensuite le bâtiment et affiche le résultat. Pour l'entrée ci-dessus, les éléments suivants sont générés:

                                     ___     ___                   
                                    |   |   |   |  ___             
            _    ___     ___     ___|   |   |   | |   |            
           / \  |   |   |   |   |   |   |   |   | |   |            
   ___    |   | |   |___|   |___|   |   |   |   | |   |            
  |   |___|   | |   |   |   |   |   |   |___|   | |   |___    ___  
__|___|___|___|_|___|___|___|___|___|___|___|___|_|___|___|__|___|_
Tom Carpenter
la source
Très bien fait!
Stewie Griffin,
4

Kotlin, 447 442 octets

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

Version non golfée:

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()
    }
}
succcubbus
la source
3

Python 2, 357 306 299 294 287 281 276 octets

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=''

Celui-ci utilise le codage "doublé", pour être transmis à la fonction sous forme de liste. Edit: octets rasés en refaisant une partie du grand conditionnel comme sélecteur de tableau et en passant au codage doublé. Réduit plus d'octets en réorganisant encore plus le conditionnel et en convertissant plus de logique en arithmétique.

EDIT: xsot est mieux

Explication:

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

dest 1 de plus que la longueur du tableau, car nous allons ajouter des zéros à chaque extrémité de la liste du deuxième élément jusqu'au zéro que nous avons ajouté à la fin. hest la hauteur du dessin. (Nous devons diviser par 2 dans ce calcul parce que nous utilisons la représentation doublée, que nous utilisons spécifiquement pour éviter d'avoir à lancer des flotteurs en pouces partout. Nous ajoutons également 1 avant de diviser les hauteurs si étranges - bâtiments pointus-- obtenir un peu plus de dégagement que le type régulier.) oest la chaîne de sortie.

 for i in range(d*h):

Une astuce standard pour réduire une boucle double en une boucle simple. Une fois que nous faisons:

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

nous avons maintenant accompli la même chose que:

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

mais d'une manière qui nous rapporte dix octets enregistrés (y compris les espaces sur les lignes suivantes).

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

Collez un mur à tout moment, la hauteur du bâtiment actuel ou du bâtiment précédent étant plus haute que la ligne actuelle, tant qu'il y a au moins une limite de bâtiment ici. C'est l'équivalent du conditionnel suivant:

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

où b est la hauteur de numérisation actuelle, a est la hauteur de bâtiment actuelle et c est la hauteur de bâtiment précédente. La dernière partie du conditionnel empêche de placer des murs entre les espaces au sol.

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

Il s'agit de la partie qui dessine le toit approprié, en sélectionnant les parties du toit en comparant la hauteur du bâtiment à la hauteur de numérisation actuelle. Si un toit ne va pas ici, il imprime un nombre approprié d'espaces (3 lorsqu'il s'agit d'un bâtiment réel, par exemple a> 0, sinon 1). Notez que lorsque nous sommes au niveau du sol, il n'essaie jamais de dessiner un toit, ce qui signifie que les bâtiments de taille 0,5 n'ont pas de toits pointus. Tant pis.

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

Lorsque nous sommes au niveau du sol, nous voulons des traits de soulignement au lieu d'espaces. Nous les remplaçons tous à la fois ici.

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

Juste avant de commencer le traitement de la ligne suivante, imprimez la ligne actuelle et effacez la ligne de sortie. Nous coupons le dernier caractère car c'est le "_" correspondant à l'espace au sol que nous avons ajouté en ajoutant un zéro au début de la fonction. (Nous avons ajouté ce zéro afin que nous n'ayons pas à ajouter un cas spécial pour insérer un mur droit, s'il existe, ce qui ajouterait beaucoup plus de code que nous n'en avons ajouté en ajoutant le 0 et en coupant le "_".)

quintopie
la source
Golf de voiture. Sensationnel. (Aussi, +1)
applaudissez
2

Python 3

725 octets

608 octets

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

Voici le code non golfé. Il y a quelques commentaires mais l'idée de base est de créer des bâtiments à double paroi, donc la ligne de fond ressemble à:

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

Ensuite, pour obtenir les index de ces doubles parois et supprimer ces colonnes, nous obtenons:

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

Code:

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

Il est temps de faire du golf!

Cajova_Houba
la source
Vous voudrez peut-être jeter un œil ici . Je pense qu'il y a beaucoup de potentiel de golf ici =) Je ne connais que le Python de base, donc je ne peux rien suggérer de précis, j'ai peur ...
Stewie Griffin
Il me semble que vous avez supprimé des espaces et raccourci les noms de variables, mais gardé le reste inchangé. Vous devriez essayer de trouver des moyens astucieux pour par exemple se débarrasser de certaines boucles, utiliser moins de comparaisons , etc. Bien sûr, des choses comme ru(n):return math.ceil(n)compte comme le golf, mais quand même ... S'il vous plaît ne prenez pas cela d'une manière négative, je ne suis pas bon golfeur moi-même, et certainement pas un bon programmeur. Je vous suggère d'essayer de l'améliorer un peu ... C'est en fait assez amusant une fois que vous réalisez que vous parvenez à le raccourcir. Je suis passé de plusieurs à 120 à 55 il y a quelques jours. C'est donc possible même si vous êtes nouveau.
Stewie Griffin
@StewieGriffin Merci pour ce lien! Je suis vraiment un débutant dans le golf de code, il s'agit donc de terminer la tâche réelle plutôt que de faire du golf de code pour moi. Mais c'est incroyable de découvrir les possibilités de différentes langues
Cajova_Houba
FTR: Pour certains des défis les plus complexes, comme celui-ci, je serais heureux de le terminer moi-même =)
Stewie Griffin
2

PHP, 307 297 293 octets

<?$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;

Prend les arguments * 2 de la ligne de commande. enregistrer dans un fichier, exécuter avec php <filename> <parameters>.

panne

// 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;
Titus
la source
1

C ++, non golfé

(ou peut-être ingérable)

En supposant qu'il y a moins de 100 éléments et que chaque élément est inférieur à 100. sest le nombre de bâtiments (requis en entrée).

#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;
}
}
ghosts_in_the_code
la source
Il y a quelques erreurs dans la sortie ... Le sol fait 3 caractères de large (il ne devrait y en avoir qu'un), et le dernier mur manque.
Stewie Griffin
@StewieGriffin J'étais toujours en train de trier les erreurs quand j'ai posté cela. 1. J'ai ajouté le dernier mur. 2. Le sol doit avoir 3 caractères de large, car le toit incliné / _ \ a 3 caractères de large.
ghosts_in_the_code
1
* Le sol entre les bâtiments, pas à l'intérieur.
Stewie Griffin
Si vous y travaillez encore, vous voudrez peut-être attendre, mais vous pouvez vous débarrasser de nombreux octets si vous supprimez les sauts de ligne et l'indentation. Je n'ai pas résolu le problème de sol, mais cela fonctionne .346 octets au lieu de 401.
Stewie Griffin
@StewieGriffin Je n'ai pas vraiment l'intention de soumettre une réponse au golf car c'est beaucoup trop long de toute façon. Je peux parier qu'il existe de meilleures langues où cela se fait en moins de 100 octets. Mon code est donc plus une solution de référence pour les autres.
ghosts_in_the_code