Dessiner un cube en art ASCII

32

Description de la tâche:

Dessinez un cube dans l'art ASCII dans à peu près une projection d'armoire.

Monospaced fontsont souvent des caractères environ deux fois plus hauts que larges. Étant donné que l'entrée correspond à la longueur des lignes verticales (à l'exclusion des coins), les lignes horizontales sont dessinées avec deux fois plus de caractères, de sorte que l'image résultante est en gros un cube. Les lignes de recul sont dessinées à la moitié de la longueur, comme le prescrit une projection de l'armoire.

Les coins du cube sont représentés par +, les lignes horizontales par -, les lignes verticales par |et les diagonales utilisent /.

Résumant: que l'entrée soit n , puis

  • Un bord horizontal du cube est dessiné avec -et se compose de 2  n caractères.
  • Un bord vertical du cube est dessiné avec |et se compose de n caractères.
  • Un bord diagonal du cube est dessiné avec /et se compose de n / 2 caractères.
  • Les coins du cube sont dessinés avec +. Les coins ne sont pas comptés pour la longueur d'un bord comme détaillé ci-dessus (voir également les exemples ci-dessous).

Contribution:

L'entrée, donnée sur l'entrée standard, est un seul nombre pair positif n (2 ≤ n ≤ 30) qui donne la longueur des lignes verticales du cube. Elle est suivie d'un saut de ligne unique.

Sortie:

La sortie est un cube sur la sortie standard suivant les règles ci-dessus. Les espaces en fin de ligne sur les lignes sont ignorés.

Exemple d'entrée 1:

2

Exemple de sortie 1:

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

Exemple d'entrée 2:

4

Exemple de sortie 2:

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

ETA: J'ai maintenant accepté la solution la plus courte. Je mettrai à jour la réponse acceptée lorsqu'une réponse plus courte arrivera.

Puisque certaines personnes ont demandé combien de temps les inscriptions de nos candidats étaient:

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

Ainsi que nos propres solutions (non classées parmi les autres):

140 - Golfscript
172 - Ruby
183 - PowerShell

Joey
la source
pouvez-vous nous parler un peu des meilleures solutions que vous aviez? Combien de caractères possédait le plus petit?
Juan
@Juan: Ajout des informations demandées
Joey
1
Curieusement, C ++ peut utiliser des dessins similaires en tant que "littéraux analogiques": hostilefork.com/2009/08/29/tweakinganalog-literals-humor
Dr. Rebmu
@Hostile: Oui, celui-là était sympa, bien qu'un peu mal ;-)
Joey

Réponses:

10

Golfscript - 96 caractères

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

La plupart de la compacité vient du stockage agressif de presque tout dans une variable (sauf si vous incluez l'écriture dans golfscript).

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

Quelques autres petites astuces ici.

  1. 'LR''str'*-> 'LstrR'.
  2. Comme nous devons inverser l'ordre des lignes dans le dernier tableau, nous choisissons de le faire après avoir généré le texte plutôt qu'avant. Cela nous permet de sauvegarder un caractère car les espaces avant le '/'seul doivent dépasser deux éléments de pile ( @) au lieu de 3 ( @ .. \).
Nabb
la source
16

Python - 248 243 230 227 191

Légèrement désordonné mais il imprime essentiellement le cube ligne par ligne (en utilisant un tampon de chaîne).

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

Merci à @marcog, pour avoir souligné la première ligne, @ThomasO pour avoir souligné la deuxième ligne et à @Juan pour m'avoir fait réaliser que je peux combiner des lignes.

JPvdMerwe
la source
4
Pour économiser un peu plus d'espace, passez s=" ";p="+";b="|";f="/";n="\n"à s,p,b,f,n=" +|/\n".
Thomas O
1
Un vote positif ne suffit pas. Vous m'avez poussé à améliorer ma solution dans des limites que je pensais impossibles, merci: D
Juan
:) maintenant pour voir si mieux est possible.
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

Je voudrais noter que j'ai pris quelques idées de JPvdMerwe (Utiliser une chaîne pour imprimer une fois, et la ligne unique pour laquelle je ne savais pas était la syntaxe correcte en Python).

Juan
la source
La ligne 3 manque un 2 à la fin, ce qui, malheureusement, fait monter le nombre à 256.
JPvdMerwe
@JPvdMerwe oups, merci d'avoir attrapé ça!
Juan
1
Peut-être pouvez-vous essayer de mettre en cache les résultats dans une chaîne comme je l'ai fait et n'imprimer qu'une seule fois?
JPvdMerwe
1
@Juan Je pense que nous devrions éviter de conserver les anciennes copies dans la poste, à moins que les deux versions ne soient très différentes. Ils sont visibles dans l'historique des modifications si quelqu'un veut le lire.
marcog
2
Quant à la FAQ: j'inclus souvent un historique de longueur dans mes messages (  voici un exemple qui est devenu trop long à inclure, cependant). Je ne sais pas si une telle chose est utile, mais elle peut aider les autres à découvrir quelles astuces ont été utilisées pour la garder courte. Bien que j'aie également une histoire SVN pour cela.
Joey
8

fortran 77 - 484 caractères

      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

Inutile de proposer une version "non obsolète". Et notez que la démarque ne correspond pas bien aux exigences de retrait.

J'ai essayé fortran en raison de la présence de boucles en ligne fournies par la writedéclaration. De toute évidence, ils aident, mais ne suffisent pas à tuer les mots de la langue. Il pourrait être réduit en utilisant une entrée de forme libre.

Validation:

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

Heureusement, la spécification ne dit pas à quelle taille doit ressembler:

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

mais d'autres tailles impaires sont raisonnables:

 $ echo 3 | ./a.out
   +------+ 
  /      /|
 +------+ |
 |      | +
 |      |/
 +------+ 
dmckee
la source
Choix intéressant de langue :-). Eh bien, la taille 1 n'a pas l'air trop mal. Ma solution lance une boucle sans fin. Différents comportements d'arrondi étaient la raison de jeter des tailles impaires, si je me souviens bien (et la limite supérieure de 30 pour s'adapter à une largeur de 80 caractères).
Joey
1
@joey: Je fais fortran de temps en temps, et je suis content si je suis moins d'un facteur 10 de plus que le vainqueur.
dmckee
4

Ma propre solution, car elle a déjà été battue à mort par 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
Joey
la source
Ah ... des langues qui vous permettent de "plusieurs" chaînes grâce à une aide scalaire pour cela ...
dmckee
Eh bien, c'est toujours loin derrière Rubis ou Golfscript de Ventero - comme d'habitude;)
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

Histoire:

  • 2011-03-01 01:54 (427) Première tentative.
  • 2011-03-01 02:01 (342) def ed quelques autres choses qui sont apparues souvent.
  • 2011-03-01 02:24 (283) Encore plus l' defart.
  • 2011-03-01 02:42 (281) Et un autre defqui enregistre deux octets supplémentaires.
  • 2011-03-01 03:01 (260) [ et ]ont de belles propriétés lorsqu'elles sont utilisées comme variables :-). Merci à KirarinSnow .
  • 2011-03-01 03:12 (246) Sauts de ligne en ligne, en utilisant un dict au lieu de nombreux defs. Merci encore :-).
  • 2011-03-01 03:26 (237) Encore merci à KirarinSnow .
Joey
la source
3

Ruby 1.9, 172 165 162 caractères

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
Ventero
la source
1

Ruby - 423 caractères

Je ne veux vraiment pas partager cela, car c'est un compte horrible, mais depuis que je l'ai écrit, cela pourrait aussi bien.

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}

Pourrait probablement être réduit d'un peu, mais je doute que cette approche par force brute puisse se rapprocher d'un nombre décent de caractères, donc je ne peux pas être dérangé.

Nemo157
la source
1

PHP, 401 392 382 363 caractères:

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

À l'origine, j'ai fait cela pour voir combien de temps je pouvais réussir à le faire en PHP, car je savais que ce serait assez long. Je suis sûr que cela pourrait être réduit, mais pas beaucoup étant donné que PHP n'a pas beaucoup de raccourcis.

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

Version non golfée: http://codepad.viper-7.com/4D3kIA

Kevin Brown
la source
Je viens de le modifier pour lire à partir de stdin, je l'ai manqué dans la question. N'a plus besoin de la fonction à cause de cela.
Kevin Brown
Modification du code pour qu'il lit correctement depuis stdin. Il a également joué un peu plus pour réduire la taille.
Kevin Brown
La ligne diagonale inférieure droite n'est pas là et à la place une ligne verticale décalée apparaît. À moins que je ne fasse quelque chose de mal en l'invoquant, cependant.
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 ou version ultérieure, exécuté avec perl -E '<code here>'

Version modifiée:

$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$_"
JB
la source
1

Perl, 269 ​​269 262 256 245 244 237 226 228 224 217 caractères

sub p {y / xS / + \ //; print; y / + \ // xS /} $ b = / 2; $ a = $ b; $ _ = "xx \ n"; s / x / x- --- / while ($ a -); jusqu'à (/ ^ 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'idée de base est de tout faire avec des substitutions d'expression régulière. Étant donné que deux des caractères utilisés (+ et /) sont des caractères spéciaux et apparaissent souvent dans les expressions régulières, il vaut la peine d'utiliser d'autres caractères et de les remplacer pour imprimer.

Version légèrement plus lisible:

# Sous-routine pour remplacer, imprimer et remplacer comme décrit ci-dessus
sub p {y / xS / + \ //; print; y / + \ // xS /}
# Lire depuis stdin et configurer la ligne initiale
$ b = <> / 2; $ a = $ b; $ _ = "xx \ n";
s / x / x ---- / while ($ a--);
# Imprimer la face supérieure
jusqu'à (/ ^ S /) {
  p;
  s / [xS] / S / g; # Premier tour: gauche + -> /; les heures suivantes se déplacent / à gauche
  s / -x / S | /; # Uniquement pertinent la première fois dans la boucle
  y / - / / # Uniquement pertinent pour la première fois dans la boucle
}
# Préparez et imprimez la ligne contenant la deuxième ligne horizontale
s / (? = * S) / - / g;
y / S / x /;
p;
# Imprime maintenant (n-1) / 2 lignes identiques
y / -x / | /;
p tandis que (- $ b);
# Apportez le bord droit
s /.$/ x /;
tandis que (/ \ | /)
{
  p;
  s /..$/ S /
}
# Ligne finale
y / | S / ++ - /;
p

Dans un sens, je triche en utilisant $ b comme compteur dans la boucle intermédiaire - je pourrais plutôt ajouter des espaces dans la boucle sur $ a puis utiliser des remplacements regex pour cette boucle aussi - mais je vais autoriser cette légère déviation à partir d'une solution pure-regex.

Sans aucun doute, une personne effrayante peut transformer cela en un script sed beaucoup plus court.

Peter Taylor
la source
"Version légèrement plus lisible" - je dois aimer que Perl ne devienne légèrement plus lisible lorsque des nouvelles lignes et des espaces sont inclus. :)
Steve
@Steve, même avec les commentaires, il faut connaître un peu Perl pour le comprendre. Utiliser yfor trn'est pas évident, et quant à la façon dont "while" peut aller avant ou après ...
Peter Taylor
1

Lua, 294 302 292 octets

Golfé:

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)
Fuite, nonne
la source
L'entrée est donnée sur le flux d'entrée standard. Cela ne semble pas fonctionner ici.
Joey
Vous pouvez également laisser de côté l' or 6après- read()appel, ce qui économise quatre octets :-)
Joey
Hm, maintenant avec (...)ça ça ne marche plus pour moi sur Lua 5.1.4.
Joey
1

Toile , 63 octets

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

Essayez-le ici!

dzaima
la source