Disegnare un cubo nell'arte ASCII


32

Descrizione del compito:

Disegna un cubo in arte ASCII in circa una proiezione di cabinet.

Monospaced fontsspesso hanno personaggi che sono circa due volte più alti che larghi. Poiché l'input è la lunghezza delle linee verticali (esclusi gli angoli), le linee orizzontali vengono disegnate con il doppio del numero di caratteri in modo che l'immagine risultante sia in realtà un cubo. Le linee sfuggenti sono disegnate a metà della lunghezza, come richiesto da una proiezione di gabinetto.

Gli angoli del cubo sono rappresentati da +, linee orizzontali da -, linee verticali da |e diagonali usate /.

Riassumendo: lascia che l'input sia n , quindi

  • Un bordo orizzontale del cubo viene disegnato con -ed è composto da 2  n caratteri.
  • Un bordo verticale del cubo viene disegnato con |ed è composto da n caratteri.
  • Un bordo diagonale del cubo viene disegnato con /ed è composto da n / 2 caratteri.
  • Vengono disegnati gli angoli del cubo +. Gli angoli non vengono conteggiati per la lunghezza di un bordo come descritto sopra (vedere anche gli esempi di seguito).

Ingresso:

L'input, fornito sull'input standard, è un singolo numero pari, positivo n (2 ≤ n ≤ 30) che indica la lunghezza delle linee verticali del cubo. È seguito da un'interruzione a riga singola.

Produzione:

L'output è un cubo sull'output standard che segue le regole precedenti. Lo spazio bianco finale sulle linee viene ignorato.

Esempio di input 1:

2

Uscita campione 1:

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

Esempio di input 2:

4

Uscita campione 2:

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

ETA: ora ho accettato la soluzione più breve. Aggiornerò la risposta accettata quando ne arriva una più breve.

Dal momento che alcune persone hanno chiesto per quanto tempo le voci dei nostri concorrenti erano:

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

Oltre alle nostre soluzioni (non classificate con le altre):

140 - Golfscript
172 - Ruby
183 - PowerShell


puoi parlarci un po 'delle migliori soluzioni che hai avuto? Quanti caratteri ha avuto il più piccolo?
Juan,

@Juan: aggiunte le informazioni richieste
Joey

1
In modo abbastanza divertente, C ++ può usare disegni simili come "letterali analogici": hostilefork.com/2009/08/29/tweakinganalog-literals-humor
Dr. Rebmu

@Hostile: Sì, quello era carino, anche se un po 'malvagio ;-)
Joey,

Risposte:


10

Golfscript - 96 caratteri

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

Gran parte della compattezza deriva dalla memorizzazione aggressiva di quasi tutto in una variabile (a meno che non si includa la scrittura in golfscript).

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

Un paio di altri piccoli trucchi qui.

  1. 'LR''str'*-> 'LstrR'.
  2. Poiché è necessario invertire l'ordine delle righe nell'ultimo array, si sceglie di farlo dopo aver generato il testo anziché prima. Questo ci consente di salvare un carattere perché gli spazi prima '/'dell'unica devono passare oltre due elementi dello stack ( @) anziché 3 ( @ .. \).

16

Python - 248 243 230 227 191

Leggermente disordinato ma fondamentalmente stampa il cubo riga per riga (utilizzando un buffer di stringa).

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

Grazie a @marcog, per aver sottolineato la prima riga, @ThomasO per aver sottolineato la seconda riga e a @Juan per avermi fatto capire che posso combinare le linee.


4
Per risparmiare un po 'più di spazio, cambia s=" ";p="+";b="|";f="/";n="\n"in s,p,b,f,n=" +|/\n".
Thomas O

1
Un voto positivo non è sufficiente. Mi stai spingendo per migliorare la mia soluzione ai limiti che pensavo impossibili, grazie: D
Juan

:) ora per vedere se il meglio è possibile.
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

Vorrei notare che ho preso alcune idee da JPvdMerwe (Usare una stringa per stampare una volta, e il one-liner per quello che non sapevo fosse la sintassi corretta in Python).


Alla riga 3 manca un 2 alla fine, che, sfortunatamente, porta il conteggio a 256.
JPvdMerwe

@JPvdMerwe oops, grazie per averlo scoperto!
Juan,

1
Forse puoi provare a memorizzare nella cache i risultati in una stringa come ho fatto io e stampare solo una volta?
JPvdMerwe,

1
@Juan Penso che dovremmo evitare di conservare vecchie copie nel post, a meno che le due versioni non siano sostanzialmente diverse. Sono visualizzabili nella cronologia delle modifiche se qualcuno vuole leggerlo.
marcog,

2
Per quanto riguarda le FAQ: spesso includo una cronologia dei miei post (  qui c'è un esempio troppo lungo da includere, però). Non so se una cosa del genere sia utile, ma potrebbe aiutare gli altri a scoprire quali trucchi sono stati usati per farla breve. Anche se ho anche una storia SVN per quello.
Joey,

8

fortran 77 - 484 caratteri

      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

Non ha senso fornire una versione "non illustrata". E nota che il markdown non va d'accordo con i requisiti di rientro.

Ho provato fortran a causa dell'inline per i loop forniti dalla writedichiarazione. Ovviamente aiutano ma non aggiungono abbastanza per uccidere il linguaggio della lingua. Potrebbe essere ridotto utilizzando input a forma libera.

convalida:

 $ 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
    +--------+ 
   /        /|
  /        / |
 +--------+  |
 |        |  |
 |        |  +
 |        | /
 |        |/
 +--------+ 

Per fortuna la specifica non dice quale dimensione dovrebbe apparire:

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

ma altre dimensioni dispari sono ragionevoli:

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

Interessante scelta della lingua :-). Bene, la taglia 1 non sembra troppo male. La mia soluzione genera un ciclo infinito. Diversi comportamenti di arrotondamento sono stati il ​​motivo per cui ho eliminato dimensioni dispari, se ricordo bene (e il limite superiore di 30 per adattarsi alla larghezza di 80 caratteri).
Joey,

1
@joey: lo faccio di tanto in tanto, e sono contento se sono meno di un fattore 10 in più rispetto al vincitore.
dmckee,

4

La mia soluzione, dato che è già stato picchiato a morte da Python:

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 ... lingue che ti permettono di "
stringere

Bene, è ancora molto dietro Ruby o Golfscript di Ventero - come al solito;)
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

Storia:

  • 01/03/2011 01:54 (427) Primo tentativo.
  • 2011-03-01 02:01 (342) def ed alcune altre cose che sono apparse spesso.
  • 01/03/2011 02:24 (283) Ancora di più defs.
  • 01/03/2011 02:42 (281) Qualunque altro defche salvi altri due byte.
  • 01/03/2011 03:01 (260) [ e ]hanno belle proprietà se usati come variabili :-). Grazie a KirarinSnow .
  • 01-03-2011 03:12 (246) Interruzioni di riga incorporate, usando un dict anziché numerose defs. Grazie ancora :-).
  • 01/03/2011 03:26 (237) Altro grazie a KirarinSnow .

3

Ruby 1.9, 172 165 162 caratteri

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

Rubino - 423 caratteri

Davvero non voglio condividere questo dato che è un conto così orribile, ma dal momento che ho scritto potrebbe anche.

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}

Probabilmente potrebbe essere ridotto di un po ', ma dubito che questo approccio alla forza bruta arriverà ovunque vicino a un numero decente di personaggi, quindi non posso essere disturbato.


1

PHP, 401 392 382 363 caratteri:

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

Inizialmente l'ho fatto per vedere quanto potevo riuscire a farlo in PHP, poiché sapevo che sarebbe stato piuttosto lungo. Sono sicuro che potrebbe essere ridotto, ma non molto considerando che PHP non ha molte scorciatoie.

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

Versione non registrata: http://codepad.viper-7.com/4D3kIA


L'ho appena modificato per leggere da stdin, mancava quello nella domanda. Non ha più bisogno della funzione per questo.
Kevin Brown,

Modificato il codice in modo che legga correttamente da stdin. Ho anche giocato a golf un po 'di più per ridurre le dimensioni.
Kevin Brown,

La linea diagonale in basso a destra non è presente e viene invece visualizzata una linea verticale offset. A meno che non stia facendo qualcosa di sbagliato nell'invocarlo, però.
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 o versioni successive, esegui con perl -E '<code here>'

Versione rispettata:

$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 caratteri

sub p {y / xS / + \ //; print; y / + \ // xS /} $ b = / 2; $ a = $ b; $ _ = "xx \ n"; s / x / x- --- / while ($ a -); fino a (/ ^ 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

L'idea di base è di fare tutto con sostituzioni regex. Poiché due dei personaggi utilizzati (+ e /) sono caratteri speciali e si presentano molto nelle regex, vale la pena usare altri personaggi e sostituirli per stampare.

Versione leggermente più leggibile:

# Subroutine per sostituire, stampare e non sostituire come descritto sopra
sub p {y / xS / + \ //; print; y / + \ // xS /}
# Leggi da stdin e imposta la riga iniziale
$ b = <> / 2; $ a = $ b; $ _ = "xx \ n";
s / x / x ---- / while ($ a--);
# Stampa la faccia superiore
fino a (/ ^ S /) {
  p;
  s / [xS] / S / g; # Primo giro: sinistra + -> /; i tempi successivi si spostano / lasciano
  s / -x / S | /; # Rilevante solo la prima volta intorno al loop
  y / - / / # Solo la prima volta rilevante intorno al loop
}
# Prepara e stampa la linea contenente la seconda linea orizzontale
s / (? = * S) / - / g;
y / S / x /;
p;
# Ora stampa (n-1) / 2 linee identiche
y / -x / | /;
p while (- $ b);
# Porta il bordo destro dentro
s /.$/ x /;
while (/ \ | /)
{
  p;
  s /..$/ S /
}
# Linea finale
y / | S / ++ - /;
p

In un certo senso sto barando usando $ b come contatore nel loop intermedio - potrei invece aggiungere spazi bianchi nel loop oltre $ ae quindi usare regex sostituisce anche per quel loop - ma permetterò quella leggera deviazione da una soluzione di pura regex.

Senza dubbio una persona spaventosa può trasformarlo in uno script sed molto più breve.


"Versione leggermente più leggibile" - Devo amare il fatto che Perl diventi leggermente più leggibile quando sono inclusi newline e spazi bianchi. :)
Steve,

@Steve, anche con i commenti devi conoscere un po 'di Perl per capirlo. Usare yper trnon è ovvio, e per quanto riguarda il modo in cui "while" può andare prima o dopo ...
Peter Taylor,

1

Lua, 294 302 292 byte

golfed:

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)

L'input viene fornito sul flusso di input standard. Questo non sembra funzionare qui.
Joey,

Puoi anche tralasciare il or 6dopo la read()chiamata, che salva quattro byte :-)
Joey

Hm, ora con il (...)non funziona più per me su Lua 5.1.4.
Joey,

1

Tela , 63 byte

╴»
±╵⁷/╋╴«3+⁷
-×+×║⌐1╴├╋;⁷├⁷±╋2⁷⁸⁸├⁷/╋12╴«├2⁷5×3+⁷±╵⁰2n{┤╴|*+∔╋

Provalo qui!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.