Nakręć mi węża liczbowego!

34

Biorąc pod uwagę liczbę całkowitą wejściową n, narysuj węża liczbowego, to znaczy pomiar siatki n x nskładający się z liczb, 1przez n^2które są nawinięte wokół siebie w następujący sposób:

Wejście n = 3:

7 8 9
6 1 2
5 4 3

Wejście n = 4:

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

Wejście 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

(Zainspirowany tym problemem z Project Euler.)

To jest , wygrywa najkrótsza odpowiedź w bajtach!

Juliusz
źródło
4
Przykład 4:? Lub dowolna liczba parzysta.
TheLethalCoder
1
Czy możemy założyć, że dane wejściowe są nieparzyste?
Pan Xcoder,
1
Powiązane
Emigna
2
Możliwy dupek ?
Shaggy
1
Zobacz także perlmonks.com/?node_id=487200 z wieloma rozwiązaniami i linkami w odpowiedziach.
b_jonas

Odpowiedzi:

43

MATL , 3 bajty

1YL

Wypróbuj online!

Wyjaśnienie

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

Luis Mendo
źródło
31
Dlaczego ... dlaczego jest to wbudowane?
TheLethalCoder
2
Zgaduję, że to ma coś wspólnego z „magicznym kwadratem”?
Magic Octopus Urn
8
@TheLethalCoder Ponieważ Matlab miał go i pomyślałem byłoby ( który to jest rzeczywiście )
Luis Mendo
18

C #, 203 202 196 193 178 bajtów

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

Zapisano bajt dzięki @StefanDelport.
Zaoszczędź 22 bajty dzięki @FelipeNardiBatista.

Działa to poprzez następującą obserwację budowy kwadratów:

Obraz kwadratu, gdzie n = 5

Jak widać, każdy bit jest dodawany do poprzedniego kwadratu. W przypadku liczb parzystych idziemy na prawo od miejsca, w którym się znajdujemy, aż do jednego, który jest niższy niż tam, gdzie był kwadrat, a następnie do końca. Liczby nieparzyste są w zasadzie odwrotne, idziemy w lewo, do góry, aż są powyżej aktualnej wysokości, a następnie w prawo do końca.

Wersja pełna / sformatowana:

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
źródło
1
++i<=n;może się stać n>++i, nic więcej nie widzę, +1.
LiefdeWen
1
n%2<1?2:1do 2-x%2? Nie testowałem tego w C #, ale w C i Python działało.
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; ....grał trochę w golfa
Felipe Nardi Batista
@FelipeNardiBatista Awesome nigdy nie pomyślałby o tych dwóch! Dzięki.
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 bajtów

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

Wypróbuj online!

W jaki sposób?

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

oblicza różnice między wskaźnikami; 1i ¯1dla prawej i lewej ¯⍵oraz dla góry i dołu.

1,⊢,¯1,-pojawia się jako 1 ⍵ ¯1 ¯⍵, +⍨⍴rozciąga tę tablicę na długość ⍵×2, dzięki czemu finał 2/⍳może powtórzyć każdy z nich, a liczba powtórzeń wzrasta co drugi element:

      (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

następnie,

(⌈2÷⍨×⍨),

przygotowuje lewy górny element spirali,

×⍨↑

ograniczyć pierwsze ⍵ 2 elementy tej listy odległości,

+\

dokonuje skumulowanej sumy,

ocenia indeksy ( ⍵[i] = ⍵[⍵[i]]), aby przetłumaczyć pierwotną macierz na indeksy każdego elementu, i na koniec

,⍨⍴

kształty jako ⍵×⍵matryca.

Uriel
źródło
Dla zainteresowanych ta technika została szczegółowo omówiona w tym doskonałym artykule .
Jonasz
9

C, 321 307 295 284 283 282 bajtów

Dzięki zarówno @Zachary T, jak i @Jonathan Frech za grę w bajt!

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

Przydziela dwuwymiarową tablicę zer, a następnie zaczyna wypełniać ją gdzieś pośrodku. Na koniec drukowane są wartości, które są większe od zera, ale mniejsze lub równe kwadratowi wejścia.

Wypróbuj online!

Sformatowany:

#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
źródło
1
Czy to możliwe, aby wymienić i,j,k,a,b,m;f(n){n*=n;int**l=calloc(a=m=3*n,4);się i,j,k,a,b,m,**l;f(n){n*=n;l=calloc(a=m=3*n,4);zapisać bajt?
Zacharý
1
Możesz być w stanie wymienić k<=n;z n>k;zapisać bajt.
Jonathan Frech,
6

PHP , 192 bajty

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

Wypróbuj online!

W ten sam sposób buduj ciąg zamiast tablicy

PHP , 217 bajtów

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

Wypróbuj online!

Jörg Hülsermann
źródło
1
[-1,1][$d&1]->$d&1?:-1
Titus
@Titus Dziękuję Nie widziałem
Jörg Hülsermann
1
Oto jeszcze jeden bajt: for(;$k<$a;print join($o)."\n")ksort($o=&$e[+$k++]);. I jeszcze jedno: "%$l".d. I jeszcze jedno: $x*$l*$a+$y*$l-> ($x*$a+$y)*$l.
Tytus
1
I myślę, że w drugiej wersji można zainicjować $sdo wypełnionego podkreślenia (lub litery lub cyfry); ta postać zostanie nadpisana.
Titus
@Titus Dziękuję i możesz użyć .dwłasnego podejścia, aby zaoszczędzić 2 bajty
Jörg Hülsermann
6

PHP, 185 176 174 bajtów

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

Uruchom jako potok -nRlub przetestuj go online .

awaria

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
}
Tytus
źródło
6

APL (Dyalog Classic) , 32 29 bajtów

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

Wypróbuj online!

Zastosowania ⎕io←1. Zaczyna się od macierzy 0 na 1 ( ⍪⍬). 2N razy ( ⍣2⍣⍵) dodaje wysokość macierzy ( ≢⍵) do każdego z jej elementów, umieszcza ją 1 2...heightpo prawej ( ,⌸) i obraca ( ⌽⍉). Po zakończeniu poprawia orientację wyniku ( ⊖∘⌽⍣⍵⌽) i odwraca liczby, odejmując je od N 2 +1 ( 1+×⍨-).

ngn
źródło
5

Mathematica, 177 bajtów

(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
źródło
8
Waaait, nie ma wbudowanego tego w Mathematica?
Pan Xcoder,
5

C ++, 245 228 bajtów

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

Wypróbuj online!

Funkcja oblicza i drukuje wartość każdej liczby macierzy w zależności od jej pozycji x, y , stosując następującą logikę:

Obliczanie wartości węża w zależności od pozycji

Wersja sformatowana :

#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
źródło
5

Python 3 , 249 247 bajtów

Inicjuję tablicę 2D i znajduję punkt początkowy, który jest środkiem nieparzystego n lub przesunięciem (-1, -1) dla parzystego n, a następnie skaluję wzór wypełnienia / kursora za pomocą bieżącego numeru „pierścienia”. Wydaje mi się, że nie potrafię interpretować wskazówek, ale nie wymyśliłem nic tańszego.

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

Wypróbuj online!

-2 dzięki Zachary T.

noktama
źródło
jak policzyłeś swoje bajty? liczą się także tabulatory, spacje i znaki nowej linii
Felipe Nardi Batista
Zamieniłem każdy \ n i \ t na „” i wziąłem len (). Właśnie skopiowałem powyższe i przerobiłem, aby upewnić się, że nic nie zmienię i zapomnę przeliczyć, ale otrzymałem ten sam numer. Przegapiłem coś?
nokturama
liczę \ti \njako 1 bajt wciąż otrzymuję 249 bajtów
Felipe Nardi Batista
e: ^^^ Czy jest lepsza / łatwiejsza metoda, której powinienem użyć? zawsze wydawały mi się używane zamiennie. ^^^ Dziwne, oto co dostaję w 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
zwykle redaktorzy tekstowi mówią ci, ile znaków jest wybranych, więc CTRL + A i czytaj, co mówi
Felipe Nardi Batista
5

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

Bajt mierzony w UTF8, \[LeftFloor]( ) i \[RightFloor]( ) kosztuje 3 bajty każdy. Mathematica nie ma żadnego specjalnego zestawu znaków bajtów.

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}]&

Wypróbuj online!


Używa zamkniętego formularza dla każdego z 4 przypadków, a następnie dokłada maksimum ostrożnie, aby uzyskać pożądany wynik.

Zwraca tablicę liczb całkowitych 2D. Nie jestem pewien, czy jest to dozwolone i chociaż zostało to poproszone w komentarzach , OP nie odpowiedział.

użytkownik202729
źródło
4

Clojure, 206 bajtów

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

Wydaje mi się, że to przyzwoity początek, buduje tablicę w sekwencji na mapie mieszającej, a następnie dzieli ją na n x nlisty. Który defmacrozakończył się dość długo, ale kod jest jeszcze krótszy z nim niż bez. Czy istnieje więcej składni succint, aby to opisać?

Większość bajtów oblicza punkt początkowy i buduje logikę wyszukiwania dla następnej prędkości v. Być może zagnieżdżenie vecbyłoby lepsze, ale wtedy masz dwa indeksy i prędkości do śledzenia.

NikoNyrh
źródło
3

J , 41 bajtów

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

Wypróbuj online!

Robi to samo co składanie APL ngn, ale zaczyna się od macierzy 1 na 1 i powtarza 2 × N − 2 razy.

FrownyFrog
źródło
Czy możesz ulepszyć moje alternatywne podejście (teraz związane w wieku 41 lat), aby pokonać siebie? Dałem mu jak dotąd najlepszy golf, ale podejrzewam, że można jeszcze wygolić jeszcze kilka bajtów.
Jonasz
1

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

Spowoduje to utworzenie tablicy numpy, a następnie obrócenie jej i dodanie boku, aż do uzyskania prawidłowego rozmiaru. Pytanie nie określało, czy ten sam punkt początkowy musi być użyty dla liczb parzystych i nieparzystych, jeśli tak nie jest, linię if n%2==0:a=r(r(a))można usunąć, oszczędzając 21 bajtów.

użytkownik2699
źródło
1
to nie jest Python, to Python + numpy
tylko ASCII
@ Tylko ASCII Czy jest gdzieś główna lista dopuszczalnych nazw języków? Jest to całkowicie poprawny python.
user2699
Korzysta z biblioteki, więc musisz także podać nazwę biblioteki ... tak jak w przypadku dozwolonych języków, każdy język z publicznie dostępną implementacją, którą można uruchomić, jest dozwolony
tylko ASCII
@ ASCII-tylko gdzie to jest napisane? Nie widziałem, aby zrobiono to z większością odpowiedzi na python.
user2699
Tak, ponieważ większość z nich nie używa numpy ... a stdlib nie liczy się jako biblioteka zewnętrzna
tylko ASCII
0

J , 41 bajtów

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

standardowe formatowanie

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

Podejście to opiera się na At Play With J Volutes (APL Uriela używa podobnej techniki).

Jest to nieoczekiwane i wystarczająco eleganckie, aby uzasadnić odpowiedź na drugie pytanie, pomyślałem.

Zasadniczo nie robimy nic proceduralnego ani nawet geometrycznego. Zamiast tego tworzymy arytmetycznie prostą sekwencję, która po zsumowaniu i stopniowaniu skanu daje prawidłową kolejność spiralnej liczby od lewej do prawej, od góry do dołu. Następnie kształtujemy to w matrycę i gotowe.

Dodam bardziej szczegółowe wyjaśnienie, gdy pozwala na to czas, ale link do artykułu wyjaśnia to dogłębnie.

Wypróbuj online!

Jonasz
źródło
0

Python 3 (bez stosu) , 192 188 179 150 bajtów

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)

Wypróbuj online!

(2y+1)2(yx)2yr

Zapisane 4 bajty, ponieważ obrót fazorów o 90 stopni można łatwo wykonać bez liczb zespolonych

SmileAndNod
źródło
0

R 183 bajtów

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

Wypróbuj online!

Wyjście to wąż matrycowy (lub matryca wężowa, cokolwiek). Prawdopodobnie nie jest to najskuteczniejsza metoda i prawdopodobnie można ją grać w golfa, ale pomyślałem, że warto ją pokazać. Właściwie jestem z tego dumny!

Metoda buduje macierz od środka, zawsze dodając dodatkową liczbę liczb całkowitych równą liczbie kolumn w macierzy przed dołączeniem. Poniższy wzorzec wiąże albo kolumny, albo wiersze, jednocześnie odwracając niektóre wartości, aby były dołączane we właściwej kolejności.

193 bajtów

Dokładnie tak samo jak powyżej, ale ostateczny bjest

matrix(b,x)

Wypróbuj online!

co daje nieco czystszy wynik, ale nie widziałem żadnych specjalnych kryteriów dla wyjścia, więc pierwsza odpowiedź powinna zadziałać, jeśli się nie mylę.

Sumner18
źródło