Enrole-me uma cobra numérica!


34

Dado um número inteiro de entrada n, desenhar uma cobra número, isto é, uma grelha de medição n x nque consiste nos números 1através de n^2que são enrolados em torno de si na seguinte forma:

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 esse problema do Project Euler.)

Isso é , a resposta mais curta em bytes vence!


4
Exemplo 4:? Ou qualquer número par.
TheLethalCoder

1
Podemos assumir que a entrada é ímpar?
Mr. Xcoder



1
Consulte também perlmonks.com/?node_id=487200 com muitas soluções e links em respostas.
b_jonas

Respostas:



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

Guardou um byte graças a @StefanDelport.
Economizou 22 bytes graças a @FelipeNardiBatista.

Isso funciona com a seguinte observação de como os quadrados são construídos:

Imagem do quadrado onde n = 5

Como você pode ver, cada bit é adicionado ao quadrado anterior. Para números pares, vamos direto de onde estávamos, até um mais baixo do que o quadrado e depois deixamos para o final. Os números ímpares são essencialmente o oposto, vamos para a esquerda, até um acima da altura atual e depois até o fim.

Versão completa / formatada:

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

1
++i<=n;pode se tornar n>++i, nada mais que eu possa ver, +1.
LiefdeWen

1
n%2<1?2:1para 2-x%2? Eu não testei em C #, mas em C e Python funcionou.
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; ....golfed um pouco
Felipe Nardi Batista

@FelipeNardiBatista Awesome nunca teria pensado nesses dois! Obrigado.
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/⍳

Experimente online!

Quão?

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

calcula as diferenças entre os índices; 1e ¯1para direita e esquerda, ¯⍵e para cima e para baixo.

1,⊢,¯1,-vem como 1 ⍵ ¯1 ¯⍵, +⍨⍴estende esse array ao comprimento de ⍵×2, para que o final 2/⍳possa repetir cada um deles, com uma contagem de repetições aumentando a 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

então,

(⌈2÷⍨×⍨),

precede o elemento superior esquerdo da espiral,

×⍨↑

limitar os primeiros elements 2 elementos desta lista de distâncias,

+\

executa soma cumulativa,

classifica os índices ( ⍵[i] = ⍵[⍵[i]]), para traduzir a matriz original com os índices de cada elemento e, finalmente,

,⍨⍴

formas como uma ⍵×⍵matriz.


Para os interessados, essa técnica é discutida detalhadamente neste excelente artigo .
Jonah

9

C, 321 307 295 284 283 282 bytes

Obrigado a @Zachary T e @Jonathan Frech por jogarem um 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);}

Aloca uma matriz bidimensional de zeros e começa a preenchê-la de algum lugar no meio. Por fim, os valores maiores que zero, mas menores ou iguais ao quadrado da entrada são impressos.

Experimente online!

Formatado:

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

1
É possível substituir i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4);por i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4);para salvar um byte?
Zachary

1
Você pode substituir k<=n;por n>k;para salvar um 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++]);

Experimente online!

Do mesmo modo, construir uma string em vez de uma 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);

Experimente online!


1
[-1,1][$d&1]->$d&1?:-1
Tito

@Titus Obrigado eu não vê-lo
Jörg Hülsermann

1
Aqui está mais um byte: for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);. E outra: "%$l".d. E mais um: $x*$l*$a+$y*$l-> ($x*$a+$y)*$l.
Titus

1
E acho que, na segunda versão, você pode inicializar $scom um sublinhado acolchoado (ou letra ou dígito); esse personagem será substituído.
Titus

@Titus obrigado e você pode usar a .dsua própria abordagem para salvar 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"
";}

Execute como tubo -nRou teste-o online .

demolir

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
}

6

APL (Dyalog Classic) , 32 29 bytes

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

Experimente online!

Usos ⎕io←1. Inicia com uma matriz de 0 por 1 ( ⍪⍬). 2N vezes ( ⍣2⍣⍵) adiciona a altura da matriz ( ≢⍵) a cada um de seus elementos, coloca 1 2...heightà direita ( ,⌸) e gira ( ⌽⍉). Quando terminar, corrige a orientação do resultado ( ⊖∘⌽⍣⍵⌽) e reverte os números subtraindo-os de N 2 +1 ( 1+×⍨-).


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

8
Waaait, não há embutido para isso no Mathematica?
Mr. 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<<' ';}}

Experimente online!

A função calcula e imprime o valor de cada número da matriz, dependendo de sua posição x, y , aplicando esta lógica:

Cálculo dos valores de cobra dependendo da posição

Versão formatada :

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

5

Python 3 , 249 247 bytes

Inicializo uma matriz 2D e encontro o ponto de partida, que é o centro para n ímpar ou deslocamento (-1, -1) para o par n e, em seguida, dimensiono o padrão de preenchimento / cursor com o número atual do 'anel'. Sinto que estou perdendo um truque para interpretar as instruções, mas não criei nada mais 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

Experimente online!

-2 graças a Zachary T!


como você contou seus bytes? tabs, espaços e novas linhas contagem bem
Felipe Nardi Batista

Substituí todos \ n e \ t por "" e peguei um len (). Eu apenas copiei o texto acima e refizi-o para garantir que não mudasse nada e esquecesse de recontar, mas obtive o mesmo número. Perdi alguma coisa?
Nocturama

Eu estou contando \te \ncomo 1 byte e ainda obter 249 bytes
Felipe Nardi Batista

e: ^^^ existe um método melhor / mais fácil que devo usar? . eles sempre pareceu ser usados alternadamente para mim ^^^ Estranho, é isso que eu entrar em 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

geralmente editores de texto dizer-lhe quantos caracteres são selecionados, de modo CTRL + A e ler o que diz
Felipe Nardi Batista

5

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

Os bytes medidos em UTF8, \[LeftFloor]( ) e \[RightFloor]( ) custam 3 bytes cada. O Mathematica não possui nenhum conjunto de caracteres de bytes 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}]&

Experimente online!


Usa o formulário fechado para cada um dos 4 casos e, em seguida, toma o máximo com cuidado para obter o resultado desejado.

Retorna uma matriz 2D de números inteiros. Não tenho certeza se isso é permitido e, embora tenha sido solicitado nos comentários , o OP não respondeu.


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

Eu acho que esse é um começo decente, constrói o quadro em sequência em um mapa de hash e o particiona em n x nlistas. Isso defmacroacabou sendo bastante longo, mas o código ainda é mais curto com ele do que sem. Existe uma sintaxe mais sucinta para descrevê-la?

O volume de bytes calcula o ponto inicial e constrói a lógica de pesquisa da próxima velocidade v. Talvez um aninhado vecseja melhor, mas você tem dois índices e velocidades para acompanhar.



1

Python 165 (ou 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)

Isso cria uma matriz numpy, depois a gira e adiciona um lado até que o tamanho correto seja atingido. A pergunta não especificou se o mesmo ponto inicial precisa ser usado para números pares e ímpares; se não for o caso, a linha if n%2==0:a=r(r(a))poderá ser removida, economizando 21 bytes.


1
este não é Python, é Python + numpy
somente ASCII

@ Somente ASCII Existe uma lista principal de nomes de idiomas aceitáveis ​​em algum lugar? Este é um python perfeitamente válido.
user2699 8/04

Ele usa uma biblioteca, então você precisa incluir o nome da biblioteca também ... como nos idiomas permitidos, qualquer idioma com uma implementação disponível publicamente que você possa executar é permitido
ASCII-only

@ Somente ASCII, onde está escrito? Eu não vi isso feito com a maioria das respostas em python.
user2699 8/04

Sim, porque a maioria deles não usa numpy ... e o stdlib não conta como uma biblioteca externa
somente ASCII

0

J , 41 bytes

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

formatação padrão

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

Essa abordagem é baseada no At Play With J Volutes (o APL de Uriel usa uma técnica semelhante).

É inesperado e elegante o suficiente para justificar uma segunda resposta em J, pensei.

Essencialmente, não fazemos nada de procedimento ou mesmo geométrico. Em vez disso, criamos aritmeticamente uma sequência simples que, quando a varredura é somada e classificada, fornece a ordem correta do número em espiral da esquerda para a direita, de cima para baixo. Em seguida, modelamos isso em uma matriz e terminamos.

Vou adicionar uma explicação mais detalhada quando o tempo permitir, mas o artigo vinculado explica isso em profundidade.

Experimente online!


0

Python 3 (sem pilha) , 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)

Experimente online!

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

Salva 4 bytes, pois a rotação fasorial de 90 graus é feita facilmente sem números complexos


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

Experimente online!

Saída é uma matriz de cobra (ou matriz de cobra, qualquer que seja). Provavelmente não é o método mais eficiente, e provavelmente poderia ser jogado, mas achei que valia a pena mostrar. Estou bastante orgulhoso disso, na verdade!

O método constrói a matriz de dentro para fora, sempre acrescentando um número adicional de números inteiros igual ao número de colunas na matriz antes de acrescentar. O padrão a seguir é vinculado por colunas ou linhas, além de reverter alguns valores para que eles sejam anexados na ordem correta.

193 bytes

Exatamente o mesmo que acima, mas final bé

matrix(b,x)

Experimente online!

que fornece uma saída um pouco mais limpa, mas não vi nenhum critério especial para a saída, portanto, a primeira resposta deve funcionar se não me engano.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.