Chebyshev Rotation

36

Stellen Sie sich ein reguläres Gitter vor, in dem jede Zelle Ganzzahlkoordinaten hat. Wir können die Zellen in (quadratische) "Ringe" gruppieren, wobei die Zellen in jedem Ring den gleichen Chebyshev-Abstand (oder Schachbrettabstand) vom Ursprung haben. Ihre Aufgabe ist es, eine solche Zellenkoordinate zu nehmen und diese Zelle innerhalb ihres Rings um eine Position gegen den Uhrzeigersinn zu drehen. Dies implementiert die folgende Zuordnung:

Bildbeschreibung hier eingeben

Wenn der Eingang also zum Beispiel ist (3, -2), sollten Sie ihn ausgeben (3, -1). Beachten Sie, dass dies (0, 0)die einzige Eingabe ist, die sich selbst zuordnen sollte.

Regeln

Das E / A-Format ist ziemlich flexibel. Sie können zwei einzelne Zahlen, ein Paar / eine Liste / ein Array / ein Tupel von Zahlen, eine einzelne komplexe Zahl, eine Zeichenfolge mit zwei Zahlen usw. verwenden.

Sie können das annehmen -128 < x,y < 128.

Sie können ein Programm oder eine Funktion schreiben und eine unserer Standardmethoden zum Empfangen und Bereitstellen von Eingaben verwenden.

Sie können jede Programmiersprache verwenden , beachten Sie jedoch, dass diese Lücken standardmäßig verboten sind.

Das ist , also gewinnt die kürzeste gültige Antwort - gemessen in Bytes .

Testfälle

(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)
Martin Ender
quelle
Können wir das Eingabe- und Ausgabeformat mischen, z. B. ein Tupel nehmen und eine komplexe Zahl ausgeben?
Dennis
@ Tennis ja das ist in Ordnung.
Martin Ender

Antworten:

16

JavaScript (ES6), 60 bis 59 Byte

Nimmt Eingaben mit aktueller Syntax entgegen (x)(y)und gibt ein Array zurück [new_x, new_y].

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

Wie es funktioniert

Unsere Hauptaufgabe ist es, zu bestimmen, in welchem ​​Quadranten wir uns befinden, damit wir wissen, in welche Richtung wir uns bewegen müssen.

Wir können diese Formel als erste Annäherung verwenden:

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

Folgendes bekommen wir:

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

Fast dort. Die unteren linken und rechten Ecken der Ringe sind jedoch ungültig. Wir müssen die untere Hälfte der Matrix um eine Position nach links verschieben, also definieren wir zals:

z = y < 0 ? x + 1 : x

Und wir ersetzen xmit zin unserer Formel:

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

Was dazu führt:

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 

Die gesamte Matrix ist nun korrekt, mit Ausnahme des Sonderfalls [0, 0](überhaupt keine Bewegung), der separat behandelt werden muss.

Testfälle

Arnauld
quelle
13

Jelly , 20 14 12 Bytes

S;IṠN0n/¦Ạ¡+

Eingabe und Ausgabe erfolgen in Form von Arrays. Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Hintergrund

Um herauszufinden, in welche Richtung wir uns bewegen müssen, können wir die relative Position des Startpunkts zu den Quadrantenhalbierenden x + y = 0 (blau) und x - y = 0 (rot) beobachten.

Diagramm

  • Der Ursprung ist festgelegt. Wir rücken vor, indem wir [0, 0] zum Startpunkt addieren .

  • Punkte im obersten Dreieck - einschließlich der Winkelhalbierenden des ersten Quadranten - haben eine positive Summe und ein nicht negatives Delta ( y - x ). Wir rücken vor, indem wir [-1, 0] zum Startpunkt addieren .

  • Punkte im äußersten linken Dreieck - einschließlich der Winkelhalbierenden des zweiten Quadranten - haben eine nicht positive Summe und ein positives Delta. Wir rücken vor, indem wir [0, -1] zum Startpunkt addieren .

  • Punkte im untersten Dreieck - einschließlich der Winkelhalbierenden des dritten Quadranten - haben eine negative Summe und ein nicht positives Delta. Wir rücken vor, indem wir [1, 0] zum Startpunkt addieren .

  • Punkte im äußersten rechten Dreieck - einschließlich der Winkelhalbierenden des vierten Quadranten - haben eine nicht negative Summe und ein negatives Delta. Wir rücken vor, indem wir [0, 1] zum Startpunkt addieren .

Um die richtige Richtung herauszufinden, berechnen wir [-sign (x + y), -sign (y - x)] , was nur neun mögliche Ergebnisse hat.

Die folgende Tabelle zeigt, welche Ergebnisse welchen Richtungen zugeordnet werden müssen.

    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

Dies lässt drei Fälle.

  • Wenn mindestens eines der Vorzeichen 0 ist , ist [Δx, Δy] = [-Zeichen (x + y), -Zeichen (yx)] .

  • Wenn die Vorzeichen gleich und ungleich Null sind, ist [Δx, Δy] = [-Zeichen (x + y), 0] .

  • Wenn sich die Vorzeichen unterscheiden und nicht Null sind, ist [Δx, Δy] = [0, -Zeichen (yx)] .

Wie es funktioniert

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].
Dennis
quelle
5

Pyth , 19 Bytes

&Q+^.jZ1.RhycPQ.n0Z

Probieren Sie es online!

Übersetzung meiner Julia-Antwort :

&Q                    If input is 0, then 0, else:
             PQ         Get phase of input
            c  .n0      Divide by π
           y            Double
          h             Add one
        .R        Z     Round to integer
   ^.jZ1                Raise i to this power
  +                     Add to input
Lynn
quelle
Schöne Parabelantwort!
Tomsmeding
5

Python, 55 Bytes

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

Erkennt die vier diagonalen Quadranten und verschiebt die entsprechende Koordinate.

xnor
quelle
4

Haskell, 77 71 69 Bytes

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)

Dies überprüft nur jeden dieser geneigten Quadranten und modifiziert die Eingabe entsprechend. Beachten Sie, dass die Leerzeichen notwendig sind, da sie sonst zB >-als Operator verstanden werden (was nicht definiert ist).

Vielen Dank an @nimi, dass Sie ein paar weitere Bytes entfernt haben!

Fehler
quelle
,statt&& innerhalb der ersten Wache speichert ein Byte. Und dann können Sie den zweiten Vergleich auf -x<yfür ein anderes Byte umschalten .
nimi
Danke, mir war das nicht bewusst ,!
Fehler
4

Rubin, 68

Die Lambda-Funktion nimmt eine komplexe Zahl als Argument und gibt eine komplexe Zahl zurück.

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

Wir drehen den Punkt viermal um 90 Grad, indem wir mit multiplizieren i. Es durchläuft daher alle 4 Quadranten und wird unverändert zurückgegeben - mit Ausnahme der Tatsache, dass wir es ändern, wenn es sich in einem bestimmten von ihnen befindet. Die Tatsache, dass es immer im selben Quadranten geändert wird, vereinfacht die Änderung.

Es ist am einfachsten zu folgen, wenn wir es ändern, zwenn es sich im rechten Quadranten befindet. in diesem Fall müssen wir die y-Koordinate um 1 erhöhen (dh izu z. hinzufügen )

Wir überprüfen dies x.abs>=y.absdurch Vergleichen der Quadrate von xund y. Dies sagt uns, dass der Punkt im rechten oder linken Quadranten liegt, nicht oben oder unten. Um zu überprüfen , es in der Tat im rechten Quadranten prüfen wir weiterhin , dass x>y( die streng größer , weil wir den Fall ausschließen möchten , x=ydie an der „Spitze“ Quadranten gehört.) Wo dies der Fall ist fügen wir izu z.

Aus Golfgründen ist das Hinzufügen inicht wünschenswert. Stattdessen ändern wir die Zahl, wenn sie sich im unteren Quadranten befindet . In diesem Fall müssen wir 1 zur xKoordinate hinzufügen (1 zu hinzufügen z). In diesem Fall testen wir, y*y>=x*xob sie sich im oberen oder unteren Quadranten befindet. Um weiterhin sicherzustellen, dass es sich im unteren Quadranten befindet, müssen wir dies überprüfen y<-x(wobei der Fall der unteren rechten Ecke strikt ausgeschlossen ist y=-x).

Ein Vorteil dieser Prüfung ist, dass es keinen Sonderfall für die Koordinate 0,0 gibt. Leider wurde festgestellt, dass das Verschieben des Punktes zu einem anderen Quadranten führen kann und dies bedeutet, dass eine zweite Bewegung unterdrückt werden muss, wenn dieser Quadrant erneut überprüft wird, was wahrscheinlich den Vorteil zunichte macht.

Beispiel 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.

Beispiel 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.

Im Testprogramm

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)

Diagramm

Das folgende Bild zeigt (blau) den Bereich x*x>=y*y, in dem (gelb) der Bereich y<-xund (grün) der Schnittpunkt von diesen ist, der Bereich, in dem die korrekte Transformation die Addition von 1 zu ist z.

Bildbeschreibung hier eingeben

Level River St
quelle
1
Entschuldigung, ich folge nicht der Erklärung. Würde es Ihnen etwas ausmachen, ein Beispiel oder ein Diagramm hinzuzufügen?
Martin Ender
@ Martin Erklärung hinzugefügt. Dies war ein interessanter Ansatz, der sich jedoch als nicht so elegant herausstellte, wie ich es mir erhofft hatte, da die doppelte Bewegung von Punkten, die sich beim ersten Bewegen im Quadranten ändern, unterdrückt werden musste.
Level River St
4

Python, 52 Bytes

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

Komplexe Ein- und Ausgabe. Um zu testen, ob der Punkt im unteren diagonalen Quadranten liegt, drehen Sie ihn zuerst gegen den Uhrzeigersinn, um diesen Quadranten in den Standardquadranten (x> 0, y> 0) zu verschieben, und prüfen Sie, ob das Ergebnis kein Minuszeichen in der Zeichenfolgendarstellung enthält. Das Subtrahieren von 1 kümmert sich zuerst um die Randbedingung.

Wenn es sich nicht in diesem Quadranten befindet, drehen Sie das gesamte Problem um 90 Grad. Die Eingabe Null wird speziell behandelt, um sich selbst auszugeben.

Andere Versuche mit komplexen Zahlen:

## 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
xnor
quelle
3

Mathematica, 34 Bytes

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

Dies definiert einen unären Operator, ±der eine komplexe Zahl annimmt und zurückgibt, deren Komponenten xund darstellen y.

Nachdem Lynn die komplexe Zahlenlösung enthüllt hat und Dennis meine Punktzahl übertroffen hat, fühle ich mich nicht so schlecht, wenn ich meine referenzierte Golf-Implementierung poste. :) (Es stellt sich heraus, dass es praktisch identisch mit Lynns Antwort ist.)

Martin Ender
quelle
Würde das helfen? ± 0 = 0 ⁢ ± z_: = z + I ^ ⌊ 2 ⁢ Arg @ z / Pi + 3/2 ⌋ (möglicherweise mit einem anderen Zeichen für die Bodenklammern)
DavidC
@DavidC leider nicht, da ich dann die UTF-8-Codierung verwenden müsste und dann die ± jeweils 2 Bytes kosten würden.
Martin Ender
Wäre das nicht 4 statt 7 Bytes, was eine Wirtschaftlichkeit von 3 Bytes ergibt?
DavidC
@DavidC Nein, die Bodenklammern haben jeweils 3 Byte.
Martin Ender
Das war mir nicht bewusst. Trotzdem sollten Sie immer noch 1 Byte sparen.
DavidC
3

MATL , 19 17 Bytes

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

Dies verwendet komplexe Zahlen als Eingabe und Ausgabe.

Probieren Sie es online! Oder überprüfen Sie alle Testfälle .

Erläuterung

Nehmen wir -127+42jals Beispiel die Eingabe .

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
Luis Mendo
quelle
3

Ruby, 51 Bytes

Ursprungsform

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

Alternatives Formular gemäß Xnors Kommentar

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

Verwendet die gleiche Art von Ungleichungen wie meine andere Antwort, jedoch auf andere Weise.

Im Testprogramm

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)
Level River St
quelle
Lohnt sich der dAuftrag? Es sieht so aus, als ob Sie es einfach vergleichen können x*x>y*y.
xnor
@Xnor Ruby benötigt leider ein Leerzeichen dazwischen y*yund ist ?daher genau gleich lang. Ich habe es aufgenommen, da ich denke, dass Ihr Weg in gewisser Weise ordentlicher ist. Ich denke, Ruby versucht, es als y?einen legalen Funktionsnamen zu übergeben.
Level River St
3

Julia, 38 34 Bytes

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

Dennis sparte vier Bytes. Vielen Dank!

Probieren Sie es online!

Lynn
quelle
Sieht so aus, als hätte ich das Verhalten von int in verschiedenen Versionen von Julia vertauscht (was zu meiner Verteidigung furchtbar inkonsistent ist). Julia 0.4 (die Version auf TIO) rundet die Hälften in Richtung Even, so dass dies nicht so funktioniert, wie es ist. In Julia 0.3 können Sie int(2angle(z)/pi+5)für dieselbe Byteanzahl verwenden (negative Potenzen verursachen einen Fehler, aus welchem ​​Grund auch immer).
Dennis
Sie können auch ein Byte mit !z=z+(z!=0)im^...in allen Versionen speichern .
Dennis
2

C ++, 94 Bytes

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

Ungolfed:

#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

Verwendung:

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

Probieren Sie es online aus

Anedar
quelle
Ich bin mir ziemlich sicher, dass das sein (x>0?x:-(x))kann (x>0?x:-x).
Yytsi
Leider nicht, da das Token x durch zB x + .5 ersetzt wird, was nur -x + .5 ergeben würde.
Anedar
In Ordung. Ich hatte eine Denkweise, in der die Verneinung ohne Klammern das Zeichen umdrehte: D
Yytsi
Genau genommen haben Sie den C- Präprozessor verwendet (der zwar Teil von C ++ ist, aber auch mit anderen C-Varianten und Nachkommen geteilt wird)
tucuxi
2

R 131 110 Bytes

Eine Funktion, die die beiden Ganzzahlen x,yals Eingaben verwendet und die Ausgabe in stdout schreibt. Die Lösung folgt dem Kontrollflussschema von @Dennis, könnte aber wahrscheinlich Golf spielen.

BEARBEITEN: Code basierend auf @ JDLs Vorschlägen aktualisiert und eine Menge Bytes gespeichert.

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

Ungolfed

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
}
Billywob
quelle
1
Ich denke, einige der logischen Bedingungen können verkürzt werden: as.logical(-1)ist TRUE, so X==0|Y==0kann es werden !X|!Y, und die Bedingung if(X!=Y...)kann es werden if(X-Y). Auch wenn X==Yund X!=0dann Y!=0ist überflüssig. Eigentlich sind alle !=0Teile überflüssig; if(X!=0)ist äquivalent zu if(X).
JDL
1
Angesichts der Tatsache, dass "das I / O-Format ziemlich flexibel ist", ist es wahrscheinlich ein faires Spiel, mit dem implizit ausgegeben werden kann, c(x,y)anstatt cat(x,y).
JDL
@JDL Das sind einige sehr nützliche Golftipps, über die ich nie nachgedacht habe, vielen Dank! Die Antwort wurde aktualisiert.
Billywob
2

JavaScript (ES6), 57 Byte (55–63 †)

Akzeptiert ein [x, y] -Array, ändert es direkt und gibt es zurück.

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

Wie es funktioniert

c=>(

Dies ist eine Einzelparameter-Pfeilfunktion mit einem return-freien, präzisen Text.

[x,y]=c

Der Parameter wird sofort in xund yVariablen zerlegt.

,

Der Kommaoperator kombiniert mehrere Ausdrücke zu einem, wobei das Ergebnis des letzten verwendet wird.

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

iwird zur Unterscheidung von Inkrement- und Dekrementfällen verwendet. Wenn xgrößer als ist y, befinden wir uns entweder im unteren oder im rechten Quadranten und müssen in einer Dimension vorrücken ( i=1durch Booleschen-Zahlen-Zwang). Ebenso, wenn wir uns im negativen Teil der dividierenden x = y- Diagonale befinden. In allen anderen Fällen - einschließlich des Ursprungs - ist kein Inkrement erforderlich ( i=0).

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

Wir verwenden einen ähnlichen Ausdruck, um zu steuern, welcher Array-Index angepasst werden soll. Wenn wir inkrementieren und nicht im linken oder unteren Quadranten (oder wenn wir nicht inkrementieren und im linken oder unteren Quadranten ), wird das bitweise XOR erzeugt 1und der y- Wert angepasst. Ebenso, wenn wir uns auf der dividierenden x = -y- Diagonale befinden (einschließlich des Ursprungs). In allen anderen Fällen ist der Index 0( x ).

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

Wenn dies der Fall iist 1, werden wir es zum angegebenen Wert hinzufügen. Wann iist 0, werden wir genau dann 1 vom Wert abziehen, wenn wir nicht am Ursprung sind. Letzteres wird erkannt, indem ein x|yWert ungleich Null ausgegeben wird, der durch booleschen Zwang auf {0, 1} begrenzt wird, und die Negation von iermöglicht die Verwendung von bitweisem ODER anstelle von logischem (da -1keine Null-Bits vorhanden sind, ist es vor Änderungen sicher).

c

Das Array ist das letzte, daher wird es zurückgegeben.

Testen

† Variationen

Wir können zwei weitere Bytes einsparen, indem wir einen aussagekräftigen Rückgabewert überspringen und nur die Eingabemutation verwenden:

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

... oder wir können die Eingabemutation überspringen und alle Variablen für eine reine Funktion auf Kosten von sechs Bytes lokalisieren:

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

JavaScript (ES6), 80 bis 76 Byte

(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])
Neil
quelle
1

Haskell, 53 Bytes

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

Nimmt zwei Zahlen und gibt ein Tupel aus. Wenn sich der Punkt im östlichen Bereich befindet -x<=y<x, erhöhen Sie die zweite Koordinate um 1. Andernfalls können Sie die Quadranten durchlaufen, indem Sie den Eingabepunkt um 90 Grad drehen, die entsprechende Funktion aufrufen und dann zurückdrehen.

xnor
quelle
1

Schläger 191 Bytes

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

Ungolfed (direktes Übersetzen der Figurenanweisungen in den Code ohne Verwendung einer Zwischenformel):

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

Testen:

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

Ausgabe:

'(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)
rnso
quelle
1

Eigentlich 16 Bytes

Dies nimmt eine komplexe Zahl als Eingabe und gibt eine andere komplexe Zahl aus. Golfvorschläge willkommen! Probieren Sie es 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.
Sherlock9
quelle
0

Scala, 184 Bytes

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

Ungolfed:

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

Erläuterung:

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
}
corvus_192
quelle