Desenhando um cubo na arte ASCII

32

Descrição da tarefa:

Desenhe um cubo na arte ASCII em aproximadamente uma projeção de gabinete.

Monospaced fontsgeralmente têm caracteres com o dobro da largura. Como a entrada é o comprimento das linhas verticais (excluindo os cantos), as linhas horizontais são desenhadas com o dobro de caracteres, para que a imagem resultante seja realmente um cubo. As linhas recuadas são desenhadas na metade do comprimento, conforme determinado por uma projeção do gabinete.

Os cantos do cubo são representados por +, linhas horizontais por -, linhas verticais por |e diagonais /.

Resumindo: Seja a entrada n , então

  • Uma aresta horizontal do cubo é desenhada com -e consiste em 2  n caracteres.
  • Uma aresta vertical do cubo é desenhada com |e consiste em n caracteres.
  • Uma aresta diagonal do cubo é desenhada com /e consiste em n / 2 caracteres.
  • Os cantos do cubo são desenhados com +. Os cantos não são contados pelo comprimento de uma aresta, conforme detalhado acima (veja também os exemplos abaixo).

Entrada:

A entrada, dada na entrada padrão, é um único número positivo positivo n (2 ≤ n ≤ 30) que fornece o comprimento das linhas verticais do cubo. É seguido por uma única quebra de linha.

Saída:

A saída é um cubo na saída padrão, seguindo as regras acima. O espaço em branco à direita nas linhas é ignorado.

Entrada de amostra 1:

2

Saída de amostra 1:

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

Entrada de amostra 2:

4

Saída de amostra 2:

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

ETA: Agora aceitei a solução mais curta. Atualizarei a resposta aceita quando surgir uma resposta mais curta.

Como algumas pessoas perguntaram quanto tempo duraram as inscrições de nossos concorrentes:

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

Assim como nossas próprias soluções (não classificadas com as outras):

140 - Golfscript
172 - Ruby
183 - PowerShell

Joey
fonte
você pode contar um pouco sobre as melhores soluções que você teve? Quantos caracteres o menor tinha?
Juan
@ Juan: Adicionadas as informações solicitadas
Joey
11
Surpreendentemente suficiente, C ++ podem utilizar desenhos semelhantes como "literais analógicos": hostilefork.com/2009/08/29/tweakinganalog-literals-humor
Dr. Rebmu
@Hostile: Sim, isso era bom, se um mal pouco ;-)
Joey

Respostas:

10

Golfscript - 96 caracteres

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

A maior parte da compacidade vem do armazenamento agressivo de quase tudo em uma variável (a menos que você inclua ser escrito em golfscript).

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

Alguns outros pequenos truques aqui.

  1. 'LR''str'*-> 'LstrR'.
  2. Como precisamos reverter a ordem das linhas na última matriz, optamos por fazer isso depois de gerar o texto em vez de antes. Isso nos permite salvar um caractere, porque os espaços anteriores ao '/'único precisam passar por dois elementos da pilha ( @) em vez de 3 ( @ .. \).
Nabb
fonte
16

Python - 248 243 230 227 191

Um pouco confuso, mas basicamente imprime o cubo linha por linha (usando um buffer de seqüência de caracteres).

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

Obrigado a @marcog, por apontar a primeira linha, a @ThomasO, por apontar a segunda linha e a @Juan, por me fazer perceber que posso combinar linhas.

JPvdMerwe
fonte
4
Para economizar mais espaço, mude s=" ";p="+";b="|";f="/";n="\n"para s,p,b,f,n=" +|/\n".
Thomas O
11
Um voto positivo não é suficiente. Você me empurrando para melhorar a minha solução para limites que eu achava impossível, graças: D
Juan
:) agora para ver se é melhor possível.
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

Gostaria de observar que peguei algumas idéias do JPvdMerwe (usando uma string para imprimir uma vez, e a linha única que eu não sabia que era a sintaxe correta no Python).

Juan
fonte
Linha 3 está faltando a 2 no final, o que, infelizmente, empurra-se a contagem a 256.
JPvdMerwe
@JPvdMerwe oops, obrigado por assistir!
Juan
11
Talvez você possa tentar armazenar em cache os resultados em uma string como eu fiz e imprimir apenas uma vez?
precisa saber é o seguinte
11
@ Juan Acho que devemos evitar manter cópias antigas no post, a menos que as duas versões sejam muito diferentes. Eles podem ser visualizados no histórico de edições, se alguém quiser ler.
marcog 29/01
2
Quanto às perguntas frequentes: muitas vezes eu incluo um histórico de comprimento em minhas postagens (  aqui estava um exemplo que demorou muito para incluir). Não sei se isso é útil, mas pode ajudar outras pessoas a descobrir quais truques foram usados ​​para mantê-lo curto. Embora eu também tenha uma história SVN para isso também.
Joey
8

fortran 77 - 484 caracteres

      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

Não faz sentido fornecer uma versão "não observada". E observe que a redução não se dá bem com os requisitos de recuo.

Tentei o fortran por causa dos inline para loops fornecidos pela writedeclaração. Obviamente, eles ajudam, mas não são suficientes para matar a palavra da linguagem. Pode ser reduzido usando a entrada de forma livre.

Validação:

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

Felizmente, a especificação não diz qual o tamanho que deve ser:

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

mas outros tamanhos ímpares são razoáveis:

 $ echo 3 | ./a.out
   +------+ 
  /      /|
 +------+ |
 |      | +
 |      |/
 +------+ 
dmckee
fonte
Escolha interessante do idioma :-). Bem, o tamanho 1 não parece muito ruim. Minha solução gera um loop sem fim. Comportamentos de arredondamento diferentes foram a razão para a remoção de tamanhos ímpares, se bem me lembro (e o limite superior de 30 para caber na largura de 80 caracteres).
Joey
11
@ joey: eu forro de vez em quando e fico feliz se eu tiver menos de um fator de 10 a mais que o vencedor.
precisa saber é o seguinte
4

Minha própria solução, uma vez que já foi derrotada pelo 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
fonte
Ah ... idiomas que permitem "várias" seqüências de caracteres por uma ajuda escalar para isso ...
dmckee
Bem, ainda é muito atrás Ruby ou Golfscript de Ventero - como de costume;)
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

História:

  • 2011-03-01 01:54 (427) Primeira tentativa.
  • 2011-03-01 02:01 (342) def ed mais algumas coisas que apareciam com freqüência.
  • 2011-03-01 02:24 (283) Ainda mais defs.
  • 2011-03-01 02:42 (281) Um outro defque salva mais dois bytes.
  • 2011-03-01 03:01 (260) [ e ]possui boas propriedades quando usadas como variáveis ​​:-). Graças ao KirarinSnow .
  • 2011-03-01 03:12 (246) Quebras de linha em linha, usando um ditado em vez de numerosos defs. Thansk novamente :-).
  • 2011-03-01 03:26 (237) Mais graças à KirarinSnow .
Joey
fonte
3

Ruby 1.9, 172 165 162 caracteres

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
fonte
1

Ruby - 423 caracteres

Realmente não quero compartilhar isso, pois é uma contagem tão horrível, mas desde que eu escrevi, isso também pode acontecer.

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}

Provavelmente poderia ser reduzido um pouco, mas duvido que essa abordagem de força bruta chegue perto de um número decente de caracteres, então não posso me incomodar.

Nemo157
fonte
1

PHP, 401 392 382 363 caracteres:

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

Originalmente, fiz isso para ver quão curto eu conseguia fazer isso em PHP, pois sabia que seria muito longo. Tenho certeza de que poderia ser reduzido, mas não considerando muito o PHP não possui muitos atalhos.

Validação:
http://codepad.viper-7.com/ftYYz9.php53

Versão semolfo: http://codepad.viper-7.com/4D3kIA

Kevin Brown
fonte
Apenas modifiquei para ler a partir de stdin, perdi isso na pergunta. Não precisa mais da função por causa disso.
Kevin Brown
Modificado o código para que ele leia do stdin corretamente. Também jogou um pouco mais para reduzir o tamanho.
Kevin Brown
A linha diagonal inferior direita não está lá e uma linha vertical de deslocamento é exibida. A menos que eu esteja fazendo algo errado ao invocá-lo, no entanto.
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 posterior, execute com perl -E '<code here>'

Versão substituída:

$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
fonte
1

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

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

A idéia básica é fazer tudo com substituições regex. Como dois dos caracteres usados ​​(+ e /) são caracteres especiais e aparecem muito nas expressões regulares, vale a pena usar outros caracteres e substituí-los para imprimir.

Versão um pouco mais legível:

# Sub-rotina para substituir, imprimir e substituir como descrito acima
sub p {y / xS / + \ //; impressão; y / + \ // xS /}
# Leia do stdin e configure a linha inicial
$ b = <> / 2; $ a = $ b; $ _ = "xx \ n";
s / x / x ---- / while ($ a--);
# Imprima a face superior
até (/ ^ S /) {
  p;
  s / [xS] / S / g; # Primeira rodada: esquerda + -> /; tempos subsequentes mover / esquerda
  s / -x / S | /; # Apenas a primeira vez relevante relevante no ciclo
  y / - / / # Apenas primeira vez relevante relevante no ciclo
}
# Prepare e imprima a linha que contém a segunda linha horizontal
s / (? = * S) / - / g;
y / S / x /;
p;
# Agora imprima (n-1) / 2 linhas idênticas
y / -x / | /;
p while (- $ b);
# Traga a borda direita para dentro
s /.$/ x /;
while (/ \ | /)
{
  p;
  s /..$/ S /
}
# Linha final
y / | S / ++ - /;
p

Em certo sentido, estou trapaceando usando $ b como contador no loop intermediário - eu poderia acrescentar espaço em branco no loop acima de $ a e usar substituições regex para esse loop também - mas vou permitir esse pequeno desvio de uma solução de regex puro.

Sem dúvida, uma pessoa assustadora pode transformar isso em um script sed muito mais curto.

Peter Taylor
fonte
"Versão ligeiramente mais legível" - adoro que o Perl só se torne um pouco mais legível quando novas linhas e espaços em branco forem incluídos. :)
Steve
@ Steve, mesmo com os comentários que você precisa conhecer um pouco de Perl para entender. Usando ypara trnão é óbvia, e quanto à maneira "enquanto" pode ir antes ou depois ...
Peter Taylor
1

Lua, 294 302 292 bytes

Golfe:

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)
Freira Furada
fonte
A entrada é fornecida no fluxo de entrada padrão. Isso não parece funcionar aqui.
Joey
Você também pode deixar o or 6após a read()chamada, o que economiza quatro bytes :-)
Joey
Hm, agora com o (...)que não funciona mais para mim no Lua 5.1.4.
Joey
1

Tela , 63 bytes

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

Experimente aqui!

dzaima
fonte