ASCIIアートでキューブを描く


32

タスクの説明:

ほぼキャビネットの投影でASCIIアートの立方体を描きます。

Monospaced fonts多くの場合、幅の約2倍の文字があります。入力は垂直線(角を除く)の長さなので、水平線は2倍の文字で描画されるため、結果のイメージは実際にはほぼ立方体になります。引き込み線は、キャビネットの投影で義務付けられている長さの半分で描画されます。

立方体の角はによって表され+、水平線は-、垂直線は|、対角線はを使用します/

要約:入力をnとし、

  • 立方体の水平方向のエッジは、-2 n個の文字で描かれ、2 n個の文字で構成さ  れています。
  • 立方体の垂直エッジは、n文字|で描かれ、n文字で構成されます。
  • 立方体の斜めのエッジは、n / 2文字/で描かれ、構成されます。
  • 立方体の角はで描画され+ます。上記で説明したように、角はエッジの長さにはカウントされません(以下の例を参照してください)。

入力:

標準入力に与えられた入力は、単一の正、偶数であるN(2≤ Nキューブの垂直線の長さを与える≤30)。その後に単一の改行が続きます。

出力:

出力は、上記の規則に従った標準出力のキューブです。行の末尾の空白は無視されます。

サンプル入力1:

2

サンプル出力1:

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

サンプル入力2:

4

サンプル出力2:

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

ETA:最短の解決策を受け入れました。短い回答が来たら、受け入れられた回答を更新します。

一部の人々は、私たちの出場者のエントリーがどれくらいであったか尋ねたので:

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

独自のソリューション(他のソリューションとはランク付けされていません):

140 – Golfscript
172 – Ruby
183 – PowerShell


あなたが持っていた最高のソリューションについて少し教えていただけますか?最小の文字数はいくつですか?
フアン

@Juan:要求された情報を追加
Joey

1
面白いことに、C ++は「アナログリテラル」として同様の図面を使用できます。hostilefork.com
Dr. Rebmu

@Hostile:うん、それは少し悪かったならいいね;
ジョーイ

回答:


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()ではなく'/'2つのスタック要素(@)を通過する必要があるため、1文字を保存できます@ .. \

16

Pythonの- 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、2番目の行を指摘してくれた@ThomasO、そして私が行を結合できることに気づかせてくれた@Juanに感謝します。


4
さらにスペースを節約するには、に変更s=" ";p="+";b="|";f="/";n="\n"s,p,b,f,n=" +|/\n"ます。
トーマスO

1
1つの賛成票では十分ではありません。D:あなたは、私が不可能と思っていることの限界に私の解決策を改善するためのおかげで、私を押しました
フアン・

:)今、より良いことが可能かどうかを確認します。
-JPvdMerwe

10

パイソン-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

JPvdMerweからいくつかのアイデアを取りました(文字列を使用して1回印刷しますが、そのためのワンライナーはPythonの正しい構文でした)。


行3の最後に2が欠落しているため、残念ながらカウントが256に押し上げられます。
JPvdMerwe11年

@JPvdMerweおっと、キャッチしてくれてありがとう!
フアン

1
たぶん、私がやったように結果を文字列にキャッシュして、一度だけ印刷することができますか?
-JPvdMerwe

1
@Juan 2つのバージョンが大きく異なる場合を除き、古いコピーを投稿に残さないようにする必要があると思います。誰かが読みたい場合、編集履歴で見ることができます。
マーコグ

2
よくある質問について:私はしばしば投稿に長い履歴を含めます(ただし、ここに含めるには長  すぎた例がありました)。そのようなことが役立つかどうかはわかりませんが、他の人がそれを短くするためにどのようなトリックが使用されたかを発見するのに役立つかもしれません。私もそのためのSVNの歴史を持っていますが。
ジョーイ

8

fortran 77-484文字

      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

「難読化されていない」バージョンを提供することには実質的な意味はありません。また、マークダウンはインデントの要件をうまく満たしていないことに注意してください。

writeステートメントによって提供されたインラインforループのために、Fortranを試しました。明らかに、彼らは助けますが、言語の言葉遣いを殺すのに十分に追加しません。自由形式の入力を使用することで削減できます。

検証:

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

ありがたいことに、仕様ではサイズがどのように見えるべきかについては言及していません。

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

しかし、他の奇妙なサイズは合理的です:

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

言語の興味深い選択:-)。さて、サイズ1はそれほど悪くはありません。私のソリューションは無限ループを投げます。私が正しく覚えていれば、異なる丸め動作が奇数サイズを捨てる理由でした(そして、80文字幅に適合するための30の上限)。
ジョーイ

1
@joey:私は時々トラントランをやっていますが、勝者よりも10倍も長ければ幸いです。
dmckee

4

私自身の解決策、それは既に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

ああ...このためのスカラーヘルプによって「複数の」文字列を許可する言語
...- dmckee

まあ、それはまだVenteroのRubyまたはGolfscriptの背後にあります
ジョーイ

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

歴史:

  • 2011-03-01 01:54 (427)最初の試行。
  • 2011-03-01 02:01 (342) def頻繁に登場するものをいくつか追加しました。
  • 2011-03-01午前2時24分(283)さらにdef、S。
  • 2011-03-01 02:42 (281)もう1 defつ、さらに2バイトを節約します。
  • 2011-03-01 03:01 (260) [そして]、変数として使用する場合は素晴らしいプロパティがあります:-)。KirarinSnowに感謝します
  • 2011-03-01 03:12 (246)多数defのsの代わりにdictを使用したインライン改行。もう一度ありがとう:-)。
  • 2011-03-01 03:26 (237)KirarinSnowに感謝します

3

Ruby 1.9、 172 165 162文字

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

ルビー-423文字

本当に恐ろしいことなので、これを共有したくありません。

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}

おそらくかなり減らすことができますが、このブルートフォースアプローチはかなりの数のキャラクターの近くに来るので、気にすることはできません。


1

PHP、401 392 382 363文字:

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

もともとこれは、かなり長くなることがわかっていたので、PHPでこれを実行できる時間を確認するために行ったものです。削減できると確信していますが、PHPに多くのショートカットがないことをあまり考慮していません。

検証:
http:

//codepad.viper-7.com/ftYYz9.php53 Ungolfedバージョン:http ://codepad.viper-7.com/4D3kIA


stdinから読み取るように変更しただけで、質問でそれを見逃しました。そのため、関数はもう必要ありません。
ケビンブラウン

stdinから正しく読み取るようにコードを変更しました。また、サイズを小さくするためにもう少しゴルフをしました。
ケビンブラウン

右下の対角線は存在せず、代わりにオフセットの垂直線が表示されます。ただし、呼び出しで何か間違ったことをしていない限り。
ジョーイ

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以降、で実行 perl -E '<code here>'

再配置されたバージョン:

$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文字

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

基本的な考え方は、すべてを正規表現で置換することです。使用される2つの文字(+と/)は特殊文字であり、正規表現で多く使用されるため、他の文字を使用して印刷に置き換えることは価値があります。

少し読みやすいバージョン:

#上記のように置換、印刷、および置換解除するサブルーチン
sub p {y / xS / + \ //; print; y / + \ // xS /}
#stdinから読み取り、初期行を設定します
$ b = <> / 2; $ a = $ b; $ _ = "xx \ n";
s / x / x ---- / while($ a--);
#上面を印刷
until(/ ^ S /){
  p;
  s / [xS] / S / g; #最初のラウンド:左+-> /; 次の時間は移動/左
  s / -x / S | /; #関連する初回のみのループ
  y /-/ /#関連する最初のループのみ
}
#2番目の水平線を含む行を準備して印刷する
s /(?= * S)/-/ g;
y / S / x /;
p;
#(n-1)/ 2個の同一行を印刷する
y / -x / | /;
p while(-$ b);
#右端を持ち込む
s /.$/ x /;
while(/ \ | /)
{
  p;
  s /..$/ S /
}
#最終行
y / | S / ++-/;
p

ある意味で、中間ループのカウンターとして$ bを使用して不正行為をしています-代わりにループに空白を追加し、そのループにも正規表現の置換を使用することができます-しかし、私はそのわずかな逸脱を許可します純粋な正規表現ソリューションから。

恐ろしい人がこれをはるかに短いsedスクリプトに変えることは間違いないでしょう。


「やや読みやすいバージョン」-改行と空白が含まれている場合、Perlが少しだけ読みやすくなることを愛する必要があります。:)
スティーブ

@Steve、コメントがあっても、それを理解するにはPerlを少し知っていなければなりません。使用するyためにはtr明白ではない、と前に行くことができる「ながら」の方法についてなどまたは後に...
ピーター・テイラー

1

LUA、294の 302 292バイト

ゴルフ:

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)

ゴルフをしていない:

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)

入力は標準入力ストリームで提供されます。ここではうまくいかないようです。
ジョーイ

また、4バイトを節約or 6するread()呼び出しの後を省くことができます:
ジョーイ

うーん、今では(...)Lua 5.1.4ではもう動作しません。
ジョーイ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.