Zeichnen eines Würfels in ASCII-Grafik


32

Aufgabenbeschreibung:

Zeichnen Sie in ASCII-Kunst einen Würfel in einer ungefähren Schrankprojektion.

Monospaced fontsHäufig sind die Zeichen doppelt so hoch wie breit. Da die Eingabe die Länge der vertikalen Linien (ohne die Ecken) ist, werden horizontale Linien mit doppelt so vielen Zeichen gezeichnet, sodass das resultierende Bild in etwa ein Würfel ist. Die zurückgehenden Linien werden auf die Hälfte der Länge gezeichnet, wie dies durch eine Kabinettprojektion vorgeschrieben ist.

Die Ecken des Würfels werden durch +horizontale Linien -, vertikale Linien |und diagonale Linien dargestellt /.

Zusammenfassen: Dann sei die Eingabe n

  • Eine horizontale Kante des Würfels wird mit gezeichnet -und besteht aus 2  n Zeichen.
  • Eine vertikale Kante des Würfels wird mit n Zeichen gezeichnet |und besteht aus n Zeichen.
  • Eine diagonale Kante des Würfels ist mit /und besteht aus n / 2 Zeichen.
  • Würfelecken sind mit gezeichnet +. Ecken werden nicht wie oben beschrieben für die Länge einer Kante gezählt (siehe auch Beispiele unten).

Eingang:

Die Eingabe bei der Standardeingabe ist eine positive gerade Zahl n (2 ≤ n ≤ 30), die die Länge der vertikalen Linien des Würfels angibt. Es folgt ein einzelner Zeilenumbruch.

Ausgabe:

Die Ausgabe ist ein Würfel für die Standardausgabe gemäß den obigen Regeln. Das nachfolgende Leerzeichen in den Zeilen wird ignoriert.

Beispieleingang 1:

2

Beispielausgabe 1:

  +----+
 /    /|
+----+ |
|    | +
|    |/
+----+

Beispieleingang 2:

4

Beispielausgabe 2:

   +--------+
  /        /|
 /        / |
+--------+  |
|        |  |
|        |  +
|        | /
|        |/
+--------+

ETA: Ich habe jetzt die kürzeste Lösung akzeptiert. Ich werde die akzeptierte Antwort aktualisieren, wenn eine kürzere kommt.

Da fragten einige Leute, wie lange die Einsendungen unserer Teilnehmer waren:

227 - Python
240 - Perl
310 - C
315 - C
326 - VB.NET
459 - C

Sowie unsere eigenen Lösungen (nicht mit den anderen eingestuft):

140 - Golfscript
172 - Ruby
183 - PowerShell


Kannst du ein wenig über die besten Lösungen erzählen, die du hattest? Wie viele Zeichen hatten die Kleinsten?
Juan

@ Juan: Hinzugefügt die angeforderten Informationen
Joey

1
Amüsanterweise kann C ++ ähnliche Zeichnungen wie "analoge Literale" verwenden: hostilefork.com/2009/08/29/tweakinganalog-literals-humor
Dr. Rebmu

@ Hostile: Ja, das war nett, wenn auch ein bisschen böse ;-)
Joey

Antworten:


10

Golfscript - 96 Zeichen

~:<2/:$){' '*}:s~'++'<'--'**:^n$,{.$\-s'//'2s<*:&*@s'|':|n}%^$[$s|n|&|]*$s'+'n$,{n'/'@s|&|}%-1%^

Der größte Teil der Kompaktheit ergibt sich aus der aggressiven Speicherung fast aller Daten in einer Variablen (es sei denn, Sie sind in Golfscript geschrieben).

<    n
$    n/2
s    {' '*}     # top of the stack becomes a string of that many spaces
^    '+------+'
&    '      '   # 2n spaces, i.e. 2s<* or <s2*
|    '|'

Ein paar andere kleine Tricks hier.

  1. 'LR''str'*-> 'LstrR'.
  2. Da wir die Zeilenreihenfolge im letzten Array umkehren müssen, wählen wir dies nach dem Generieren des Texts statt zuvor. Dies ermöglicht es uns, ein Zeichen zu speichern, da die Leerzeichen davor '/'nur zwei Stapelelemente ( @) anstelle von 3 ( @ .. \) überschreiten müssen.

16

Python - 248 243 230 227 191

Etwas unordentlich, aber es druckt den Würfel grundsätzlich zeilenweise (unter Verwendung eines Zeichenfolgenpuffers).

t=v=h=input()/2
s,p,b,f,n=" +|/\n"
l=p+"-"*t*4+p;S=s*4*t;k=s*h;K=b+S+b
r=s*t+s+l+n
while t:r+=s*t+f+S+f+s*(h-t)+b+n;t-=1
r+=l+k+b+n+(K+k+b+n)*(v-1)+K+k+p+n
while v:v-=1;r+=K+s*v+f+n
print r+l

Vielen Dank an @marcog für den Hinweis auf die erste Zeile, @ThomasO für den Hinweis auf die zweite Zeile und an @Juan, der mir klar gemacht hat, dass ich Zeilen kombinieren kann.


4
Um etwas mehr Platz zu sparen, wechseln Sie s=" ";p="+";b="|";f="/";n="\n"zu s,p,b,f,n=" +|/\n".
Thomas O

1
Eine Stimme ist nicht genug. Sie haben mich dazu gedrängt, meine Lösung an Grenzen zu bringen, die ich für unmöglich hielt, danke: D
Juan

:) Jetzt mal schauen, ob es besser geht.
JPvdMerwe

10

Python - 179

h=input()*2
j=d=h/4
q,e,u,p,k="| \n+/"
w=e*d
s=p+'-'*h+p
i=''
o=e+w+s+u
v=q+e*h+q
while j:o+=e*j+k+e*h+k+e*(d-j)+q+u;j-=1;i+=v+e*j+k+u
print o+s+w+q+u+(v+w+q+u)*(d-1)+v+w+p+u+i+s

Ich möchte darauf hinweisen, dass ich einige Ideen von JPvdMerwe übernommen habe.


Zeile 3 fehlt eine 2 am Ende, was den Zähler leider auf 256
erhöht.

@JPvdMerwe Hoppla, danke, dass du das erwischt hast!
Juan

1
Vielleicht können Sie versuchen, die Ergebnisse in einer Zeichenfolge zwischenzuspeichern, wie ich es getan habe und nur einmal zu drucken?
JPvdMerwe

1
@ Juan Ich denke, wir sollten vermeiden, alte Kopien in der Post zu behalten, es sei denn, die beiden Versionen unterscheiden sich erheblich. Sie können im Bearbeitungsverlauf angezeigt werden, wenn jemand sie lesen möchte.
Marcog

2
Was die FAQ betrifft: Ich füge meinen Posts oft einen Längenverlauf hinzu (  hier war jedoch ein Beispiel, das zu lang geworden ist). Ich weiß nicht, ob so etwas hilfreich ist, aber es kann anderen helfen, herauszufinden, welche Tricks verwendet wurden, um es kurz zu halten. Obwohl ich auch eine SVN-Geschichte dafür habe.
Joey

8

fortran 77 - 484 Zeichen

      program z
      read(*,*) i
      g=f('+- ',i/2+1,i,0)
      do k=1,i/2
         g=f('/ |',i/2-k+1,i,k-1)
      end do
      g=f('+-|',0,i,i/2)
      do k=1,i/2-1
         g=f('| |',0,i,i/2)
      end do
      g=f('| +',0,i,i/2)
      do k=1,i/2
         g=f('| /',0,i,i/2-k)
      end do
      g=f('+- ',0,i,0)
      stop
      end
      real function f(c,l,m,n)
      character c(3)
      write(*,*)(' ',j=1,l),c(1),(c(2),j=1,2*m),c(1),(' ',j=1,n),c(3)
      return
      end

Kein wirklicher Grund, eine "unbefangene" Version bereitzustellen. Beachten Sie, dass Markdown mit den Einrückungsanforderungen nicht gut zurechtkommt.

Ich habe fortran wegen der Inline for-Schleifen aus der writeAnweisung ausprobiert . Offensichtlich helfen sie, aber sie summieren sich nicht auf genug, um die Worte der Sprache zu töten. Sie kann durch die Verwendung von Freiform-Eingaben verringert werden.

Validierung:

 $ wc cube_func_array.f
 22  41 484 cube_func_array.f
 $ gfortran cube_func_array.f
 $ echo 2 | ./a.out
   +----+ 
  /    /|
 +----+ |
 |    | +
 |    |/
 +----+ 
 $ echo 4 | ./a.out
    +--------+ 
   /        /|
  /        / |
 +--------+  |
 |        |  |
 |        |  +
 |        | /
 |        |/
 +--------+ 

Zum Glück sagt die Spezifikation nicht, wie die Größe aussehen soll:

 $ echo 1 | ./a.out
  +--+ 
 +--+|
 |  |+
 +--+ 

aber andere ungerade Größen sind vernünftig:

 $ echo 3 | ./a.out
   +------+ 
  /      /|
 +------+ |
 |      | +
 |      |/
 +------+ 

Interessante Sprachwahl :-). Nun, Größe 1 sieht nicht schlecht aus. Meine Lösung löst eine Endlosschleife aus. Wenn ich mich recht erinnere, waren unterschiedliche Rundungsverhalten der Grund, ungerade Größen auszuschließen (und die Obergrenze von 30 für die Anpassung an eine Breite von 80 Zeichen).
Joey

1
@joey: Ich mache von Zeit zu Zeit Fortran und bin froh, wenn ich weniger als einen Faktor 10 länger als der Gewinner bin.
dmckee

4

Meine eigene Lösung, da sie von Python bereits zu Tode geprügelt wurde:

Windows PowerShell, 183

$t=($w=($s=' ')*($o=($n="$input")/2))*4
$r="|$t|"
$s*($a=$o+1)+($q='+'+'--'*$n+'+')
$o..1|%{$s*--$a+"/$t/$($s*$b++)|"}
"$q$w|"
for(;$o-++$x){"$r$w|"}"$r$w+"
--$b..0|%{$r+$s*$_+'/'}
$q

Ah ... Sprachen, die Sie "mehrere" Zeichenfolgen durch einen Skalar helfen lassen, für diese ...
dmckee

Nun, es ist immer noch weit hinter Venteros Ruby oder Golfscript - wie immer;)
Joey

4

PostScript, 237

[/n(%stdin)(r)file token()/p{print}/r{repeat}([){{( )p}r}/N{n 2 mul}(]){n 2 idiv}/l{N(+)p{(-)p}r(+)p}/I{(|)p}/X{][p}>>begin
( )X l()=]-1 1{dup[(/)p N[(/)p]exch sub[(|)=}for
l(|
)X]1 sub{I N[I(|
)X}r
I N[I(+
)X]-1 1{I N[I 1 sub[(/)=}for
l

Geschichte:

  • 2011-03-01 01:54 (427) Erster Versuch.
  • 2011-03-01 02:01 (342) hat def noch einige Dinge hinzugefügt , die oft aufgetaucht sind.
  • 2011-03-01 02:24 (283) Noch mehr defs.
  • 2011-03-01 02:42 (281) Und noch eine def, die zwei weitere Bytes speichert.
  • 2011-03-01 03:01 (260) [ und ]haben schöne Eigenschaften, wenn sie als Variablen verwendet werden :-). Danke an KirarinSnow .
  • 2011-03-01 03:12 (246) Inline-Zeilenumbrüche mit einem Diktat anstelle zahlreicher defs. Nochmals vielen Dank :-).
  • 2011-03-01 03:26 (237) Mehr Dank an KirarinSnow .

3

Ruby 1.9, 172 165 162 Zeichen

w=(s=?\s)*o=(n=gets.to_i)/2;r=(z=?|)+w*4+z
puts s*(o+1)+q=?++?-*2*n+?+,(l=0...o).map{|u|[s*(o-u),w*4,s*u+z]*?/},q+w+z,[r+w+z]*o-=1,r+w+?+,l.map{|u|r+s*(o-u)+?/},q

1

Ruby - 423 Zeichen

Ich möchte das wirklich nicht teilen, da es so eine schreckliche Zählung ist, aber da ich es geschrieben habe, könnte es genauso gut sein.

n=$<.read.to_i
a=(q=Array).new(n+n/2+3){q.new(2*n+n/2+3,' ')<<"\n"}
a[n+1][2*n+n/2+2]=a[0][n/2+1]=a[0][2*n+n/2+1]=a[n/2+1][0]=a[n/2+1][2*n]=a[n+n/2+2][0]=a[n+n/2+2][2*n]=:+
a[0][n/2+2,n*2-1]=a[n/2+1][1,n*2-1]=a[n+n/2+2][1,n*2-1]=[:-]*2*n
a[n/2+2,n].each{|b|b[0]=b[2*n+1]=:|}
a[1,n].each{|b|b[2*n+n/2+2]=:|}
c=n/2
a[1,n/2].each{|b|b[c]=b[2+2*n+c-=1]=:/}
c=n/2
a[n+2,n/2].each{|b|b[2+2*n+c-=1]=:/}
a.flatten.each{|g|print g}

Könnte wahrscheinlich um einiges reduziert werden, aber ich bezweifle, dass dieser Brute-Force-Ansatz eine annähernd anständige Anzahl von Charakteren erreichen wird, so dass ich mich nicht darum kümmern kann.


1

PHP, 401 392 382 363 Zeichen:

<? $h=fgets(STDIN);$s="str_repeat";$w=$h*2;$d=$h/2;$b=$h;$c=" ";echo$s($c,$h/2+1)."+".$s("-",$w)."+\n";for($i=1;$i<=$d;$i++,$a=--$b){echo$s($c,($h/2+1)-$i)."/".$s($c,$w)."/".$s($c,$i-1)."|\n";}echo"+".$s("-",$w)."+".$s($c,$d)."|\n";for($i=1;$i<=$h;$i++){echo"|".$s($c,$w)."|";echo $a-->0?$s($c,$b).($a>0?"|":"+")."\n":$s($c,$h-$i)."/\n";}echo"+".$s("-",$w)."+\n";

Ich habe das ursprünglich gemacht, um zu sehen, wie kurz ich das in PHP schaffen könnte, da ich wusste, dass es ziemlich lang werden würde. Ich bin sicher, es könnte reduziert werden, aber nicht viel, wenn man bedenkt, dass PHP nicht viele Verknüpfungen hat.

Validierung:
http://codepad.viper-7.com/ftYYz9.php53

Ungolfed Version: http://codepad.viper-7.com/4D3kIA


Habe es nur so geändert, dass es aus stdin liest, das habe ich in der Frage verpasst. Benötigt die Funktion deswegen nicht mehr.
Kevin Brown

Der Code wurde so geändert, dass er korrekt aus stdin liest. Auch golfte es ein wenig mehr, um die Größe zu reduzieren.
Kevin Brown

Die untere rechte diagonale Linie ist nicht vorhanden und stattdessen wird eine versetzte vertikale Linie angezeigt. Es sei denn, ich rufe etwas falsch an.
Joey

1

Perl, 163

$d=<>/2;$s=$"x$d;$H=$s x4;$f="|$H|";$t.=$"
x$d--."/$H/".$"x$_."|\n",$m.="$f$s|\n",$b
=$f.$"x$_."/\n$b"for 0..$d-1;$_="+$H+";
y/ /-/;say" $s$_\n$t$_$s|\n$m$f$s+\n$b$_"

Perl 5.10 oder höher kann mit ausgeführt werden perl -E '<code here>'

Respaced Version:

$d = <> / 2;
$s = $" x $d;
$H = $s x 4;
$f = "|$H|";

$t .= $" x $d-- . "/$H/" . $"x$_ . "|\n",
$m .= "$f$s|\n",
$b = $f . $" x $_ . "/\n$b"
  for 0 .. $d-1;

$_ = "+$H+";
y/ /-/;
say " $s$_\n$t$_$s|\n$m$f$s+\n$b$_"

1

Perl, 269 ​​269 262 256 245 244 237 226 228 224 217 Zeichen

sub p {y / xS / + \ //; print; y / + \ // xS /} $ b = / 2; $ a = $ b; $ _ = "xx \ n"; s / x / x- --- / while ($ a -); bis (/ ^ S /) {p; s / [xS] / S / g; s / -x / S | /; y / - / /} s / ( = * S) / - / g; y / S / x /; p; y / -x / | /; p while (- $ b); s / .$/ x /; while (/ \ | / ) {p; s /..$/ S /} y / | S / ++ - /; p

Die Grundidee ist, alles mit Regex-Substitutionen zu machen. Da zwei der verwendeten Zeichen (+ und /) Sonderzeichen sind und häufig in regulären Ausdrücken vorkommen, lohnt es sich, andere Zeichen zu verwenden und durch diese zu ersetzen.

Etwas besser lesbare Version:

# Unterprogramm zum Ersetzen, Drucken und Ersetzen wie oben beschrieben
sub p {y / xS / + \ //; print; y / + \ // xS /}
# Lesen Sie von stdin und richten Sie die Anfangszeile ein
$ b = <> / 2; $ a = $ b; $ _ = "xx \ n";
s / x / x ---- / while ($ a--);
# Bedrucken Sie die Oberseite
bis (/ ^ S /) {
  p;
  s / [xS] / S / g; # Zum ersten Mal: ​​left + -> /; nachfolgende Zeiten bewegen / links
  s / -x / S | /; # Nur relevant beim ersten Mal in der Schleife
  y / - / / # Nur relevantes erstes Mal in der Schleife
}
# Bereiten Sie die Zeile mit der zweiten horizontalen Linie vor und drucken Sie sie aus
s / (& agr; = * S) / - / g;
y / S / x /;
p;
# Jetzt drucken Sie (n-1) / 2 identische Zeilen
y / -x / | /;
p while (- $ b);
# Bringen Sie die rechte Kante ein
s /.$/ x /;
während (/ \ | /)
{
  p;
  s /..$/ S /
}
# Letzte Zeile
y / | S / ++ - /;
p

In gewisser Weise betrüge ich, indem ich $ b als Zähler in der Zwischenschleife verwende - ich könnte stattdessen Leerzeichen in der Schleife über $ a anhängen und dann Regex-Ersetzungen für diese Schleife verwenden - aber ich werde diese leichte Abweichung zulassen aus einer reinen Regex-Lösung.

Zweifellos kann eine beängstigende Person daraus ein viel kürzeres Sed-Skript machen.


"Etwas besser lesbare Version" - ich finde es toll, dass Perl nur dann etwas besser lesbar wird, wenn Zeilenumbrüche und Leerzeichen enthalten sind. :)
Steve

@Steve, auch bei den Kommentaren muss man ein bisschen Perl kennen, um es zu verstehen. Die Verwendung von yfor trist nicht offensichtlich und der Weg, den "while" gehen kann, bevor oder nachdem ...
Peter Taylor

1

Lua, 294 302 292 Bytes

Golf gespielt:

n=(...)p="+"d=2*n s=" "S=s:rep(d)h=n/2 T=s:rep(h)L="\n"o="/"v="|"a=p..("-"):rep(d)..p r=T..s..a..L for i=0,h-1 do r=r..s:rep(h-i)..o..S..o..s:rep(i)..v..L end r=r..a..T..v for i=1,h do r=r..L..v..S..v..T..(i==h and p or v) end for i=h-1,0,-1 do r=r..L..v..S..v..s:rep(i)..o end print(r..L..a)

Ungolfed:

n        = n or io.read() or 6
plus     = "+"
doubled  = 2*n
space    = " "
Space    = space:rep(doubled)
halved   = n/2
T        = space:rep(halved)
Line     = "\n"
or_sign  = "/"
vertical = "|"
a        = plus..("-"):rep(doubled)..plus
result   = T..space..a..Line

for i=0,halved-1 do
    result = result .. space:rep(halved-i) .. or_sign .. Space .. or_sign .. space:rep(i) .. vertical .. Line
end

result = result..a..T..vertical

for i=1,halved do
    result = result .. Line .. vertical .. Space .. vertical .. T .. (i==halved and plus or vertical)
end

for i=halved-1,0,-1 do
    result = result .. Line .. vertical .. Space .. vertical .. space:rep(i) .. or_sign
end

print(result .. Line .. a)

Die Eingabe erfolgt über den Standardeingabestream. Dies scheint hier nicht zu funktionieren.
Joey

Sie können auch das or 6nach dem read()Anruf weglassen, was vier Bytes spart :-)
Joey

Hm, jetzt mit dem (...)funktioniert es bei mir auf Lua 5.1.4 nicht mehr.
Joey

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.