用ASCII艺术画一个立方体


32

任务描述:

在大致的橱柜投影中绘制ASCII艺术形式的立方体。

Monospaced fonts通常字符的宽度大约是宽度的两倍。由于输入的是垂直线的长度(不包括角),因此绘制的水平线的字符数是原来的两倍,因此生成的图像实际上大约是一个立方体。后退线的绘制长度是机柜投影所要求的一半。

用表示立方体的角,用+水平线表示,用-垂直线表示,用|对角线表示/

总结:设输入为n,则

  • 立方体的水平边缘用-2 n个字符组成,并由2  个n字符组成。
  • 立方体的垂直边缘绘制有n个字符|,并由n个字符组成。
  • 立方体的对角线边缘用n / 2个字符/组成,并由n / 2个字符组成。
  • 用绘制立方体的角+。如上所述,不计算边沿长度的角(也​​请参见下面的示例)。

输入:

输入,在标准输入给定,是一个正,偶数Ñ(2≤ Ñ ≤30),使该立方体的垂直线的长度。它后面是一个换行符。

输出:

输出是遵循上述规则的标准输出上的多维数据集。行尾的空白将被忽略。

样本输入1:

2

样本输出1:

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

样本输入2:

4

样本输出2:

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

ETA:我现在接受了最短的解决方案。当出现较短的答案时,我将更新接受的答案。

由于有人问我们参赛者的参赛作品有多长时间:

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

以及我们自己的解决方案(未与其他解决方案排名):

140 – Golfscript
172 – 红宝石
183 – PowerShell


您能否简单介绍一下您拥有的最佳解决方案?最小的有几个字符?
胡安(Juan)

@Juan:添加了请求的信息
Joey

1
足够有趣的是,C ++可以使用类似的图形作为“模拟文字”:hostilefork.com/2009/08/29/tweakinganalog-literals-humor
Rebmu博士2011年

@敌对:是的,那是一个很好的,如果有点邪恶;-)
Joey

Answers:


10

Golfscript-96个字符

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

大部分紧凑性来自积极地将几乎所有内容都存储到变量中(除非您包括用golfscript编写的内容)。

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

这里还有其他一些小技巧。

  1. 'LR''str'* -> 'LstrR'
  2. 由于我们需要反转最后一个数组中的行顺序,因此我们选择在生成文本之后而不是之前执行此操作。这样可以节省一个字符,因为'/'唯一的空格需要经过两个堆栈元素(@)而不是3(@ .. \)。

16

蟒- 248 243 230 227 191

有点混乱,但它基本上逐行打印多维数据集(使用字符串缓冲区)。

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

感谢@marcog指出第一行,@ThomasO指出第二行,感谢@Juan使我意识到我可以合并行。


4
To save some more space change s=" ";p="+";b="|";f="/";n="\n" to s,p,b,f,n=" +|/\n".
Thomas O

1
One up vote is not enough. You've pushing me to improve my solution to limits that I thought impossible, thanks :D
Juan

:) now to see if better is 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

I'd like to note that I took some ideas from JPvdMerwe (Using a string to print once, and the one-liner for that I didn't know was correct syntax in Python).


Line 3 is missing a 2 at the end, which, unfortunately, pushes up the count to 256.
JPvdMerwe

@JPvdMerwe oops, thanks for catching that!
Juan

1
Maybe you can try caching the results in a string like I did and only print once?
JPvdMerwe

1
@Juan I think we should avoid keeping old copies in the post, unless the two versions are majorly different. They're viewable in the edit history if someone wants to read it.
marcog

2
As for the FAQ: I often include a length history in my posts ( here was an example that got too long to include, though). Don't know whether such a thing is helpful but it may help others to discover what tricks were used to keep it short. Although I also have a SVN history for that as well.
Joey

8

fortran 77 -- 484 characters

      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

No real point in providing a "unobsfucated" version. And note that markdown doesn't get along well with the indent requirements.

I tried fortran because of the inline for loops provided by the write statement. Obviously they help but don't add up to enough to kill the wordiess of the language. It could be reduce by using freeform input.

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

Thankfully the spec doesn't say what size one should look like:

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

but other odd sizes are reasonable:

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

Interesting choice of language :-). Well, size 1 doesn't look too bad. My solution throws up an endless loop. Different rounding behaviors were the reason to throw out odd sizes, if I remember correctly (and the upper bound of 30 for fitting into 80 characters width).
Joey

1
@joey: I do fortran from time to time, and am happy if I'm less than a factor of 10 longer than the winner.
dmckee

4

My own solution, since it has already been beaten to death by 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...languages that let you "multiple" strings by a scalar help for this...
dmckee

Well, it's still far behind Ventero's Ruby or Golfscript – as usual ;)
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

History:

  • 2011-03-01 01:54 (427) First attempt.
  • 2011-03-01 02:01 (342) defed a few more things that appeared often.
  • 2011-03-01 02:24 (283) Even more defs.
  • 2011-03-01 02:42 (281) Aaand another def that saves two more bytes.
  • 2011-03-01 03:01 (260) [ and ] have nice properties when used as variables :-). Thanks to KirarinSnow.
  • 2011-03-01 03:12 (246) Inline line breaks, using a dict instead of numerous defs. Thansk again :-).
  • 2011-03-01 03:26 (237) More thanks to KirarinSnow.

3

Ruby 1.9, 172 165 162 characters

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 characters

Really don't want to share this since it's such a horrible count, but since I've written it might as well.

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}

Could probably be reduced by quite a bit but I doubt this brute-force approach is going to come anywhere near a decent number of characters so I can't be bothered.


1

PHP, 401 392 382 363 characters:

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

I originally did this to see how short I could manage to do this in PHP, as I knew that it would be pretty long. I'm sure it could be reduced, but not by much considering PHP doesn't have many shortcuts.

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

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


Just modified it to read from stdin, missed that in the question. Doesn't need the function anymore because of that.
Kevin Brown

Modified the code so that it reads from stdin correctly. Also golfed it a little more to reduce the size.
Kevin Brown

The lower right diagonal line isn't there and instead an offset vertical line appears. Unless I'm doing something wrong in invoking it, though.
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 or later, run with 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 chars

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

The basic idea is to do everything with regex substitutions. Because two of the characters used (+ and /) are special characters and turn up a lot in the regexes, it's worthwhile using other characters and substituting them to print.

Slightly more legible version:

# Subroutine to substitute, print, and unsubstitute as described above
sub p{y/xS/+\//;print;y/+\//xS/}
# Read from stdin and set up the initial line
$b=<>/2;$a=$b;$_=" xx\n";
s/ x/  x----/ while($a--);
# Print the top face
until(/^S/) {
  p;
  s/ [xS]/S /g; # First time round: left + -> /; subsequent times move / left
  s/-x/S|/; # Only relevant first time round the loop
  y/-/ / # Only relevant first time round the loop
}
# Prepare and print the line containing second horizontal line
s/ (?= *S)/-/g;
y/S/x/;
p;
# Now print (n-1)/2 identical lines
y/-x/ |/;
p while (--$b);
# Bring the right edge in
s/.$/x/;
while(/ \|/)
{
  p;
  s/..$/S/
}
# Final line
y/|S /++-/;
p

In a sense I'm cheating by using $b as a counter in the intermediate loop - I could instead append whitespace in the loop over $a and then use regex replaces for that loop too - but I'm going to allow that slight deviation from a pure-regex solution.

No doubt some scary person can turn this into a much shorter sed script.


"Slightly more legible version" - gotta love that Perl only becomes slightly more readable when newlines and whitespace are included. :)
Steve

@Steve, even with the comments you have to know a bit of Perl to understand it. Using y for tr isn't obvious, and as for the way "while" can go before or after...
Peter Taylor

1

Lua, 294 302 292 bytes

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)

Input is given on the standard input stream. This doesn't seem to work here.
Joey

You can also leave out the or 6 after the read() call, which saves four bytes :-)
Joey

Hm, now with the (...) it doesn't work for me anymore on Lua 5.1.4.
Joey

1

Canvas, 63 bytes

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

Try it here!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.