Spiralne dzielnice

19

Jeśli weźmiemy liczby naturalne i zwiniemy je przeciwnie do ruchu wskazówek zegara w spiralę, otrzymamy następującą nieskończoną spiralę:

                  ....--57--56
                             |
36--35--34--33--32--31--30  55
 |                       |   |
37  16--15--14--13--12  29  54
 |   |               |   |   |
38  17   4---3---2  11  28  53
 |   |   |       |   |   |   |
39  18   5   0---1  10  27  52
 |   |   |           |   |   |
40  19   6---7---8---9  26  51
 |   |                   |   |
41  20--21--22--23--24--25  50
 |                           |
42--43--44--45--46--47--48--49

Biorąc pod uwagę pewną liczbę w tej spirali, Twoim zadaniem jest określenie jej sąsiadów - co oznacza element powyżej, po lewej, po prawej i poniżej.

Przykład

Jeśli przyjrzymy się temu 27, zobaczymy, że ma on następujących sąsiadów:

  • powyżej: 28
  • lewo: 10
  • dobrze: 52
  • poniżej: 26

Tak więc wynik będzie: [28,10,52,26]

Zasady

  • Wejście będzie liczbą w dowolnym domyślnym formacie We / Wyn0
  • Wyjście będzie listą / macierzą / .. 4 sąsiadów tych liczb w dowolnej (spójnej!) Kolejności
  • Możesz pracować ze spiralą, która zaczyna się od 1 zamiast 0, jednak powinieneś to określić w swojej odpowiedzi

Przykłady

Dane wyjściowe są w formacie [above,left,right,below]i wykorzystują spiralę opartą na 0:

0  ->  [3,5,1,7]
1  ->  [2,0,10,8]
2  ->  [13,3,11,1]
3  ->  [14,4,2,0]
6  ->  [5,19,7,21]
16  ->  [35,37,15,17]
25  ->  [26,24,50,48]
27  ->  [28,10,52,26]
73  ->  [42,72,74,112]
101  ->  [100,146,64,102]
2000  ->  [1825,1999,2001,2183]
1000000  ->  [1004003,1004005,999999,1000001]
ბიმო
źródło
powiązane
ბიმო

Odpowiedzi:

6

R , 156 bajtów

function(n){g=function(h)c(0,cumsum(h((4*(0:(n+2)^2)+1)^.5%%4%/%1/2)))
x=g(sinpi)
y=g(cospi)
a=x[n]
b=y[n]
which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))}

Wypróbuj online!

  • opublikował kolejną odpowiedź R, ponieważ jest to nieco inne podejście niż @ngn
  • 1-indeksowany
  • sąsiedzi są zawsze sortowani według wartości rosnącej
  • zapisywane 6 bajtów usuwanie roundi obsługa cospi(x)/sinpi(x)które są bardziej precyzyjne niż cos(x*pi)/sin(x*pi)w przypadku numerów (pół 0.5, 1.5etc ...)
  • zapisano kolejny bajt usuwając minus na współrzędnych y, ponieważ wynik jest taki sam (tylko sąsiadów góra / dół są odwrócone)

Objaśnienie:

Jeśli spojrzymy na współrzędne macierzy wartości, biorąc pod uwagę pierwszą 0umieszczoną wartość x=0, y=0, są to:

x = [0,  1,  1,  0, -1, -1, -1,  0,  1,  2,  2,  2,  2,  1,  0, ...] 
y = [0,  0,  1,  1,  1,  0, -1, -1, -1, -1,  0,  1,  2,  2,  2, ...]

Te xwspółrzędne śledzić sekwencję A174344 OEIS z rekurencyjne o wzorze:

a(1) = 0, a(n) = a(n-1) + sin(mod(floor(sqrt(4*(n-2)+1)),4)*pi/2)

Ta sama formuła obowiązuje dla ywspółrzędnych macierzy, ale z coszamiast sini z negacją:

a(1) = 0, a(n) = a(n-1) - cos(mod(floor(sqrt(4*(n-2)+1)),4)*pi/2)

Tak więc w R możemy przetłumaczyć wzór na tę funkcję, przyjmując sinpi/cospijako parametr:

g=function(h)c(0,cumsum(h((4*(0:(n+2)^2)+1)^.5%%4%/%1/2)))

i generujemy dwa wektory współrzędnych (nie negujemy współrzędnych y, ponieważ otrzymamy ten sam wynik, tylko z odwróconymi sąsiadami góra / dół):

x=g(sinpi)
y=g(cospi)

Zauważ, że wygenerowaliśmy (n+2)^2współrzędne, które są większe niż minimalne niezbędne współrzędne zawierające zarówno nich, jak i ich sąsiadów (ściślejsza granica byłaby, (floor(sqrt(n))+2)^2ale niestety jest mniej „golfowa”).

Dlatego teraz, gdy mamy już wszystkie współrzędne, najpierw szukamy współrzędnych a,bodpowiadających naszym n:

a=x[n]
b=y[n]

w końcu wybieramy pozycje ich sąsiadów, tj .:

  • góra / dół sąsiedzi where x == a and y == b+1 or b-1
  • prawi / lewi sąsiedzi where y == b and x == a+1 or a-1

za pomocą :

which(x==a&(y==b+1|y==b-1)|y==b&(x==a+1|x==a-1))
digEmAll
źródło
„nieco inny” :)
ngm
@ngm: eheh ... ponieważ użyty przez ciebie kod rozety jest dla mnie dość „niejasny”, założyłem, że w jakiś sposób generuje indeksy pozycji macierzy w inny, ale podobny sposób niż moje sekwencje OEIS: D
digEmAll
4

Perl 6 , 94 83 bajtów

{my \ s = 0, | [+] flat ((1, i ... ) Zxx flat (1..Inf Z 1..Inf)); map {first: k, s [$ _] + $ ^ d, s}, i, -1,1, -i}

{my \s=0,|[\+] flat((1,*i...*)Zxx(1,1.5...*));map {first :k,s[$_]+$^d,s},i,-1,1,-i}

Wypróbuj online!

sto leniwa, nieskończona lista współrzędnych spiralnych, reprezentowana jako liczby zespolone. Jest zbudowany z dwóch innych nieskończonych list: 1, *i ... *tworzy listę 1, i, -1, -i .... 1, 1.5 ... *tworzy listę 1, 1.5, 2, 2.5, 3, 3.5 .... Skompresowanie tych dwóch list razem z listy replikacji produkuje lista kroków od każdej spirali współrzędnych do drugiego: 1, i, -1, -1, -i, -i, 1, 1, 1, i, i, i .... (Ułamkowe części argumentów po prawej stronie operatora replikacji listy są odrzucane.) Wykonanie trójkątnej redukcji dodawania ( [\+]) na tej liście (i wklejenie 0 na początku) tworzy listę współrzędnych spiralnych.

Wreszcie, zaczynając od liczby zespolonej s[$_] ( $_jako jedyny argument funkcji), patrzymy w górę indeksy ( first :k) w spirali z liczb zespolonych, które są odsunięte od tego numeru, i, -1, 1, i -i.

Sean
źródło
4

Brain-Flak , 238 bajtów

((){[()]<((({}[((()))]<>)<<>{((([{}]({}))([{}]{})())[()]){({}[()])<>}{}}>)<<>({}<(((({}{})()){}<>({}))()())<>>)<>>()())<>{{}((()()()[({})]){}<>({}<{}>))(<>)}>}{}){<>((((())()())()())()())(<>)}{}{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>

Wypróbuj online!

Wyjście jest w kolejności lewo, góra, prawo, dół.

Wyjaśnienie

# If n is nonzero:
((){[()]<

  ((

    # Push 1 twice, and push n-1 onto other stack.
    ({}[((()))]<>)

    # Determine how many times spiral turns up to n, and whether we are on a corner.
    # This is like the standard modulus algorithm, but the "modulus" used
    # increases as 1, 1, 2, 2, 3, 3, ...
    <<>{((([{}]({}))([{}]{})())[()]){({}[()])<>}{}}>

  # Push n-1: this is the number behind n in the spiral.
  )<

    # While maintaining the "modulus" part of the result:
    <>({}<

      # Push n+2k+1 and n+2k+3 on top of n-1, where k is 3 more than the number of turns.
      # n+2k+1 is always the number to the right in the direction travelled.
      # If we are on a corner, n+2k+3 is the number straight ahead.
      (((({}{})()){}<>({}))()())<>

    >)<>

  # Push n+1.  If we are on a corner, we now have left, front, right, and back
  # on the stack (from top to bottom)
  >()())

  # If not on a corner:
  <>{{}

    # Remove n+2k+3 from the stack entirely, and push 6-2k+(n+1) on top of the stack.
    ((()()()[({})]){}<>({}<{}>))

  (<>)}

>}{})

# If n was zero instead:
{

  # Push 1, 3, 5, 7 on right stack, and implicitly use 1 (from if/else code) as k.
  <>((((())()())()())()())

(<>)}{}

# Roll stack k times to move to an absolute reference frame
# (switching which stack we're on each time for convenience)
{({}[()]<<>({}<>)<>({}<({}<({}<>)>)>)<>>)}<>
Nitrodon
źródło
Bardzo imponujące! Chyba nie generujesz całej spirali jak inni?
ბიმო
3

MATL , 15 bajtów

2+1YLtG=1Y6Z+g)

Wejścia i wyjścia są oparte na 1.

Dane wyjściowe podaje lewego, dolnego, górnego i prawego sąsiada w tej kolejności.

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe oprócz dwóch ostatnich, które przekroczą limit czasu w TIO.

2+      % Implicit input: n. Add 2. This is needed so that
        % the spiral is big enough
1YL     % Spiral with side n+2. Gives a square matrix
t       % Duplicate
G=      % Compare with n, element-wise. Gives 1 for entry containing n
1Y6     % Push 3×3 mask with 4-neighbourhood
Z+      % 2D convolution, keeping size. Gives 1 for neighbours of the
        % entry that contained n
g       % Convert to logical, to be used as an index
)       % Index into copy of the spiral. Implicit display
Luis Mendo
źródło
2
1YL- MATLAB ma spiralfunkcję? Kiedy MATLAB zmienił się w Mathematica ?!
Sundar - Przywróć Monikę
Tak, obejrzałem to po zobaczeniu, co oznacza 1YL, a ten kod Rosetta był jedynym miejscem, w którym mogłem znaleźć potwierdzenie, że jest to MATLAB, a nie tylko funkcja MATL. Zaczynałem myśleć, że to może być coś, co dodałeś do gry w MATL, dopóki nie zobaczyłem tego wpisu.
sundar - Przywróć Monikę
@sundar Dziwne, że nie jest to już udokumentowane
Luis Mendo
3

R , 172 bajty

function(x,n=2*x+3,i=cumsum(rep(rep(c(1,n,-1,-n),l=2*n-1),n-seq(2*n-1)%/%2))){F[i]=n^2-1:n^2
m=matrix(F,n,n,T)
j=which(m==x,T)
c(m[j[1],j[2]+c(-1,1)],m[j[1]+c(-1,1),j[2]])}

Wypróbuj online!

To jest R, więc oczywiście odpowiedź ma indeks 0.

Większość pracy polega na tworzeniu matrycy. Kod inspirowany przez: https://rosettacode.org/wiki/Spiral_matrix#R

ngm
źródło
2

JavaScript (ES6), 165 bajtów

Drukuje indeksy za pomocą alert().

f=(n,x=w=y=n+2)=>y+w&&[0,-1,0,1].map((d,i)=>(g=(x,y,A=Math.abs)=>(k=A(A(x)-A(y))+A(x)+A(y))*k+(k+x+y)*(y>=x||-1))(x+d,y+~-i%2)-n||alert(g(x,y)))|f(n,x+w?x-1:(y--,w))

Wypróbuj online!

W jaki sposób?

x,yZjax,y

ZAx,y=||x|-|y||+|x|+|y|
S.x,y={1,gdyby yx-1,gdyby y<x
jax,y=ZAx,y2)+(ZAx,y+x+y)×S.x,y

(na podstawie tej odpowiedzi z math.stackexchange)

Arnauld
źródło
To wydaje się działać dobrze z mniejszych ilościach, ale pojawia się błąd podczas testowania tego z dużą liczbą jak 2000. Błąd na tio.run: RangeError: Maximum call stack size exceededi błędów w konsoli przeglądarki: InternalError: too much recursion. czy robię coś źle?
Night2,
1
4n2)
2

Python 2 , 177 164 1 46 144 bajtów

def f(n):N=int(n**.5);S=N*N;K=S+N;F=4*N;return[n+[F+3,[-1,1-F][n>K]][n>S],n+[F+5,-1][n>K],n+[[1,3-F][n<K],-1][0<n==S],n+[F+7,1][n<K]][::1-N%2*2]

Wypróbuj online!

Oblicza u,l,r,dbezpośrednio z n.

Chas Brown
źródło
1

PHP (> = 5,4), 208 bajtów

<?$n=$argv[1];for(;$i++<($c=ceil(sqrt($n))+($c%2?2:3))**2;$i!=$n?:$x=-$v,$i!=$n?:$y=+$h,${hv[$m&1]}+=$m&2?-1:1,$k++<$p?:$p+=$m++%2+$k=0)$r[-$v][+$h]=$i;foreach([0,1,0,-1]as$k=>$i)echo$r[$x+$i][$y+~-$k%2].' ';

Aby uruchomić:

php -n -d error_reporting=0 <filename> <n>

Przykład:

php -n -d error_reporting=0 spiral_neighbourhoods.php 2001

Lub wypróbuj online!

Uwagi:

  • -d error_reporting=0Opcja nie służy do wyjścia zawiadomień / ostrzeżenia.
  • Ta spirala zaczyna się od 1.

W jaki sposób?

Generuję spiralę ze zmodyfikowaną wersją tej odpowiedzi w 2-wymiarowej tablicy.

Decyduję o wielkości spirali na podstawie danych wejściowych nz formułą, aby zawsze uzyskać dodatkową rundę liczb w spirali (gwarancja istnienia powyżej / poniżej / lewej / prawej). Dodatkowa runda liczb oznacza +2wysokość i +2szerokość dwuwymiarowego układu.

Jeśli więc nzostanie umieszczony w spirali o maksymalnym rozmiarze 3*3, wygenerowana będzie spirala 5*5.

Spirala rozmiar jest c*cgdzie c = ceil(sqrt(n)) + k, jeśli ceil(sqrt(n))jest nieparzysta, to kjest 2, a jeśli ceil(sqrt(n))nawet, to kjest 3.

Na przykład powyższa formuła spowoduje:

  • Jeśli n = 1to c = 3i rozmiar spirali będzie3*3
  • Jeśli n <= 9to c = 5i rozmiar spirali będzie5*5
  • Jeśli n <= 25to c = 7i rozmiar spirali będzie7*7
  • Jeśli n <= 49to c = 9i rozmiar spirali będzie9*9
  • I tak dalej ...

Podczas generowania spiralę, przechowywać xi yod ni po pokoleniu, wyjście I elementy powyżej / poniżej / lewo / prawo od niego.

Noc 2
źródło