¡Enróllame una serpiente número!

34

Dado un número entero de entrada n, dibujar una serpiente número, es decir, una cuadrícula de medición n x nque consiste en los números 1a través de n^2que se enrollan alrededor de la otra de la manera siguiente:

Entrada n = 3:

7 8 9
6 1 2
5 4 3

Entrada n = 4:

 7  8  9 10
 6  1  2 11
 5  4  3 12
16 15 14 13

Entrada n = 5:

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13

(Inspirado por este problema del Proyecto Euler).

Este es el , ¡la respuesta más corta en bytes gana!

Julius
fuente
44
Ejemplo: 4? O cualquier número par.
TheLethalCoder
1
¿Podemos suponer que la entrada es impar?
Sr. Xcoder
1
Relacionado
Emigna
2
Posible engaño ?
Shaggy
1
Consulte también perlmonks.com/?node_id=487200 con muchas soluciones y enlaces en las respuestas.
b_jonas

Respuestas:

43

MATL , 3 bytes

1YL

Pruébalo en línea!

Explicación

Incorporado ... ¯ \ _ (ツ) _ / ¯

Luis Mendo
fuente
31
¿Por qué ... por qué es esto incorporado?
TheLethalCoder
2
Supongo que esto tiene algo que ver con las cosas del "Magic Square".
Magic Octopus Urn
8
@TheLethalCoder Porque Matlab lo tenía y pensé que sería útil ( lo cual es realmente )
Luis Mendo
18

C #, 203 202 196 193 178 bytes

n=>{var r=new int[n,n];for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,b=1-2*(i%2),j;n>i++;){r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;}return r;}

Guardado un byte gracias a @StefanDelport.
Guardado 22 bytes gracias a @FelipeNardiBatista.

Esto funciona mediante la siguiente observación de cómo se forman los cuadrados:

Imagen del cuadrado donde n = 5

Como puede ver, cada bit se agrega al cuadrado anterior. Para los números pares, vamos a la derecha de donde estábamos, hacia abajo, hasta que estuvimos uno más abajo de donde estaba el cuadrado y luego nos fuimos al final. Los números impares son esencialmente lo opuesto, vamos a la izquierda, hasta que estuvimos uno por encima de la altura actual y luego al final.

Versión completa / formateada:

using System;
using System.Linq;

class P
{
    static void Main()
    {
        Func<int, int[,]> f = n =>
        {
            var r = new int[n, n];
            for (int o = n - 2 + n % 2 >> 1, i = r[o, o] = 1, c = 2, w = o, h = o, b = 1 - 2 * (i % 2), j; n > i++;)
            {
                r[h, w += b] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h += b, w] = c++;

                for (j = 0; j < i - 1; ++j)
                    r[h, w -= b] = c++;
            }

            return r;
        };

        Console.WriteLine(String.Join("\n", f(3).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(4).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");
        Console.WriteLine(String.Join("\n", f(5).ToJagged().Select(line => String.Join(" ", line.Select(l => (l + "").PadLeft(2))))) + "\n");

        Console.ReadLine();
    }
}

public static class ArrayExtensions
{
    public static T[][] ToJagged<T>(this T[,] value)
    {
        T[][] result = new T[value.GetLength(0)][];

        for (int i = 0; i < value.GetLength(0); ++i)
            result[i] = new T[value.GetLength(1)];

        for (int i = 0; i < value.GetLength(0); ++i)
            for (int j = 0; j < value.GetLength(1); ++j)
                result[i][j] = value[i, j];

        return result;
    }
}
TheLethalCoder
fuente
1
++i<=n;puede convertirse n>++i, nada más puedo ver, +1.
LiefdeWen
1
n%2<1?2:1a 2-x%2? No lo he probado en C #, pero en C y Python funcionó.
Felipe Nardi Batista
1
for(int o=n-2+n%2>>1,i=r[o,o]=1,c=2,w=o,h=o,j;n>i++;){var b=i%2<1; ....golf un poco
Felipe Nardi Batista
¡@FelipeNardiBatista Awesome nunca hubiera pensado en esos dos! Gracias.
TheLethalCoder
1
var b=1-2*(i%2);r[h,w+=b]=c++;for(j=0;j<i-1;++j)r[h+=b,w]=c++;for(j=0;j<i-1;++j)r[h,w-=b]=c++;
Felipe Nardi Batista
15

Dyalog APL, 70 56 45 41 bytes

,⍨⍴∘(⍋+\)×⍨↑(⌈2÷⍨×⍨),(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

Pruébalo en línea!

¿Cómo?

(+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳

calcula las diferencias entre los índices; 1y ¯1para derecha e izquierda, ¯⍵y para arriba y abajo.

1,⊢,¯1,-viene como 1 ⍵ ¯1 ¯⍵, +⍨⍴estira esta matriz a la longitud de ⍵×2, por lo que el final 2/⍳puede repetir cada uno de ellos, con un conteo de repeticiones que aumenta cada segundo elemento:

      (1,⊢,¯1,-) 4
1 4 ¯1 ¯4
      (+⍨⍴1,⊢,¯1,-) 4
1 4 ¯1 ¯4 1 4 ¯1 ¯4
      (2/⍳) 4
1 1 2 2 3 3 4 4
      ((+⍨⍴1,⊢,¯1,-)(/⍨)2/⍳) 4
1 4 ¯1 ¯1 ¯4 ¯4 1 1 1 4 4 4 ¯1 ¯1 ¯1 ¯1 ¯4 ¯4 ¯4 ¯4

luego,

(⌈2÷⍨×⍨),

antepone el elemento superior izquierdo de la espiral,

×⍨↑

limitar los primeros ⍵ 2 elementos de esta lista de distancias,

+\

realiza suma acumulativa,

califica los índices ( ⍵[i] = ⍵[⍵[i]]), para traducir la matriz original con los índices de cada elemento, y finalmente

,⍨⍴

formas como una ⍵×⍵matriz.

Uriel
fuente
Para aquellos interesados, esta técnica se discute extensamente en este excelente artículo .
Jonás
9

C, 321 307 295 284 283 282 bytes

¡Gracias a @Zachary T y @Jonathan Frech por jugar al golf en un byte!

#define F for(b=a;b--;)l
i,j,k,a,b,m;**l;f(n){n*=n;l=calloc(a=m=3*n,4);F[b]=calloc(m,4);for(l[i=j=n][j]=a=k=1;n>k;++a){F[i][++j]=++k;F[++i][j]=++k;++a;F[i][--j]=++k;F[--i][j]=++k;}for(i=0;i<m;++i,k&&puts(""))for(j=k=0;j<m;)(a=l[i][j++])>0&&a<=n&&printf("%*d ",(int)log10(n)+1,k=a);}

Asigna una matriz bidimensional de ceros, luego comienza a llenarlo desde algún lugar en el medio. Por último, se imprimen los valores que son mayores que cero pero menores o iguales que el cuadrado de la entrada.

Pruébalo en línea!

Formateado:

#define F for(b=a; b--;)l
i, j, k, a, b, m; **l;
f(n)
{
    n *= n;
    l = calloc(a=m=3*n, 4);

    F[b] = calloc(m, 4);

    for(l[i=j=n][j]=a=k=1; n>k; ++a)
    {
        F[i][++j] = ++k;
        F[++i][j] = ++k;
        ++a;

        F[i][--j] = ++k;
        F[--i][j] = ++k;
    }

    for(i=0; i<m; ++i, k&&puts(""))
        for(j=k=0; j<m;)
            (a=l[i][j++])>0 && a<=n && printf("%*d ", (int)log10(n)+1, k=a);
}
Steadybox
fuente
1
¿Es posible reemplazar i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4);con i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4);para guardar un byte?
Zacharý
1
Es posible que pueda reemplazar k<=n;con n>k;para guardar un byte.
Jonathan Frech
6

PHP , 192 bytes

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=$a/2^$w=0;$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$e[$x-!($a&1)][$y]=sprintf("%$l".d,$i);for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);

Pruébalo en línea!

Del mismo modo, construya una cadena en lugar de una matriz

PHP , 217 bytes

for($l=strlen($q=($a=$argn)**2)+$d=1,$x=$y=($a/2^$w=0)-!($a&1),$s=str_pad(_,$q*$l);$i++<$q;${yx[$w%2]}+=$d&1?:-1,$i%$d?:$d+=$w++&1)$s=substr_replace($s,sprintf("%$l".d,$i),($x*$a+$y)*$l,$l);echo chunk_split($s,$a*$l);

Pruébalo en línea!

Jörg Hülsermann
fuente
1
[-1,1][$d&1]->$d&1?:-1
Titus
@Titus Gracias, no lo he visto
Jörg Hülsermann
1
Aquí es un byte más: for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);. Y otro: "%$l".d. Y uno más: $x*$l*$a+$y*$l-> ($x*$a+$y)*$l.
Titus
1
Y creo que en la segunda versión, puede inicializar $sa un guión bajo (o letra o dígito); ese personaje se sobrescribirá.
Titus
@Titus Gracias y puedes usarlo .den tu propio enfoque para ahorrar 2 bytes
Jörg Hülsermann
6

PHP, 185 176 174 bytes

for(;$n++<$argn**2;${xy[$m&1]}+=$m&2?-1:1,$k++<$p?:$p+=$m++%2+$k=0)$r[+$y][+$x]=$n;ksort($r);foreach($r as$o){ksort($o);foreach($o as$i)printf(" %".strlen($n).d,$i);echo"
";}

Ejecutar como tubería con -nRo probarlo en línea .

Descompostura

for(;$n++<$argn**2;     # loop $n from 1 to N squared
    ${xy[$m&1]}+=$m&2?-1:1, # 2. move cursor
    $k++<$p?:               # 3. if $p+1 numbers have been printed in that direction:
        $p+=$m++%2+             # increment direction $m, every two directions increment $p
        $k=0                    # reset $k
)$r[+$y][+$x]=$n;           # 1. paint current number at current coordinates

ksort($r);              # sort grid by indexes
foreach($r as$o){       # and loop through it
    ksort($o);              # sort row by indexes
    foreach($o as$i)        # and loop through it
        printf(" %".strlen($n).d,$i);   # print formatted number
    echo"\n";               # print newline
}
Titus
fuente
6

APL (Dyalog Classic) , 32 29 bytes

1+×⍨-{⊖∘⌽⍣⍵⌽{⌽⍉,⌸⍵+≢⍵}⍣2⍣⍵⍪⍬}

Pruébalo en línea!

Usos ⎕io←1. Comienza con una matriz 0 por 1 ( ⍪⍬). 2N veces ( ⍣2⍣⍵) agrega la altura de la matriz ( ≢⍵) a cada uno de sus elementos, se coloca 1 2...heighta la derecha ( ,⌸) y gira ( ⌽⍉). Cuando haya terminado, corrige la orientación del resultado ( ⊖∘⌽⍣⍵⌽) e invierte los números restándolos de N 2 +1 ( 1+×⍨-).

ngn
fuente
5

Mathematica, 177 bytes

(n=#;i=j=Floor[(n+1)/2];c=1;d=0;v={{1,0},{0,-1},{-1,0},{0,1}};a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]], {k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];Grid@a)&
J42161217
fuente
8
Waaait, no hay incorporado para esto en Mathematica?
Sr. Xcoder
5

C ++, 245 228 bytes

void f(){for(int i=0,j=-1,v,x,y,a,b;i<n;i++,j=-1,cout<<endl)while(++j<n){x=(a=n%2)?j:n-j-1;y=a?i:n-i-1;v=(b=y<n-x)?n-1-2*(x<y?x:y):2*(x>y?x:y)-n;v=v*v+(b?n-y-(y>x?x:y*2-x):y+1-n+(x>y?x:2*y-x));cout<<setw(log10(n*n)+1)<<v<<' ';}}

Pruébalo en línea!

La función calcula e imprime el valor de cada número de la matriz en función de su x, y aplicando esta lógica:

Cálculo de valores de serpiente dependiendo de la posición

Versión formateada :

#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

void f(int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int value = 0;

            // Invert x and y when n is even
            int x = n % 2 == 0 ? n - j - 1 : j;
            int y = n % 2 == 0 ? n - i - 1 : i;
            if (y < (n - x))
            {
                // Left-top part of the matrix
                int padding = x < y ? x : y;
                value = n - 1 - padding * 2;
                value *= value;
                value += y >= x ? n - x - y : n + x - y - (y * 2);
            }
            else
            {
                // Right-bottom part of the matrix
                int padding = x > y ? n - x : n - y;
                value = n - padding * 2;
                value *= value;
                value += x > y ? y - padding + 1 : n + y - x - (padding * 2) + 1;
            }

            cout << setw(log10(n * n) + 1);
            cout << value << ' ';
        }

        cout << endl;
    }
}

int main()
{
    int n;
    while (cin >> n && n > 0)
    {
        f(n);
        cout << endl;
    }
}
Julio E. Rodríguez Cabañas
fuente
5

Pitón 3 , 249 247 bytes

Inicializo una matriz 2D y encuentro el punto de partida, que es el centro para n impar o desplazamiento (-1, -1) para n par, luego escalo el patrón de relleno / cursor con el número de 'anillo' actual. Siento que me falta un truco para interpretar las instrucciones, pero no he encontrado nada más barato.

def f(n):
 M=[n*[0]for a in range(n)]
 x=y=n//2-1+n%2
 M[x][y]=i=s=1
 while 1:
  t=s*2
  for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t:
   if i==n*n:print(*M,sep='\n');return
   v=[1,-1][d in'LU']
   if d in'UD':x+=v
   else:y+=v
   M[x][y]=i=i+1
  s+=1

Pruébalo en línea!

-2 gracias a Zachary T!

nocturama
fuente
¿Cómo contabas tus bytes? pestañas, espacios y líneas nuevas también cuentan
Felipe Nardi Batista
Reemplacé cada \ ny \ t con "" y tomé un len (). Simplemente copié lo anterior y lo rehice para asegurarme de que no cambié nada y me olvidé de contarlo, pero obtuve el mismo número. ¿Me he perdido algo?
nocturama
Estoy contando \ty \ncomo 1 byte y todavía obtengo 249 bytes
Felipe Nardi Batista
e: ^^^ ¿Hay un método mejor / más fácil que debería usar? siempre me parecieron utilizados indistintamente. ^^^ Extraño, esto es lo que obtengo en IDLE:len("def f(n): M=[n*[0]for a in range(n)] x=y=n//2-(n%2<1) M[x][y]=i=s=1 while 1: t=s*2 for d in'R'+'D'*(t-1)+'L'*t+'U'*t+'R'*t: if i==n*n:print(*M,sep='\n');return v=[1,-1][d in'LU'] if d in'UD':x+=v else:y+=v M[x][y]=i=i+1 s+=1") 223
nocturama
por lo general, los editores de texto le dicen cuántos caracteres se seleccionan, así que CTRL + A y leen lo que dice
Felipe Nardi Batista
5

Wolfram Language (Mathematica) , (...) 83 bytes

Byte medido en UTF8, \[LeftFloor]( ) y \[RightFloor]( ) cuesta 3 bytes cada uno. Mathematica no tiene ningún conjunto de caracteres de byte especial.

Table[Max[4x^2-Max[x+y,3x-y],4y
y-{x+y,3y-x}]+1,{y,b+1-#,b=⌊#/2⌋},{x,b+1-#,b}]&

Pruébalo en línea!


Utiliza el formulario cerrado para cada uno de los 4 casos, luego toma el máximo con cuidado para obtener el resultado deseado.

Devuelve una matriz 2D de enteros. No estoy seguro de si esto está permitido, y aunque se ha preguntado en los comentarios , el OP no respondió.

usuario202729
fuente
4

Clojure, 206 bytes

(defmacro F[s]`(if(~'r(+ ~'p ~'v ~s))~'v ~s))
#(loop[i 1 p(*(quot(dec %)2)(inc %))v 1 r{}](if(<(* % %)i)(partition %(map r(range i)))(recur(inc i)(+ p v)({1(F %)-1(F(- %))%(F -1)(- %)(F 1)}v)(assoc r p i))))

Supongo que este es un comienzo decente, construye el tablero en secuencia en un mapa hash y luego lo divide en n x nlistas. Eso defmacroterminó siendo bastante largo, pero el código aún es más corto con él que sin él. ¿Existe una sintaxis más sucinta para describirla?

La cantidad de bytes calcula el punto de partida y construye la lógica de búsqueda de la siguiente velocidad v. Quizás un anidado vecsería mejor, pero entonces tienes dos índices y velocidades para seguir.

NikoNyrh
fuente
3

J , 41 bytes

(]|.@|:@[&0](|.@|:@,.*/@$+#\)@]^:[1:)2*<:

Pruébalo en línea!

Hace lo mismo que el envío APL de ngn pero comienza con una matriz 1 por 1 y se repite 2 × N − 2 veces.

FrownyFrog
fuente
¿Puedes mejorar mi enfoque alternativo (ahora empatado en 41) para superarte? Le he dado mi mejor golf hasta el momento, pero sospecho que al menos unos pocos bytes más podrían eliminarse.
Jonás
1

Python 165 (o 144)

from pylab import *
def S(n):
 a=r_[[[1]]];r=rot90;i=2
 while any(array(a.shape)<n):
  q=a.shape[0];a=vstack([range(i,i+q),r(a)]);i+=q
 if n%2==0:a=r(r(a))
 print(a)

Esto crea una matriz numpy, luego la gira y agrega un lado hasta alcanzar el tamaño correcto. La pregunta no especificó si el mismo punto de inicio debe usarse para números pares e impares, si ese no es el caso, la línea if n%2==0:a=r(r(a))se puede eliminar, ahorrando 21 bytes.

usuario2699
fuente
1
esto no es Python, es Python + numpy
solo ASCII
@ Solo ASCII ¿Hay una lista maestra de nombres de idiomas aceptables en alguna parte? Esta es una pitón perfectamente válida.
user2699
Utiliza una biblioteca, por lo que debe incluir el nombre de la biblioteca también ... en cuanto a los idiomas permitidos, cualquier idioma con una implementación disponible públicamente que pueda ejecutar está permitido
solo ASCII
@ Solo ASCII ¿dónde está escrito eso? No lo he visto hecho con la mayoría de las respuestas de Python.
user2699
Sí, porque la mayoría de ellos no usan numpy ... y stdlib no cuenta como una biblioteca externa
solo ASCII
0

J , 41 bytes

,~$[:/:[:+/\_1|.1&,(]##@]$[,-@[)2}:@#1+i.

formato estándar

,~ $ [: /: [: +/\ _1 |. 1&, (] # #@] $ [ , -@[) 2 }:@# 1 + i.

Este enfoque se basa en At Play With J Volutes (el APL de Uriel usa una técnica similar).

Es inesperado y lo suficientemente elegante como para justificar una segunda respuesta J, pensé.

Esencialmente, no hacemos nada de procedimiento o incluso geométrico. En cambio, creamos aritméticamente una secuencia simple que, cuando el escaneo se suma y se califica, da el orden correcto del número en espiral de izquierda a derecha, de arriba a abajo. Luego formamos eso en una matriz y listo.

Agregaré una explicación más detallada cuando el tiempo lo permita, pero el artículo vinculado lo explica en profundidad.

Pruébalo en línea!

Jonás
fuente
0

Python 3 (sin apilamiento) , 192 188 179 150 bytes

lambda n:[list(map(v,list(range(t-n,t)),[y]*n))for t in[1+n//2]for y in range(n-t,-t,-1)]
v=lambda x,y,r=0:y>=abs(x)and(3-2*r+4*y)*y+x+1or v(y,-x,r+1)

Pruébalo en línea!

El algoritmo aquí es formar un fasor para cada coordenada en la cuadrícula, y luego rotarlo 90 grados en el sentido de las agujas del reloj hasta que el fasor se encuentre entre las diagonales superiores. Se puede usar una fórmula simple para calcular el valor basado en las coordenadas y el número de rotaciones en sentido horario:

(2y+1)2-(y-X)-2yr

Guardado 4 bytes ya que la rotación fasorial de 90 grados se realiza fácilmente sin números complejos

SmileAndNod
fuente
0

R , 183 bytes

x=scan()
b=t(d<-1)
while(2*x-1-d){m=max(b)
y=(m+1):(m+sum(1:dim(b)[2]|1))
z=d%%4
if(z==1)b=cbind(b,y)
if(z==2)b=rbind(b,rev(y))
if(z==3)b=cbind(rev(y),b)
if(z==0)b=rbind(y,b)
d=d+1}
b

Pruébalo en línea!

La salida es una serpiente de matriz (o matriz de serpiente, lo que sea). Probablemente no sea el método más eficiente, y probablemente podría jugar golf, pero pensé que valía la pena mostrarlo. ¡Estoy bastante orgulloso de esto en realidad!

El método construye la matriz de adentro hacia afuera, siempre agregando un número adicional de enteros igual al número de columnas en la matriz antes de agregar. El patrón que sigue es vinculante por columnas o por filas, mientras que también invierte algunos valores para que se agreguen en el orden correcto.

193 bytes

Exactamente igual que el anterior, pero el final bes

matrix(b,x)

Pruébalo en línea!

lo que da una salida ligeramente más limpia, pero no vi ningún criterio especial para la salida, por lo que la primera respuesta debería funcionar si no me equivoco.

Sumner18
fuente