建築家がスカイラインを視覚化できるようにします


29

都市計画プロジェクトの一環として、都市のスカイラインを表示するプログラムまたは機能を作成する割り当てを取得しました。建築家からの入力があります。プロジェクトは起動段階にあるため、非常に大まかなスケッチで十分です。もちろん、最も簡単な方法は、単にASCIIアートでスカイラインを描くことです。

すべての建物は川沿いにあるため、すべて揃っています。建築家は各建物の高さを入力として提供し、コードはスカイラインを表示する必要があります。

アーキテクトからの入力は、整数または半整数のいずれかです。数値が整数の場合、建物の屋根は平らになりますが、半分の整数では屋根が傾斜します。ゼロは単に平らな地面になります。建物の壁は3文字離れており、ゼロは1文字幅です。隣接する建物は壁を共有しています。

出力に関する詳細と説明については、以下の例をご覧ください。

N = 3
 ___
|   |
|   |
|___|

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

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

n = 0
_

入力例: 3 3.5 0 2

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

入力例: 0 0 2.5 3 0 4 1

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

ルイビル0 2 1 3.5 0 4 2 4 2 4 6 1 6 0 5 1

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

使用されるASCII文字は、改行、スペース、および/\_|(コードポイント10、32、47、92、95、124)です。

ルール:

  • すべての数値に2を掛けて、整数のみを入力として使用するプログラムを作成することはオプションです。そのため、3 3.5 2プログラムはの代わりにを取得する場合があります6 7 4。2番目の入力形式を選択した場合、6を入力すると3階建ての建物になり、7は傾斜屋根などの3階建ての建物になります。
  • 出力は上記のとおりになりますが、末尾のスペースと改行は問題ありません。
  • 入力の正確な形式はオプションです。あなたの言語で最高のものは何でも。
  • 結果を画面に表示して、建築家がそれを見ることができるようにする必要があります。
  • 少なくとも1つの整数が与えられ、有効な入力のみが与えられると仮定できます。

これはcodegolfであるため、バイト単位の最短コードが優先されます。


1
高さ0.5の建物はどのように見えますか?
トムカーペンター

本当に考えていません。...最も明白な選択肢はほとんどホビットの家のように、ちょうど屋根のだろう:-)しかし、あなた選択するか、入力を取ることができるしている自由は0.5になることはありません
Stewieグリフィン

1
現時点では、壁がないために奇妙なことが起こります(0.5の高さは存在しないと想定していました)。そのため、少し答えに取り組まなければなりません。
トムカーペンター

高さ0.5でコードを試したところ、「奇妙な」という言葉は非常にわかりやすい言葉であることに同意します。= PIは詳細には説明していません。したがって、何が起こっているのかわかりません。完全に有効な、あなたは...任意の0.5建物が存在しないと仮定することができます
Stewieグリフィン

回答:


5

Python 2、199 193 188 185バイト

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

これは、整数を入力として受け入れる完全なプログラムです。例入力


素晴らしい!私は将来のゴルフのためにこれらのトリックのいくつかを盗む必要があります
...-quintopia

5

MATLAB、219 209 203バイト

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

残念ながら、これはOctaveでは機能しません。なぜ完全に定かではないが、壊れるdisp / flipudビットと関係があるようだ。

また、現在、0.5の高さの建物がどのように見えるかについての定義も、それらの言及もないため、このコードでは、それらは許可されていないと仮定します。

以下は、もう少し読みやすいコードです。

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

まず、入力を配列として受け取り、変数の初期化を行います。

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;

高さゼロの建物は苦痛なので、基本的には隣にあるものに依存する幅になります(印刷されるものは変わりませんが)、すべての建物に十分な地面を描くことで物事を単純化します。各建物の幅は4文字であると想定しています(隣接する建物が結合するため)-高さゼロの建物はそうではありませんが、超過分は後でトリミングされます。

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

次に、各建物を順番に引き出します。

for a=i

まず、高さの整数部分を取得します。これにより、「|」の数が決定されます。必要です。

    b=fix(a);

次に、この建物の壁を描きます-隣接する建物が2つある場合、この新しい建物の壁は最後の建物の壁と同じ列になります。

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

これが半分の高さの建物かどうかを確認します。そうである場合、屋根は異なります。/ \ハーフハイトの場合、ルーフはフルハイトのものになります___(Matlabはこれを単一のアンダースコアから暗黙的に複製するため、そこに数バイトを保存します)。半分の高さの建物には1行高い屋根の余分なビットがあるため、それも追加されます。

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

屋根に描く

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

次に、次の建物の開始点に移動し、共有壁を描画します(この時点で壁が短すぎる場合は、次の建物が描画されるときに壁が大きくなります)。高さゼロの建物は1幅、通常の建物は4幅なので、ブール値ではなく10進数として(a> 0)を処理することで、if-else以外を単純化することに注意してください。

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

次に、高さゼロの建物を操作するためのちょっとしたハッカーが来ます。基本的にこれは、この建物が高さゼロで、それ以前の建物がそうでない場合、次の建物の場所が1ずつ増加する必要があることを意味します。通常、隣接する建物と共有される余分な壁を考慮します。また、次回このチェックを行うために、この建物の高さを追跡します。

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

完了したら、ビルディングマトリックスを正しい方向に反転させて表示します。ここで余分な地面も切り落とすことに注意してください。

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

したがって、このスクリプトを実行すると、次のように入力を求められます。

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

次に、建物を生成し、結果を表示します。上記の入力に対して、次が生成されます。

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

非常によくやりました!
スティーヴィーグリフィン

4

Kotlin、447 442バイト

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

ゴルフされていないバージョン:

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

パイソン2、357の 306 299 294 287 281 276バイト

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

これは、「二重」エンコーディングを使用して、リストとして関数に渡されます。編集:大きな条件の一部を配列セレクターとしてやり直し、2倍のエンコーディングに切り替えることで、バイトを削ります。条件をさらに再配置し、より多くのロジックを算術に変換することにより、より多くのバイトを削りました。

編集:xsotのは良いです

説明:

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

dリストの各端に2番目の要素から最後に追加したゼロまでゼロを追加するため、配列の長さより1大きくなります。h図面の高さです。(この計算では、2倍の表現を使用しているので、2で割る必要があります。これは、場所全体にfloatをintにキャストする必要がないようにするために特に使用します。通常の種類よりも少し多くのクリアランスを取得します。)oは出力文字列です。

 for i in range(d*h):

ダブルforループをシングルforループに折り畳むための標準的なトリック。実行したら:

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

今と同じことを達成しました:

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

しかし、10バイトの節約になります(次の行の空白を含む)。

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

ここに少なくとも1つの建物の境界がある限り、現在の建物または前の建物のいずれかの高さが現在の線よりも高い場合はいつでも壁を貼り付けてください。次の条件と同等です。

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

ここで、bは現在のスキャンの高さ、aは現在の建物の高さ、cは前の建物の高さです。条件の後半は、地面の間に壁を置くことを防ぎます。

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

これは、建物の高さと現在のスキャン高さを比較して屋根のパーツを選択し、正しい屋根を描くパーツです。屋根がここに行かない場合は、適切な数のスペース(実​​際の建物の場合は3、a> 0、それ以外の場合は1)を印刷します。地上にいるときは、屋根を描画しようとしません。つまり、0.5サイズの建物には尖った屋根ができません。しかたがない。

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

地上レベルでは、スペースではなくアンダースコアが必要です。ここで一度にすべて置き換えます。

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

次の行の処理を開始する直前に、現在の行を印刷して出力行をクリアします。関数の先頭にゼロを追加して追加したグラウンドスペースに対応する「_」であるため、最後の文字を切り取ります。(0を追加して "_"を切り捨てて追加したコードよりもはるかに多くのコードが追加されるように、右の壁が存在する場合は挿入するために特別なケースを追加する必要がないようにゼロを追加しました。)


カーゴルフ。ワオ。(また、+ 1)
クラップ

2

Python 3

725バイト

608バイト

ゴルフコード:

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)

これは、変更されていないコードです。いくつかのコメントがありますが、基本的な考え方は二重壁の建物を作成することです。

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

次に、これらの二重壁のインデックスを取得し、それらの列を削除して、以下を取得します。

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

コード:

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

ゴルフをする時間です!


ここを見てみてください。私は私が...怖いものの特定を提案することはできませんので、私は、基本的なPythonのを知っている)=ゴルフの多くの可能性がここにあると思う
Stewieグリフィン

スペースを削除して変数名を短縮したように見えますが、残りは変更しません。たとえば、いくつかのループを取り除き、比較を少なくするなど、賢い方法を見つけてください。もちろん、ru(n):return math.ceil(n)ゴルフとしてカウントするようなものですが、それでも...否定的な方法でこれを受け取らないでください。ゴルファー自身、そして地獄のように良いプログラマーではありません。いくつか改善してみることをお勧めします...実際に短くすることに気づいたら、それは実際に一種の楽しみです。私は数日前に多くの人から120人から55人になりました。だから、あなたがそれに慣れていなくても可能です。
スティーヴィーグリフィン

@StewieGriffinそのリンクをありがとう!私は本当にコードゴルフの初心者なので、私のためにコードゴルフをするよりも実際のタスクを完了することが重要です。しかし、さまざまな言語の可能性を発見するのは驚くべきことです
-Cajova_Houba

FTR:このような複雑な課題のいくつかについては、自分でそれを終えることができれば幸いです=)
Stewie Griffin

2

PHP、307 297 293バイト

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

コマンドラインから引数* 2を取ります。ファイルに保存し、で実行しphp <filename> <parameters>ます。

壊す

// 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 ++、ungolfed

(またはたぶん使用不可)

100未満の要素があり、各要素が100未満であると想定sします。建物の数です(入力で必要)。

#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;
}
}

出力にはいくつかのエラーがあります...地面の幅は3文字で(1だけでなければなりません)、最後の壁がありません。
スティーヴィーグリフィン

@StewieGriffinこれを投稿したとき、私はまだエラーを整理していました。1.最後の壁を追加しました。2.傾斜した屋根/ _ \は3文字幅なので、地面は3文字幅でなければなりません。
ghosts_in_the_code

1
*地上間の内部の建物、ではありません。
スティーヴィーグリフィン

まだ作業中の場合は、待つことをお勧めしますが、改行とインデントを削除すると、多くのバイトを取り除くことができます。地上の問題は修正していませんが、これは401ではなく0.346バイトで動作します。
Stewie Griffin

@StewieGriffinそれはとにかく長すぎるので、私は実際にゴルフの答えを提出するつもりはありません。100バイト未満で処理されるより良い言語が存在するに違いない。ですから、私のコードは他の人への参照ソリューションです。
ghosts_in_the_code
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.