Rotacja Czebyszewa


36

Rozważ zwykłą siatkę, w której każda komórka ma współrzędne całkowite. Możemy pogrupować komórki w (kwadratowe) „pierścienie”, w których komórki w każdym pierścieniu mają tę samą odległość Czebyszewa (lub odległość szachownicy) od początku. Twoim zadaniem jest przyjęcie takiej współrzędnej komórki i obrócenie tej komórki o jedną pozycję przeciwnie do ruchu wskazówek zegara w obrębie jej pierścienia. To implementuje następujące mapowanie:

wprowadź opis zdjęcia tutaj

Na przykład, jeśli dane wejściowe to (3, -2)powinieneś wyjść (3, -1). Zauważ, że (0, 0)to jedyne wejście, które powinno być odwzorowane na siebie.

Zasady

Format we / wy jest dość elastyczny. Możesz użyć dwóch pojedynczych liczb, pary / listy / tablicy / krotki liczb, pojedynczej liczby zespolonej, ciągu zawierającego dwie liczby itp.

Możesz to założyć -128 < x,y < 128.

Możesz napisać program lub funkcję i użyć dowolnej z naszych standardowych metod otrzymywania danych wejściowych i dostarczania danych wyjściowych.

Możesz używać dowolnego języka programowania , ale pamiętaj, że te luki są domyślnie zabronione.

To jest , więc wygrywa najkrótsza ważna odpowiedź - mierzona w bajtach .

Przypadki testowe

(0, 0)       => (0, 0)
(1, 0)       => (1, 1)
(1, 1)       => (0, 1)
(0, 1)       => (-1, 1)
(-1, 1)      => (-1, 0)
(-1, 0)      => (-1, -1)
(-1, -1)     => (0, -1)
(0, -1)      => (1, -1)
(1, -1)      => (1, 0)
(95, -12)    => (95, -11)
(127, 127)   => (126, 127)
(-2, 101)    => (-3, 101)
(-65, 65)    => (-65, 64)
(-127, 42)   => (-127, 41)
(-9, -9)     => (-8, -9)
(126, -127)  => (127, -127)
(105, -105)  => (105, -104)

Czy możemy łączyć format wejściowy i wyjściowy, np. Pobrać krotkę i wyprowadzić liczbę zespoloną?
Dennis

@Dennis tak, w porządku.
Martin Ender

Odpowiedzi:


16

JavaScript (ES6), 60 59 bajtów

Pobiera dane wejściowe ze składnią curry (x)(y)i zwraca tablicę [new_x, new_y].

x=>y=>(x|y&&((z=x+(y<0))>-y?z>y?y++:x--:z>y?x++:y--),[x,y])

Jak to działa

Naszym głównym zadaniem jest określenie, w której kwadrancie jesteśmy, abyśmy wiedzieli, w którym kierunku się poruszać.

Możemy użyć tej formuły jako pierwszego przybliżenia:

x > -y ? (x > y ? 0 : 1) : (x > y ? 2 : 3)

Oto, co otrzymujemy:

3 1 1 1 1 1 1 1 1
3 3 1 1 1 1 1 1 0
3 3 3 1 1 1 1 0 0
3 3 3 3 1 1 0 0 0
3 3 3 3 3 0 0 0 0
3 3 3 3 2 2 0 0 0
3 3 3 2 2 2 2 0 0
3 3 2 2 2 2 2 2 0
3 2 2 2 2 2 2 2 2

Prawie na miejscu. Ale dolne lewe i prawe dolne rogi pierścieni są nieprawidłowe. Musimy przesunąć dolną połowę macierzy o jedną pozycję w lewo, dlatego definiujemy zjako:

z = y < 0 ? x + 1 : x

I zamieniamy xz znaszego wzoru:

z > -y ? (z > y ? 0 : 1) : (z > y ? 2 : 3)

Który prowadzi do:

3 1 1 1 1 1 1 1 1 
3 3 1 1 1 1 1 1 0 
3 3 3 1 1 1 1 0 0 
3 3 3 3 1 1 0 0 0 
3 3 3 3 3 0 0 0 0 
3 3 3 2 2 0 0 0 0 
3 3 2 2 2 2 0 0 0 
3 2 2 2 2 2 2 0 0 
2 2 2 2 2 2 2 2 0 

Cała macierz jest teraz poprawna, z wyjątkiem specjalnego przypadku [0, 0](brak ruchu), który należy rozwiązać osobno.

Przypadki testowe


13

Galaretka , 20 14 12 bajtów

S;IṠN0n/¦Ạ¡+

Dane wejściowe i wyjściowe mają postać tablic. Wypróbuj online! lub zweryfikuj wszystkie przypadki testowe .

tło

Aby dowiedzieć się, w którym kierunku musimy się poruszać, możemy zaobserwować względne położenie punktu początkowego do dwusiecznych kwadrantu x + y = 0 (niebieski) i x - y = 0 (czerwony).

diagram

  • Pochodzenie jest ustalone. Przechodzimy dalej, dodając [0, 0] do punktu początkowego.

  • Punkty w najwyższym trójkącie - w tym bisektor pierwszej ćwiartki - mają sumę dodatnią i nieujemną deltę ( y - x ). Przechodzimy dalej, dodając [-1, 0] do punktu początkowego.

  • Punkty w lewym trójkącie - w tym dwusieczna drugiej ćwiartki - mają nie dodatnią sumę i dodatnią deltę. Przechodzimy dalej, dodając [0, -1] do punktu początkowego.

  • Punkty w najniższym trójkącie - w tym dwusieczna trzeciego kwadrantu - mają sumę ujemną i różnicę dodatnią. Przechodzimy dalej, dodając [1, 0] do punktu początkowego.

  • Punkty w prawym trójkącie - w tym dwusieczna czwartej ćwiartki - mają sumę nieujemną i deltę ujemną. Przechodzimy dalej, dodając [0, 1] do punktu początkowego.

Aby ustalić właściwy kierunek, obliczamy [-sign (x + y), -sign (y - x)] , który ma tylko dziewięć możliwych wyników.

Poniższa tabela ilustruje, które wyniki muszą zostać zmapowane do jakich kierunków.

    sign(x+y) |  sign(y-x) | -sign(x+y) | -sign(y-x) |     Δx     |     Δy
  ------------+------------+------------+------------+------------+------------
        0     |      0     |      0     |      0     |      0     |      0
        1     |      0     |     -1     |      0     |     -1     |      0
        1     |      1     |     -1     |     -1     |     -1     |      0
        0     |      1     |      0     |     -1     |      0     |     -1
       -1     |      1     |      1     |     -1     |      0     |     -1
       -1     |      0     |      1     |      0     |      1     |      0
       -1     |     -1     |      1     |      1     |      1     |      0
        0     |     -1     |      0     |      1     |      0     |      1
        1     |     -1     |     -1     |      1     |      0     |      1

To pozostawia trzy przypadki.

  • Jeśli co najmniej jeden ze znaków to 0 , [Δx, yy] = [-sign (x + y), -sign (yx)] .

  • Jeśli znaki są równe i niezerowe, [Δx, yy] = [-sign (x + y), 0] .

  • Jeśli znaki są różne i niezerowe, [Δx, yy] = [0, -sign (yx)] .

Jak to działa

S;IṠN0n/¦Ạ¡+  Main link. Argument: [x, y] (pair of integers)

S             Sum; compute x + y.
  I           Increments; compute [y - x].
 ;            Concatenate; yield [x + y, y - x].
   Ṡ          Sign; compute [sign(x + y), sign(y - x)].
    N         Negate; yield [-sign(x + y), -sign(y - x)].
          ¡   Do n times:
         Ạ      Set n to all([-sign(x + y), -sign(y - x)]), i.e., 1 if the signs
                are both non-zero and 0 otherwise.
        ¦       Conditional application:
      n/          Yield 1 if the signs are not equal, 0 if they are.
     0            Replace the coordinate at 1 or 0 with a 0.
              This returns [Δx, Δy].
           +  Add; yield  [Δx + x, Δy + y].


5

Python, 55 bajtów

lambda x,y:(x-(-y<x<=y)+(y<=x<-y),y+(~x<y<x)-(x<y<=-x))

Wykrywa cztery kwadraty ukośne i przesuwa odpowiednią współrzędną.


4

Haskell, 77 71 69 bajtów

x#y|y>=x,-x<y=(x-1,y)|y>x=(x,y-1)|y< -x=(x+1,y)|y<x=(x,y+1)|1>0=(0,0)

Sprawdza to po prostu każdą z tych nachylonych ćwiartek i odpowiednio modyfikuje dane wejściowe. Zauważ, że spacje są konieczne, w przeciwnym razie np. >-Będzie rozumiany jako operator (który nie jest zdefiniowany).

Dziękuję @nimi za usunięcie kilku kolejnych bajtów!


,zamiast w&& obrębie pierwszego strażnika zapisuje bajt. Następnie możesz przełączyć drugie porównanie -x<yna inny bajt.
nimi

Dziękuję, nie wiedziałem o tym ,!
flawr

4

Ruby, 68

Funkcja Lambda przyjmuje jako argument liczbę zespoloną, zwraca liczbę zespoloną.

->z{k=1
4.times{z*=?i.to_c
x,y=z.rect
y*y>=x*x&&y<-x&&(z+=k;k=0)}
z} 

Obracamy punkt o 90 stopni 4 razy, mnożąc przez i. W związku z tym przechodzi przez wszystkie 4 ćwiartki i zostanie zwrócony w niezmienionej formie - z wyjątkiem tego, że modyfikujemy go, gdy znajduje się w jednym z nich. Fakt, że zawsze jest modyfikowany w tej samej ćwiartce, upraszcza modyfikację.

Najłatwiej jest naśladować, jeśli zmienimy go, zgdy znajduje się on w prawej ćwiartce. w tym przypadku musimy zwiększyć współrzędną y o 1 (tj. dodać ido z.)

Sprawdzamy x.abs>=y.abs, porównując kwadraty xi y. To mówi nam, że punkt znajduje się w prawej lub lewej ćwiartce, a nie u góry lub u dołu. Aby sprawdzić to w rzeczywistości w kwadrancie stroną możemy dodatkowo sprawdzić, że x>y(ściśle większa, ponieważ chcemy, aby wykluczyć przypadek, x=yktóry należy do „top” ćwiartce.) Jeżeli to prawda dodamy ido z.

Z powodów golfowych dodawanie inie jest pożądane. Zamiast tego modyfikujemy liczbę, gdy znajduje się ona w dolnej ćwiartce, w którym to przypadku musimy dodać 1 do xwspółrzędnej (dodać 1 do z.) W tym przypadku testujemy, y*y>=x*xaby sprawdzić, czy jest ona w górnej lub dolnej ćwiartce. Aby dodatkowo upewnić się, że znajduje się w dolnej ćwiartce, musimy to sprawdzić y<-x(ściśle wykluczając przypadek prawego dolnego rogu, gdzie y=-x.)

Zaletą tego sprawdzenia jest to, że nie ma specjalnego przypadku dla współrzędnej 0,0. Niestety stwierdzono, że przesunięcie punktu może przesunąć go do innej ćwiartki, a to oznacza, że ​​drugi ruch musi zostać stłumiony, jeśli ćwiartka zostanie ponownie sprawdzona, co prawdopodobnie neguje przewagę.

Przykład 1

Input                                        95,-12
Rotate 90deg                                 12,95    
Rotate 90deg                                -95,12    
Rotate 90deg                                -12,-95 
Rotate 90deg                                 95,-12
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x     95,-11

The check and alteration of the coordinate is done AFTER the rotation.
Thus in this case it gets done in the 4th iteration of the loop, not the 1st.
If the code were rewritten to do the check and alteration BEFORE the rotation, 
it would be done in the 1st iteration instead of the 4th.

Przykład 2

Input                                        -1,0
Rotate 90deg                                  0,-1
y.abs>=x.abs=TRUE, y<-x=TRUE, increase x      1,-1
Rotate 90deg                                  1,1
Rotate 90deg                                  1,-1
Rotate 90deg                                 -1,-1
y.abs>=x.abs?=TRUE, y<-x=TRUE but DO NOT CHANGE x!

This is an unusual situation due to the fact that the first move caused the
point to advance by one quadrant. We do NOT want to move it again, for this
reason we need to set k to 0 the first time it is moved.

W programie testowym

f=->z{k=1                   #amount to be added to coordinate
4.times{z*=?i.to_c          #iterate 4 times, rotating point by 90deg till it reaches the original orientation
x,y=z.rect                  #separate out x and y for testing
y*y>=x*x&&y<-x&&(z+=k;k=0)} #if y.abs>=x.abs and y negative and not equal -x, move the point and zero k.
z}                          #return z

puts f[Complex(0, 0)]       # (0, 0)
puts f[Complex(1, 0)]       # (1, 1)
puts f[Complex(1, 1)]       # (0, 1)
puts f[Complex(0, 1)]       # (-1, 1)
puts f[Complex(-1, 1)]      # (-1, 0)
puts
puts f[Complex(-1, 0)]      # (-1, -1)
puts f[Complex(-1, -1)]     # (0, -1)
puts f[Complex(0, -1)]      # (1, -1)
puts f[Complex(1, -1)]      # (1, 0)
puts f[Complex(95, -12)]    # (95, -11)
puts f[Complex(127, 127)]   # (126, 127)
puts
puts f[Complex(-2, 101)]    # (-3, 101)
puts f[Complex(-65, 65)]    # (-65, 64)
puts f[Complex(-127, 42)]   # (-127, 41)
puts f[Complex(-9, -9)]     # (-8, -9)
puts f[Complex(126, -127)]  # (127, -127)
puts f[Complex(105, -105)]  # (105, -104)

Diagram

Poniższy obraz pokazuje (niebieski) obszar, w którym x*x>=y*y(żółty) obszar, w którym y<-xi (zielony) ich przecięcie, czyli region, w którym poprawna transformacja jest dodaniem 1 do z.

wprowadź opis zdjęcia tutaj


1
Przepraszam, nie stosuję się do wyjaśnień. Czy mógłbyś dodać przykład lub schemat?
Martin Ender

Dodano wyjaśnienie Martina. To było ciekawe podejście, ale ze względu na potrzebę tłumienia podwójnego ruchu punktów, które zmieniają kwadrant przy pierwszym ruchu, nie okazało się tak eleganckie, jak się spodziewałem.
Level River St

4

Python, 52 bajty

h=lambda z:z and 1j*h(z/1j)if'-'in`z*1j-z-1`else z+1

Złożone dane wejściowe i wyjściowe. Aby przetestować punkt znajdujący się w dolnej ćwiartce przekątnej, najpierw obróć go o 135 w kierunku przeciwnym do ruchu wskazówek zegara, aby przesunąć tę ćwiartkę do standardowej ćwiartki (x> 0, y> 0) i sprawdź, czy wynik nie zawiera symbolu minus w reprezentacji ciągu. Odejmowanie 1 najpierw zajmuje warunek brzegowy.

Jeśli nie ma go w tej ćwiartce, obróć cały problem o 90 stopni. Wejście to zero jest specjalnie obsługiwane do samego wyjścia.

Inne próby z liczbami zespolonymi:

## 56 bytes
## Coordinate input, complex output
q=lambda x,y:(y<=x<-y)*(1j*y-~x)or x+1j*y and 1j*q(y,-x)

## 60 bytes
h=lambda z:(z+1)*(z.imag<=z.real<-z.imag)or z and 1j*h(z/1j)

## 63 bytes
from cmath import*
h=lambda z:z and 1j**(phase(z*1j-z)*2//pi)+z

3

Mathematica, 34 bajty

±0=0
±z_:=z+I^Floor[2Arg@z/Pi+3/2]

Definiuje to jednoargumentowy operator, ±który pobiera i zwraca liczbę zespoloną, której elementy reprezentują xi y.

Teraz, gdy Lynn ujawniła złożone rozwiązanie liczbowe, a Dennis pobił mój wynik, nie czuję się tak źle, publikując moją implementację z golfem. :) (Okazuje się, że jest praktycznie identyczna z odpowiedzią Lynn.)


Czy to pomogłoby? ± 0 = 0 ⁢ ± z_: = z + I ^ ⌊ 2 ⁢ Arg @ z / Pi + 3/2 ⌋ (być może z innym char dla wsporników podłogowych)
DavidC

@DavidC niestety nie dlatego, że wtedy musiałbym użyć kodowania UTF-8, a wtedy ± kosztowałyby 2 bajty każdy.
Martin Ender

Czy nie byłoby to 4 bajty zamiast 7, co daje oszczędność 3 bajtów?
DavidC

@DavidC nie, wsporniki podłogowe będą miały 3 bajty każdy.
Martin Ender

Nie byłam tego świadoma. Ale mimo to powinieneś oszczędzać 1 bajt.
DavidC

3

MATL , 19 17 bajtów

t|?JGJq*X/EYP/k^+

Wykorzystuje to liczby zespolone jako dane wejściowe i wyjściowe.

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie

Weźmy -127+42jza przykład przykład.

t|       % Implicit input. Duplicate and take absolute value
         % STACK: -127+42j, 133.764718816286
?        % If nonzero
         % STACK: -127+42j
  J      %   Push j (imaginary unit)
         %   STACK: -127+42j, j
  GJq*   %   Push input multiplied by -1+j. This adds 3*pi/4 to the phase of the input
         %   STACK: -127+42j, j, 85-169i
  X/     %   Phase of complex number
         %   STACK: -127+42j, j, -1.10478465600433
  EYP/   %   Divide by pi/2
         %   STACK: -127+42j, j, -0.703327756220671
  k      %   Round towards minus infinity
         %   STACK: -127+42j, j, -1
  ^      %   Power
         %   STACK: -127+42j, -j
  +      %   Add
         %   STACK: -127+41j
         % Implicit end
         % Implicit display

3

Rubinowy, 51 bajtów

Oryginalna forma

->x,y{d=x*x-y*y
[x+(d>0?0:-y<=>x),y+(d<0?0:x<=>y)]}

Alternatywna forma dla komentarza Xnora

->x,y{[x+(x*x>y*y ?0:-y<=>x),y+(x*x<y*y ?0:x<=>y)]}

Używa tego samego rodzaju nierówności, co moja inna odpowiedź, ale w inny sposób.

W programie testowym

f=->x,y{d=x*x-y*y
[x+(d>0?0:-y<=>x), #if y.abs>=x.abs: x+=1 if -y>x, x-=1 if -y<x 
y+(d<0?0:x<=>y)]}  #if x.abs>=y.abs: y+=1 if  x>y, y-=1 if  x<y

p f[0, 0]       # (0, 0)
p f[1, 0]       # (1, 1)
p f[1, 1]       # (0, 1)
p f[0, 1]       # (-1, 1)
p f[-1, 1]      # (-1, 0)
puts
p f[-1, 0]      # (-1, -1)
p f[-1, -1]     # (0, -1)
p f[0, -1]      # (1, -1)
p f[1, -1]      # (1, 0)
p f[95, -12]    # (95, -11)
p f[127, 127]   # (126, 127)
puts
p f[-2, 101]    # (-3, 101)
p f[-65, 65]    # (-65, 64)
p f[-127, 42]   # (-127, 41)
p f[-9, -9]     # (-8, -9)
p f[126, -12]   # (127, -127)
p f[105, -105]  # (105, -104)

Czy dzlecenie jest tego warte? Wygląda na to, że możesz po prostu porównać x*x>y*y.
xnor

@Xnor niestety Ruby wymaga spacji między, y*ya ?więc ma dokładnie taką samą długość. Uwzględniłem to, ponieważ myślę, że twoja droga jest pod pewnymi względami ładniejsza. Myślę, że Ruby próbuje y?podać to jako nazwę funkcji prawnej.
Level River St

3

Julia, 38 34 bajtów

!z=z==0?0:z+im^int(2angle(z)/pi+1)

Dennis zapisał cztery bajty. Dzięki!

Wypróbuj online!


Wygląda na to, że pomieszałem zachowanie int z różnymi wersjami Julii (co w mojej obronie jest strasznie niespójne). Julia 0.4 (wersja na TIO) zaokrągla połówki w kierunku parzystego, więc to nie zadziała tak jak jest. W Julii 0.3 możesz używać int(2angle(z)/pi+5)tej samej liczby bajtów (moce ujemne powodują błąd z jakiegokolwiek powodu).
Dennis

Ponadto możesz zapisać bajt !z=z+(z!=0)im^...we wszystkich wersjach.
Dennis

2

C ++, 94 bajty

#define a(x) (x>0?x:-(x))
#define f(x,y) y>a(x-.5)?x--:-y>a(x+.5)?x++:x>a(y+.5)?y++:x|y?y--:x;

Nie golfowany:

#define a(x) (x>0?x:-(x))  //shorter than std::abs from <cmath>
#define f(x,y) 
    y>a(x-.5)?      // shift absolute value function by 0.5 to the right to get upper fourth
        x--:
        -y>a(x+.5)? //same for lower fourth
            x++:
            x>a(y+.5)? //same for right fourth
                y++:
                x|y? //only left fourth and 0 are left
                    y--:
                    x; //can't be empty, just does nothing

Stosowanie:

#include <iostream>
void test(int x, int y, int rx, int ry){
    std::cout << "(" << x << ", " << y << ")=>";
    f(x,y);
    std::cout << "(" << x << ", " << y << ") - " << ((x==rx&&y==ry)?"OK":"FAILURE") << std::endl;
}

//Using the test cases from the question
int main() {
    test(0, 0, 0, 0);
    test(1, 0, 1, 1);
    test(1, 1, 0, 1);
    test(0, 1, -1, 1);
    test(-1, 1, -1, 0);
    test(-1, 0, -1, -1);
    test(-1, -1, 0, -1);
    test(0, -1, 1, -1);
    test(1, -1, 1, 0);
    test(95, -12, 95, -11);
    test(127, 127, 126, 127);
    test(-2, 101, -3, 101);
    test(-65, 65, -65, 64);
    test(-127, 42, -127, 41);
    test(-9, -9, -8, -9);
    test(126, -127, 127, -127);
    test(105, -105, 105, -104);

    return 0;
}

Wypróbuj online


Jestem prawie pewien, że tak (x>0?x:-(x))może być (x>0?x:-x).
Yytsi

Niestety nie, ponieważ token x zostanie zastąpiony przez np. X + .5, który po prostu otrzyma -x + .5.
Anedar

W porządku. Miałem sposób myślenia, w którym negacja bez nawiasów zmieniła znak: D
Yytsi

Ściśle mówiąc, użyłeś preprocesora C (który jest wprawdzie częścią C ++, ale jest także współdzielony z innymi wariantami C i potomkami)
tucuxi 18.10.16

2

R, 131 110 bajtów

Funkcja, która przyjmuje dwie liczby całkowite x,yjako dane wejściowe i zapisuje dane wyjściowe na standardowe wyjście. Rozwiązanie jest zgodne ze schematem kontroli @Dennis, ale prawdopodobnie można je zastosować w golfa.

EDYCJA: Zaktualizowałem kod na podstawie sugestii @ JDL i zapisałem kilka bajtów.

function(x,y){X=sign(x+y);Y=sign(y-x);if(!X|!Y){x=x-X;y=y-Y}else if(X==Y&X&Y)x=x-X else if(X-Y&X)y=y-Y;c(x,y)}

Bez golfa

f=function(x,y){
    X=sign(x+y)                 # calculate sign 
    Y=sign(y-x)                 #  =||=
    if(!X|!Y){x=x-X;y=y-Y}      # if at least one is 0: subtract sign
    else if(X==Y&X&Y)x=x-X      # if signs are equal and non-zero: add sign to x
    else if(X-Y&X)y=y-Y         # if signs are not equal and non-zero: add sign to y
    c(x,y)                      # print to stdout
}

1
Myślę, że niektóre z warunków logicznych można skrócić: as.logical(-1)jest TRUE, X==0|Y==0może się stać !X|!Y, a stan if(X!=Y...)może się stać if(X-Y). Ponadto, jeśli X==Yi X!=0wtedy Y!=0jest zbędny. W rzeczywistości wszystkie !=0części są zbędne; if(X!=0)jest równoważne z if(X).
JDL

1
Ponadto, biorąc pod uwagę, że „format we / wy jest dość elastyczny”, prawdopodobnie jest to uczciwa gra, w której można uzyskać wynik domyślnie c(x,y)zamiast cat(x,y).
JDL

@JDL Oto kilka bardzo przydatnych wskazówek golfowych, o których nigdy nie myślałem, dziękuję bardzo! Zaktualizowałem odpowiedź.
Billywob 17.10.16

2

JavaScript (ES6), 57 bajtów (55–63 †)

Akceptuje tablicę [x, y], modyfikuje ją w miejscu i zwraca.

c=>([x,y]=c,i=x>y|x==y&x<0,c[i^x<-y|x==-y]-=-i|!!(x|y),c)

Jak to działa

c=>(

Jest to jednoparametrowa funkcja strzałki z returnzwięzłym korpusem.

[x,y]=c

Parametr jest natychmiast rozkładany na zmienne xi y.

,

Operator przecinka łączy wiele wyrażeń w jedno, wykorzystując wynik ostatniego.

i=x>y|x==y&x<0

isłuży do rozróżniania przypadków inkrementacji i dekrementacji. Kiedy xjest większa niż y, znajdujemy się w dolnej lub prawej ćwiartce i musimy iść do przodu w jednym wymiarze ( i=1poprzez wymuszenie wartości logicznej na liczbę). Podobnie, gdy znajdujemy się w ujemnej części dzielącej x = y przekątnej. We wszystkich innych przypadkach - łącznie z miejscem pochodzenia - nie jest wymagany przyrost ( i=0).

c[i^x<-y|x==-y]

Używamy nieco podobnego wyrażenia do kontrolowania, który indeks tablicy należy dostosować. Kiedy zwiększamy, a nie w lewym lub dolnym kwadrancie (lub gdy nie zwiększamy, w lewym lub dolnym), bitowy XOR wygeneruje 1i dostosujemy wartość y . Podobnie, gdy jesteśmy na dzielącej przekątnej x = -y (włączając początek). We wszystkich innych przypadkach indeks będzie wynosił 0( x ).

-=-i|!!(x|y)

Kiedy ijest 1, dodamy go do określonej wartości. Kiedy ijest 0, odejmujemy 1 od wartości wtedy i tylko wtedy , gdy nie jesteśmy u źródła. Ta ostatnia jest wykrywana przez x|yuzyskanie wartości niezerowej, przyciętej do {0, 1} przez boolean przymus, a negacja ipozwala nam użyć bitowego OR zamiast logicznego (ponieważ -1nie ma zerowych bitów, jest bezpieczny od modyfikacji).

c

Tablica jest ostatnia, więc zostanie zwrócona.

Testowanie

† Wariacje

Możemy zapisać dwa kolejne bajty, pomijając znaczącą wartość zwracaną i używając tylko mutacji wejściowej:

c=>([x,y]=c,i=x>y|x==y&x<0,c[i^x<-y|x==-y]-=-i|!!(x|y))

… Lub możemy pominąć mutację wejściową i uczynić wszystkie zmienne lokalnymi dla czystej funkcji, kosztem sześciu bajtów:

([x,y],i=x>y|x==y&x<0,c=[x,y])=>(c[i^x<-y|x==-y]-=-i|!!(x|y),c)

1

JavaScript (ES6), 80 76 bajtów

(x,y,s=Math.max(x,y,-x,-y))=>(s?x+s?y-s?x-s?x++:y++:x--:y+s?y--:x++:0,[x,y])

1

Haskell, 53 bajty

0%0=(0,0)
x%y|y>=0-x,y<x=(x,y+1)|(p,q)<-(-y)%x=(q,-p)

Pobiera dwie liczby, tworzy krotkę. Jeśli punkt znajduje się we wschodniej części -x<=y<x, zwiększ drugą współrzędną o 1. W przeciwnym razie przełóż kwadraty, obracając punkt wejściowy o 90 stopni, wywołując na nim funkcję, a następnie obracając do tyłu.


1

Rakieta 191 bajtów

(cond[(= 0 x y)(list x y)][(= x y)(if(> x 0)(list(sub1 x)y)(list(add1 x)y))][(> x y)(if(>= x(abs y))
(list x(add1 y))(list(add1 x)y))][(< x y)(if(> y(abs x))(list(sub1 x)y)(list x(sub1 y)))])

Niegolfowany (bezpośrednio tłumacząc kierunki rysunku na kod bez użycia pośredniej formuły):

(define(f x y)
  (cond
    [(= 0 x y) (list x y)]
    [(= x y)
     (if (> x 0)
         (list (sub1 x) y)   ; left
         (list (add1 x) y))] ; right
    [(> x y)
     (if (>= x (abs y))
         (list x (add1 y))   ; up
         (list (add1 x) y))] ; right
    [(< x y)
     (if (> y (abs x))
         (list (sub1 x) y)   ; left
         (list x (sub1 y)))] ; down
    ))

Testowanie:

(f 0  0)      
(f 1  0)     
(f 1  1)     
(f 0  1)     
(f -1  1)    
(f -1  0)    
(f -1  -1)   
(f 0  -1)    
(f 1  -1)    
(f 95  -12)  
(f 127  127) 
(f -2  101)  
(f -65  65)  
(f -127  42) 
(f -9  -9)    
(f 126  -127) 
(f 105  -105) 

Wydajność:

'(0 0)
'(1 1)
'(0 1)
'(-1 1)
'(-1 0)
'(-1 -1)
'(0 -1)
'(1 -1)
'(1 0)
'(95 -11)
'(126 127)
'(-3 101)
'(-65 64)
'(-127 41)
'(-8 -9)
'(127 -127)
'(105 -104)

1

Właściwie 16 bajtów

Pobiera to liczbę zespoloną jako dane wejściowe i zwraca inną liczbę zespoloną. Zapraszamy do gry w golfa! Wypróbuj online!

;`₧╦@/τuLïⁿ+0`╬X

Ungolfing

         Implicit input z.
;        Duplicate z.
`...`╬   If z is non-zero (any a+bi except 0+0j), run the following function.
           Stack: z, z
  ₧        Get phase(z).
  ╦@/      Divide phase(z) by pi.
  τuL      Push floor(2*phase(z)/pi + 1).
  ïⁿ       Push 1j ** floor(2*phase(z)/pi + 1).
  +        And add it to z. This is our rotated z.
  0        Push 0 to end the function.
X        Discard either the duplicate (0+0j) or the 0 from the end of function.
         Implicit return.

0

Scala, 184 bajty

val s=math.signum _
(x:Int,y:Int)=>{val m=x.abs max y.abs
if(x.abs==y.abs)if(s(x)==s(y))(x-s(x),y)else(x,y-s(y))else
if(x.abs==m)(x,y+Seq(0,x).indexOf(m))else(x-Seq(0,y).indexOf(m),y)}

Nie golfowany:

import math._

(x: Int, y: Int) => {
  val max = max(x.abs, y.abs)
  if (x.abs == y.abs)
    if (signum(x) == signum(y))
      (x - signum(x), y)
    else
      (x, y - signum(y))
  else
    if (x.abs == max)
      (x, y + Seq(0, x).indexOf(max))
    else
      (x - Seq(0, y).indexOf(max), y)
}

Wyjaśnienie:

val s=math.signum _             //define s as an alias to math.signum
(x:Int,y:Int)=>{                //define an anonymous function
  val m=x.abs max y.abs           //calculate the maximum of the absolute values,
                                  //which is 1 for the innermost circle and so on.
  if(x.abs==y.abs)                //if we have a cell at a corner of a circle
    if(s(x)==s(y))                  //if it's at the top-left or bottom-right, we need to
                                    //modify the x value
      (x-s(x),y)                      //if x is positive (bottom-right),
                                      //we need to return (x+1,y),
                                      //(x-1,y) If it's at the top-left.
                                      //This can be simplified to (x-s(x),y)
    else                            //for top-right and bottom-left, 
      (x,y-s(y))                      //modify y in the same way.
  else                            //we don't have a corner piece
    if(x.abs==m)                    //if we're at the left or right edge of the square
      (x,y+Seq(0,x).indexOf(m))       //if it's a piece from the right edge, add one
                                      //to y, else subtract 1
    else                            //it's a piece from the top or bottm edge
      (x-Seq(0,y).indexOf(m),y)       //subtract 1 from x if it's from the top edge,
                                      //else subtract -1
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.