language-agnostic code-golf rosetta-stone spiral

language agnostic - Codigo Golf: Easter Spiral



language-agnostic code-golf (10)

¿Qué es más apropiado que un Spiral para las sesiones de Easter Code Golf?
Bueno, supongo que casi cualquier cosa.

El reto

El código más corto por número de caracteres para mostrar una bonita espiral ASCII hecha de asteriscos (''*'').

La entrada es un número único, R , que será el tamaño x de la espiral. La otra dimensión (y) es siempre R-2 . El programa puede asumir que R es siempre impar y> = 5.

Algunos ejemplos:

Input 7 Output ******* * * * *** * * * * ***** * Input 9 Output ********* * * * ***** * * * * * * *** * * * * * ******* * Input 11 Output *********** * * * ******* * * * * * * * *** * * * * * * * * ***** * * * * * ********* *

El conteo de códigos incluye entrada / salida (es decir, programa completo). Se permite cualquier idioma.

Mi ejemplo de Python largo 303 caracteres fácilmente vencibles:

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);

Ahora, entra en la espiral ...


C #, 292 262 255 caracteres

Enfoque simple: dibuje la línea espiral de afuera hacia adentro.

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();}}


F #, 267 caracteres

Muchas respuestas comienzan con espacios en blanco y añadiendo * s, pero creo que puede ser más fácil comenzar con un campo de estrellas y agregar espacios en blanco.

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

Para aquellos que buscan información sobre cómo jugar al golf, he ahorrado muchos progresos en el camino, que presento aquí con comentarios. No todos los programas son correctos, pero todos se están enfocando en una solución más corta.

En primer lugar, busqué un patrón de cómo pintar el blanco:

********* * * * ***** * * * * * * *** * * * * * ******* * ********* *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*

Ok ya lo veo Primer programa:

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()

Sé que d , la matriz de la tupla de (x, y) -diffs-modulo-4 se puede reducir más tarde en x e y ambas se indexan en diferentes porciones de la misma matriz int, de ahí el TODO. El resto es sencillo basado en la visión visual de la "pintura de espacios en blanco". Estoy imprimiendo una matriz 2D, lo cual no es correcto, necesito una matriz de cadenas, así que:

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]

Ok, ahora vamos a cambiar la matriz de tuplas en una matriz de 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")

El let para A puede ser parte de la línea anterior. Y z y i son en su mayoría redundantes, puedo calcular uno en términos del otro.

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 es largo, vuelve a hacer los cálculos para que pueda subir (arriba) to bucle.

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

Un poco más apretado produce la solución final.


Groovy, 373 295 257 243 caracteres

Intenté un enfoque recursivo que construye cuadrados a partir del más externo que va hacia adentro. Usé Groovy .

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

y así..

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

uno legible

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

EDITAR : mejorado simplemente llenando cuadrados y luego reemplazándolos (ver ejemplo nuevo): así que evité llenar solo el borde del rectángulo pero el entero.


Java

328 caracteres

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)); } }

Tan poco como 1/6 más que Python no parece tan malo;)

Aquí es lo mismo con la sangría adecuada:

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)); } }


Java, 265 250 245 240 caracteres

En lugar de preasignar un búfer rectangular y rellenarlo, simplemente reparto las coordenadas x / y obtengo ''*'' o '''' para la posición actual. Para esto, necesitamos un algoritmo que pueda evaluar puntos arbitrarios para determinar si están en la espiral. El algoritmo que utilicé se basa en la observación de que la espiral es equivalente a una colección de cuadrados concéntricos, con la excepción de un conjunto de posiciones que ocurren a lo largo de una diagonal particular; estas posiciones requieren una corrección (deben estar invertidas).

La versión algo legible:

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(); } } }

Una breve explicación de lo anterior:

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

Optimizado hacia abajo. 265 caracteres:

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)?''*'':'' ''); }}}}

Actualizado. Ahora bajamos a 250 caracteres:

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)?''*'':'' ''); }}}}

Afeitado sólo unos pocos personajes más. 245 caracteres:

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)?''*'':'' ''); }}}}

Afeitado sólo unos pocos personajes más. 240 caracteres:

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)?''*'':'' ''); }}}}


Python (2.6): 156 caracteres

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," *")

Gracias por los comentarios. He eliminado espacios en blanco extraños y utilicé input (). Todavía prefiero un programa que toma su argumento en la línea de comandos, así que aquí hay una versión que todavía usa sys.argv en 176 caracteres:

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," *")

Explicación

Toma la espiral y córtala en dos partes casi iguales, superior e inferior, con una fila superior más grande que la inferior:

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

Observe cómo la parte superior es agradable y simétrica. Observe cómo la parte inferior tiene una línea vertical hacia abajo del lado derecho, pero por lo demás es muy parecida a la parte superior. Note el patrón en cada segunda fila en la parte superior: un número creciente de estrellas en cada lado. Tenga en cuenta que cada fila intermedia es exactamente la sierra como la anterior, excepto que llena las estrellas con el área central.

La función p (r, s) imprime la línea i de la parte superior de la espiral de ancho r y pega el sufijo s en el extremo. Tenga en cuenta que i es una variable global, ¡aunque no sea obvia! Cuando i es par, llena la mitad de la fila con espacios, de lo contrario con estrellas. (El ~ i% 2 fue una manera desagradable de obtener el efecto de i% 2 == 0, pero en realidad no es necesario en absoluto porque debería haber cambiado simplemente el "*" y el "".) Primero, dibujamos la parte superior filas de la espiral con i creciente, luego dibujamos las filas de abajo con i decreciente. Bajamos r por 2 y el sufijo "*" para obtener la columna de estrellas a la derecha.


Python: 238 - 221 - 209 caracteres

Todos los comentarios son bienvenidos:

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)


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, ¿dónde estás? )


OCaml, 299 caracteres


Aquí hay una solución en OCaml, no la más corta, pero creo que es bastante legible.

Solo utiliza manipulaciones de cuerdas, ya que puedes construir una espiral al reflejar la anterior.

Digamos que empiezas con n = 5:

55555 5 5 555 5

Ahora con n = 7:

7777777 7 7 5 555 7 5 5 7 55555 7

¿Viste donde fueron todos los 5?

Aquí está el código no oculto utilizando solo la biblioteca limitada provista con 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 ());;

Aquí está la versión ofuscada que tiene 299 caracteres:

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 ()))


Ruby, 237 caracteres

Soy nuevo en el código de golf, así que estoy muy lejos de la marca, pero pensé que lo intentaría.

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}

Versión larga