22

イースター・コード・ゴルフのセッションにスパイラルより適切なものは何ですか?
まあ、ほとんどなんでもいいと思います。

チャレンジ

アスタリスク ('*') で構成された素敵な ASCII スパイラルを表示するための、文字数による最短コード。

R入力は、スパイラルの x サイズになる単一の数値です。もう一方の次元 (y) は常にR-2です。Rプログラムは、常に奇数で >= 5 であると想定できます。

いくつかの例:

Input
    7
Output

*******
*     *
* *** *
*   * *
***** *                   

Input
    9
Output

*********
*       *
* ***** *
* *   * *
* *** * *
*     * *
******* *

Input
   11
Output

***********
*         *
* ******* *
* *     * *
* * *** * *
* *   * * *
* ***** * *
*       * *
********* *

コード カウントには、入力/出力 (つまり、完全なプログラム) が含まれます。どの言語でも使用できます。

私の簡単に勝てる 303 文字の長い Python の例:

import sys;
d=int(sys.argv[1]);
a=[d*[' '] for i in range(d-2)];
r=[0,-1,0,1];
x=d-1;y=x-2;z=0;pz=d-2;v=2;
while d>2:
    while v>0:
        while pz>0:
            a[y][x]='*';
            pz-=1;
            if pz>0:
                x+=r[z];
                y+=r[(z+1)%4];
        z=(z+1)%4; pz=d; v-=1;
    v=2;d-=2;pz=d;
for w in a:
    print ''.join(w);

さぁ、スパイラルに突入…

4

10 に答える 10

15

Python (2.6): 156 文字

r=input()
def p(r,s):x=(i+1)/2;print "* "*x+("*" if~i%2 else" ")*(r-4*x)+" *"*x+s
for i in range(r/2):p(r,"")
for i in range((r-1)/2-1)[::-1]:p(r-2," *")

コメントありがとうございます。不要な空白を削除し、input() を使用しました。私はまだコマンドラインで引数を取るプログラムを好むので、176 文字で sys.argv をまだ使用しているバージョンがあります:

import sys
r=int(sys.argv[1])
def p(r,s):x=(i+1)/2;print "* "*x+("*" if~i%2 else" ")*(r-4*x)+" *"*x+s
for i in range(r/2):p(r,"")
for i in range((r-1)/2-1)[::-1]:p(r-2," *")

説明

らせんを取り、上と下の 2 つのほぼ等しい部分に切り刻みます。上の行は下の行よりも 1 行大きくなります。

***********
*         *
* ******* *
* *     * *
* * *** * *

* *   * * *
* ***** * *
*       * *
********* *

上部が美しく左右対称になっていることに注目してください。下部の右側に垂直線があることを確認しますが、それ以外は上部とよく似ています。上部の 2 行ごとのパターンに注意してください。両側の星の数が増えています。間にある各行は、中央の領域が星で埋められていることを除いて、前の行とまったく同じであることに注意してください。

関数 p(r,s) は、幅 r のらせんの上部の i 番目の行を出力し、末尾に接尾辞 s を付けます。明らかではないかもしれませんが、i はグローバル変数であることに注意してください。i が偶数の場合、行の中央がスペースで埋められ、それ以外の場合は星で埋められます。( ~i%2 は i%2==0 の効果を得るための厄介な方法でしたが、実際にはまったく必要ありません。単に "*" と " " を交換するだけだったからです。) 最初に上部を描画します。 i を増やしてスパイラルの行を描画し、次に i を減らして一番下の行を描画します。r を 2 減らし、接尾辞 " *" を付けて、右側の星の列を取得します。

于 2010-04-01T23:38:57.520 に答える
6

Java

328文字

class S{
public static void main(String[]a){
int n=Integer.parseInt(a[0]),i=n*(n-2)/2-1,j=0,t=2,k;
char[]c=new char[n*n];
java.util.Arrays.fill(c,' ');
int[]d={1,n,-1,-n};
if(n/2%2==0){j=2;i+=1+n;}
c[i]='*';
while(t<n){
for(k=0;k<t;k++)c[i+=d[j]]='*';
j=(j+1)%4;
if(j%2==0)t+=2;
}
for(i=0;i<n-2;i++)System.out.println(new String(c,i*n,n));
}
}

Pythonよりもわずか1/6多いので、それほど悪くはないようです;)

適切なインデントでも同じです。

class S {
    public static void main(String[] a) {
        int n = Integer.parseInt(a[0]), i = n * (n - 2) / 2 - 1, j = 0, t = 2, k;
        char[] c = new char[n * n];
        java.util.Arrays.fill(c, ' ');
        int[] d = { 1, n, -1, -n };
        if (n / 2 % 2 == 0) {
            j = 2;
            i += 1 + n;
        }
        c[i] = '*';
        while (t < n) {
            for (k = 0; k < t; k++)
                c[i += d[j]] = '*';
            j = (j + 1) % 4;
            if (j % 2 == 0)
                t += 2;
        }
        for (i = 0; i < n - 2; i++)
            System.out.println(new String(c, i * n, n));
    }
}
于 2010-04-01T22:43:22.820 に答える
6

F#、267 文字

多くの回答は空白から始めて*s を追加していますが、スターフィールドから始めて空白を追加する方が簡単かもしれないと思います。

let n=int(System.Console.ReadLine())-2
let mutable x,y,d,A=n,n,[|1;0;-1;0|],
 Array.init(n)(fun _->System.Text.StringBuilder(String.replicate(n+2)"*"))
for i=1 to n do for j=1 to(n-i+1)-i%2 do x<-x+d.[i%4];y<-y+d.[(i+1)%4];A.[y].[x]<-' '
Seq.iter(printfn"%O")A

私がどのようにゴルフをするかについての洞察を探している人のために、私は途中でたまたま多くの進歩を保存しました。すべてのプログラムが完全に正しいわけではありませんが、すべてのプログラムがより短い解決策に取り組んでいます。

まず、白の塗り方のパターンを探しました。

********* 
*       * 
* ***** * 
* *   * * 
* *** * * 
*     * * 
******* * 

********* 
*6543216* 
*1*****5* 
*2*212*4* 
*3***1*3* 
*41234*2* 
*******1* 

*********** 
*         * 
* ******* * 
* *     * * 
* * *** * * 
* *   * * * 
* ***** * * 
*       * * 
********* *

*********** 
*876543218* 
*1*******7* 
*2*43214*6* 
*3*1***3*5* 
*4*212*2*4* 
*5*****1*3* 
*6123456*2* 
*********1*

わかりました。最初のプログラム:

let Main() =
    let n=int(System.Console.ReadLine())
    let A=Array2D.create(n-2)n '*'
    let mutable x,y,z,i=n-2,n-2,0,n-2
    let d=[|0,-1;-1,0;0,1;1,0|]  // TODO
    while i>0 do
     for j in 1..i-(if i%2=1 then 1 else 0)do
      x<-x+fst d.[z]
      y<-y+snd d.[z]
      A.[y,x]<-'0'+char j
     z<-(z+1)%4
     i<-i-1
    printfn"%A"A
Main()

d(x,y)-diffs-modulo-4 のタプル配列は、後で同じ int-array の異なる部分にインデックスを付ける x と y によって削減できることを知っています。したがって、TODO です。残りは、「空白の描画」への視覚的な洞察に基づいて簡単です。私は2D配列を印刷していますが、これは正しくありません.文字列の配列が必要です.

let n=int(System.Console.ReadLine())
let s=String.replicate n "*"
let A=Array.init(n-2)(fun _->System.Text.StringBuilder(s))
let mutable x,y,z,i=n-2,n-2,0,n-2
let d=[|0,-1;-1,0;0,1;1,0|]
while i>0 do
 for j in 1..i-(if i%2=1 then 1 else 0)do
  x<-x+fst d.[z]
  y<-y+snd d.[z]
  A.[y].[x]<-' '
 z<-(z+1)%4
 i<-i-1
for i in 0..n-3 do
 printfn"%O"A.[i]

では、タプルの配列を int の配列に変更しましょう。

let n=int(System.Console.ReadLine())-2
let mutable x,y,z,i,d=n,n,0,n,[|0;-1;0;1;0|]
let A=Array.init(n)(fun _->System.Text.StringBuilder(String.replicate(n+2)"*"))
while i>0 do
 for j in 1..i-i%2 do x<-x+d.[z];y<-y+d.[z+1];A.[y].[x]<-' '
 z<-(z+1)%4;i<-i-1
A|>Seq.iter(printfn"%O")

letfor A は、前の行の一部にすることができます。とはほとんど冗長ですがzi一方をもう一方の観点から計算できます。

let n=int(System.Console.ReadLine())-2
let mutable x,y,d,A=n,n,[|0;-1;0;1|],
 Array.init(n)(fun _->System.Text.StringBuilder(String.replicate(n+2)"*"))
for i=n downto 1 do for j in 1..i-i%2 do x<-x+d.[(n-i)%4];y<-y+d.[(n-i+1)%4];A.[y].[x]<-' '
Seq.iter(printfn"%O")A

downto長いので、計算をやり直してto、ループに (上に) 行くことができるようにします。

let n=int(System.Console.ReadLine())-2
let mutable x,y,d,A=n,n,[|1;0;-1;0|],
 Array.init(n)(fun _->System.Text.StringBuilder(String.replicate(n+2)"*"))
for i=1 to n do for j in 1..(n-i+1)-i%2 do x<-x+d.[i%4];y<-y+d.[(i+1)%4];A.[y].[x]<-' '
Seq.iter(printfn"%O")A

もう少し締めると、最終的な解決策が得られます。

于 2010-04-02T06:22:35.857 に答える
4

Python: 238 - 221 - 209 文字

すべてのコメントを歓迎します:

d=input();r=range
a=[[' ']*d for i in r(d-2)]
x=y=d/4*2
s=d%4-2
for e in r(3,d+1,2):
 for j in r(y,y+s*e-s,s):a[x][j]='*';y+=s
 for j in r(x,x+s*e-(e==d)-s,s):a[j][y]='*';x+=s
 s=-s
for l in a:print''.join(l)
于 2010-04-01T22:54:30.910 に答える
4

Groovy、373 295 257 243 文字

内部に入る最も外側のものから始まる正方形を構築する再帰的アプローチを試みました..私はGroovyを使用しました。

*********
*********
*********
*********
*********
*********
******* *

*********
*       *
*       *
*       *
*       *
*     * *
******* *

*********
*       *
* ***** *
* ***** *
* *** * *
*     * *
******* *

*********
*       *
* ***** *
* *   * *
* *** * *
*     * *
******* *

等々..

r=args[0] as int;o=r+1;c='*'
t=new StringBuffer('\n'*(r*r-r-2))
e(r,0)
def y(){c=c==' '?'*':' '}
def e(s,p){if (s==3)t[o*p+p..o*p+p+2]=c*s else{l=o*(p+s-3)+p+s-2;(p+0..<p+s-2).each{t[o*it+p..<o*it+p+s]=c*s};y();t[l..l]=c;e(s-2,p+1)}}
println t

読み取り可能なもの:

r=args[0] as int;o=r+1;c='*'
t=new StringBuffer('\n'*(r*r-r-2))
e(r,0)
def y(){c=c==' '?'*':' '}
def e(s,p){
 if (s==3)
  t[o*p+p..o*p+p+2]=c*s 
 else{
  l=o*(p+s-3)+p+s-2
  (p+0..<p+s-2).each{
   t[o*it+p..<o*it+p+s]=c*s}
   y()
   t[l..l]=c
   e(s-2,p+1)      
  }   
}
println t

編集:四角形を塗りつぶしてから上書きすることで改善されました(新しい例を確認してください):四角形の端だけを塗りつぶすのを避けましたが、四角形全体を塗りつぶしました。

于 2010-04-02T03:01:37.420 に答える
3

ルビー、237文字

私はコードゴルフに慣れていないので、マークから外れていますが、私はそれを試してみると思いました。

x=ARGV[0].to_i
y=x-2
s,h,j,g=' ',x-1,y-1,Array.new(y){Array.new(x,'*')}
(1..x/2+2).step(2){|d|(d..y-d).each{|i|g[i][h-d]=s}
(d..h-d).each{|i|g[d][i]=s}
(d..j-d).each{|i|g[i][d]=s}
(d..h-d-2).each{|i|g[j-d][i]=s}}
g.each{|r|print r;puts}

ロングバージョン

于 2010-04-02T13:49:15.187 に答える
3

OCaml、299文字


これはOCamlのソリューションで、最短ではありませんが、かなり読みやすいと思います。

前のものをミラーリングすることでスパイラルを構築できるという事実を使用して、文字列操作のみを使用します。

n = 5 から始めるとします。

55555
5   5
555 5

n = 7 の場合:

7777777
7     7
5 555 7
5   5 7
55555 7

すべての 5 がどこに行ったか見ましたか?

以下は、OCaml で提供される限られたライブラリのみを使用した、難読化されていないコードです。

(* The standard library lacks a function to reverse a string *)
let rev s =
  let n = String.length s - 1 in
  let r = String.create (n + 1) in
    for i = 0 to n do
      r.[i] <- s.[n - i]
    done;
    r
;;

let rec f n =
  if n = 5 then
    [
      "*****";
      "*   *";
      "*** *"
    ]
  else
    [
      String.make n '*';
      "*" ^ (String.make (n - 2) ' ') ^ "*"
    ] @ ( 
      List.rev_map (fun s -> (rev s) ^ " *") (f (n - 2))
    )
;;

let p n =
  List.iter print_endline (f n)
;;

let () = p (read_int ());;

長さが 299 文字の難読化バージョンを次に示します。

open String
let rev s=
  let n=length s-1 in
  let r=create(n+1)in
    for i=0 to n do r.[i]<-s.[n-i]done;r
let rec f n=
  if n=5 then["*****";"*   *";"*** *"]else
    [make n '*';"*"^(make (n-2) ' ')^"*"]
    @(List.rev_map(fun s->(rev s)^" *")(f(n-2)));;
List.iter print_endline (f(read_int ()))
于 2010-04-08T16:10:31.797 に答える
3

Java、265 250 245 240 文字

四角形のバッファーを事前に割り当てて埋めるのではなく、x/y 座標をループして、現在の位置の '*' または ' ' を出力します。このためには、任意の点がらせん上にあるかどうかを評価できるアルゴリズムが必要です。私が使用したアルゴリズムは、特定の対角線に沿って発生する一連の位置を除いて、らせんが同心正方形の集合と同等であるという観察に基づいています。これらの位置は修正する必要があります (反転する必要があります)。

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

public class Spr2 {

  public static void main(String[] args) {
    int n = Integer.parseInt(args[0]);
    int cy = (n - 5) / 4 * 2 + 1;
    int cx = cy + 2;
    for (int y = n - 3; y >= 0; y--) {
      for (int x = 0; x < n; x++) {
        int dx = cx - x;
        int dy = cy - y;
        int adx = Math.abs(dx);
        int ady = Math.abs(dy);
        boolean c = (dx > 0 && dx == dy + 1);
        boolean b = ((adx % 2 == 1 && ady <= adx) || (ady % 2 == 1 && adx <= ady)) ^ c;
        System.out.print(b ? '*' : ' ');
      }
      System.out.println();
    }
  }

}

上記の簡単な説明:

cx,cy = center
dx,dy = delta from center
adx,ady = abs(delta from center)
c = correction factor (whether to invert)
b = the evaluation

最適化されたダウン。265 文字:

public class S{
public static void main(String[]a){
int n=Integer.parseInt(a[0]),c=(n-5)/4*2+1,d=c+2,e,f,g,h,x,y;
for(y=0;y<n-2;y++){
for(x=0;x<=n;x++){
e=d-x;f=c-y;g=e>0?e:-e;h=f>0?f:-f;
System.out.print(x==n?'\n':(g%2==1&&h<=g||h%2==1&&g<=h)^(e>0&&e==f+1)?'*':' ');
}}}}

更新しました。250 文字まで削減:

class S{
public static void main(String[]a){
int n=Integer.parseInt(a[0]),c=(n-5)/4*2+1,d=c+2,g,h,x,y;
for(y=-c;y<n-2-c;y++){
for(x=-d;x<=n-d;x++){
g=x>0?x:-x;h=y>0?y:-y;
System.out.print(x==n-d?'\n':(g%2==1&&h<=g||h%2==1&&g<=h)^(x<0&&x==y-1)?'*':' ');
}}}}

あと数キャラ削った。245 文字:

class S{
public static void main(String[]a){
int n=Integer.parseInt(a[0]),c=(n-5)/4*2+1,d=c+2,g,h,x,y=-c;
for(;y<n-2-c;y++){
for(x=-d;x<=n-d;x++){
g=x>0?x:-x;h=y>0?y:-y;
System.out.print(x==n-d?'\n':(g%2==1&h<=g|h%2==1&g<=h)^(x<0&x==y-1)?'*':' ');
}}}}

あと数キャラ削った。240 文字:

class S{
public static void main(String[]a){
int n=Byte.decode(a[0]),c=(n-5)/4*2+1,d=c+2,g,h,x,y=-c;
for(;y<n-2-c;y++){
for(x=-d;x<=n-d;x++){
g=x>0?x:-x;h=y>0?y:-y;
System.out.print(x==n-d?'\n':(g%2==1&h<=g|h%2==1&g<=h)^(x<0&x==y-1)?'*':' ');
}}}}
于 2010-04-03T03:14:46.260 に答える
2

Ruby(1.9.2)— 126

f=->s{s<0?[]:(z=?**s;[" "*s]+(s<2?[]:[z]+f[s-4]<<?*.rjust(s))).map{|i|"* #{i} *"}<<z+"** *"}
s=gets.to_i;puts [?**s]+f[s-4]

Perl、どこにいるの?)。

于 2010-08-30T13:46:48.813 に答える
2

C#、292 262 255 文字

簡単なアプローチ: らせんを外側から内側に 1 行ずつ描きます。

using C=System.Console;class P{static void Main(string[]a){int A=
1,d=1,X=int.Parse(a[0]),Y=X-2,l=X,t=0,i,z;while(l>2){d*=A=-A;l=l<
4?4:l;for(i=1;i<(A<0?l-2:l);i++){C.SetCursorPosition(X,Y);C.Write
("*");z=A<0?Y+=d:X+=d;}if(t++>1||l<5){l-=2;t=1;}}C.Read();}}
于 2010-04-03T06:52:03.840 に答える