Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Consider a regular grid, where each cell has integer coordinates. We can group the cells into (square-shaped) "rings" where the cells in each ring have the same Chebyshev distance (or chessboard distance) from the origin. Your task is to take such a cell coordinate and rotate that cell by one position counter-clockwise within its ring. This implements the following mapping:

enter image description here

So for example if the input is (3, -2) you should output (3, -1). Note that (0, 0) is the only input that should map to itself.

Rules

The I/O format is fairly flexible. You can use two individual numbers, a pair/list/array/tuple of numbers, a single complex number, a string containing two numbers, etc.

You may assume that -128 < x,y < 128.

You may write a program or a function and use any of the our standard methods of receiving input and providing output.

You may use any programming language, but note that these loopholes are forbidden by default.

This is , so the shortest valid answer – measured in bytes – wins.

Test Cases

(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)
share|improve this question
    
Can we mix input and output format, e.g., take a tuple and output a complex number? – Dennis yesterday
    
@Dennis yes that's fine. – Martin Ender yesterday

17 Answers 17

JavaScript (ES6), 60 59 bytes

Takes input with currying syntax (x)(y) and returns an array [new_x, new_y].

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

How it works

Our main task is to determine in which quadrant we are, so that we know in which direction to move.

We can use this formula as a first approximation:

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

Here is what we get:

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

Almost there. But the bottom left and bottom right corners of the rings are invalid. We need to shift the lower half of the matrix by one position to the left, so we define z as:

z = y < 0 ? x + 1 : x

And we replace x with z in our formula:

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

Which leads to:

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 

The whole matrix is now correct, except for the special case [0, 0] (no move at all) which must be addressed separately.

Test cases

let f =

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

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

share|improve this answer

Jelly, 20 14 12 bytes

S;IṠN0n/¦Ạ¡+

Input and output are in form of arrays. Try it online! or verify all test cases.

Background

To figure out in which direction we have to move, we can observe the relative position of the start point to the quadrant bisectors x + y = 0 (blue) and x - y = 0 (red).

diagram

  • The origin is fixed. We advance by adding [0, 0] to the start point.

  • Points in the topmost triangle – including the bisector of the first quadrant – have positive sum and non-negative delta (y - x). We advance by adding [-1, 0] to the start point.

  • Points in the leftmost triangle – including the bisector of the second quadrant – have non-positive sum and positive delta. We advance by adding [0, -1] to the start point.

  • Points in the bottommost triangle – including the bisector of the third quadrant – have negative sum and non-positive delta. We advance by adding [1, 0] to the start point.

  • Points in the rightmost triangle – including the bisector of the fourth quadrant – have non-negative sum and negative delta. We advance by adding [0, 1] to the start point.

To figure out the correct direction, we compute [-sign(x + y), -sign(y - x)], which has only nine possible outcomes.

The following table illustrates which outcomes have to get mapped to which directions.

    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

This leaves three cases.

  • If at least one of the signs is 0, [Δx, Δy] = [-sign(x+y), -sign(y-x)].

  • If the signs are equal and non-zero, [Δx, Δy] = [-sign(x+y), 0].

  • If the signs are different and non-zero, [Δx, Δy] = [0, -sign(y-x)].

How it works

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].
share|improve this answer

Pyth, 19 bytes

&Q+^.jZ1.RhycPQ.n0Z

Try it online!

Translation of my Julia answer:

&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
share|improve this answer
    
Nice parabola answer! – tomsmeding yesterday

Python, 55 bytes

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

Detects the four diagonal quadrants, and shifts the appropriate coordinate.

share|improve this answer

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)

This is just checking each of those tilted quadrants, and modifying the input accordingly. Note that the spaces are necessary, otherwise e.g. >- would be understood as an operator (which is not defined).

Thank you @nimi for removing a few more bytes!

share|improve this answer
    
, instead of && within the first guard saves a byte. And then you can switch the second comparison to -x<yfor another byte. – nimi 2 days ago
    
Thank you, I wasn't aware of the ,! – flawr yesterday

Ruby, 68

Lambda function takes complex number as argument, returns complex number.

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

We rotate the point through 90 degrees 4 times by multiplying by i. It therefore passes through all 4 quadrants, and would be returned unchanged - except for the fact we modify it when it is in a specific one of them. The fact it is always modified in the same quadrant simplifies the modification.

It is easiest to follow if we alter it zwhen it is in the righthand quadrant. in this case we need to increase the y coordinate by 1 (i.e add i to z.)

We check x.abs>=y.abs by comparing the squares of x and y. This tells us the point is in the righthand or lefthand quadrant, not top or bottom. To check it is in fact in the righthand quadrant we further check that x>y (strictly greater because we want to exclude the case x=y which belongs to the "top" quadrant.) Where this is true we add i to z.

For golfing reasons, adding i is not desirable. Instead we modifiy the number when it is in the bottom quadrant, in which case we have to add 1 to the x coordinate (add 1 to z.) In this case we test that y*y>=x*x to check it is in the top or bottom quadrant. To further ensure it is in the bottom quadrant we need to check y<-x (strictly excluding the case of the bottom right corner where y=-x.)

An advantage of this check is there is no special case for the coordinate 0,0. Unfortunately it was found that moving the point can shift it to a different quadrant and this means that a second movement must be suppressed should that quadrant be checked again, which probably negates the advantage.

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

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

In test program

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

The following image shows (blue) the area where x*x>=y*y, (yellow) the area where y<-x and (green) the intersection of these, which is the region where the correct transformation is the addition of 1 to z.

enter image description here

share|improve this answer
1  
Sorry, I'm not following the explanation. Would you mind adding either an example or a diagram? – Martin Ender yesterday
    
@Martin explanation added. This was an interesting approach but due to the need to suppress double movement of points that change quadrant the first time they move, it didn´t turn out as elegant as I had hoped. – Level River St yesterday

Python, 52 bytes

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

Complex input and output. To test the point for being in the lower diagonal quadrant, first rotate it 135 counterclockwise to move that quadrant to the (x>0, y>0) standard quadrant, and test if the result has no minus symbol in the string representation. Subtracting 1 first takes care of the boundary condition.

If it's not in that quadrant, rotate the whole problem 90 degrees. The input is zero is specially handled to output itself.

Other attempts with complex numbers:

## 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
share|improve this answer

Mathematica, 34 bytes

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

This defines a unary operator ± which takes and returns a complex number whose components represent x and y.

Now that Lynn has revealed the complex number solution and Dennis has beaten my score, I don't feel so bad for posting my golfed referenced implementation. :) (It turns out to be virtually identical to Lynn's answer.)

share|improve this answer
    
Would this help? ± 0 = 0 ⁢ ± z_ := z + I ^ ⌊ 2 ⁢ Arg @ z / Pi + 3 / 2 ⌋ (perhaps with a different char for the floor brackets) – DavidC yesterday
    
@DavidC unfortunately not because then I'd have to use UTF-8 encoding and then the ± would cost 2 bytes each. – Martin Ender yesterday
    
Wouldn't that be 4 bytes instead of 7, thus giving an economy of 3 bytes? – DavidC yesterday
    
@DavidC no, the floor brackets would be 3 bytes each. – Martin Ender yesterday
    
I wasn't aware of that. But, even so, you should still be saving 1 byte. – DavidC yesterday

MATL, 19 17 bytes

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

This uses complex numbers as input and output.

Try it online! Or verify all test cases.

Explanation

Let's take input -127+42j as an example.

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
share|improve this answer

Ruby, 51 bytes

Original form

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

Alternate form per Xnor's comment

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

Uses the same type of inequalities as my other answer, but in a different way.

In test program

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)
share|improve this answer
    
Is the d assignment worth it? It looks like you can just compare x*x>y*y. – xnor yesterday
    
@Xnor unfortunately Ruby requires a space between y*y and ? so it's exactly the same length. I've included it as I think your way is in some ways neater. I think Ruby is trying to pass it as y? which would be a legal function name. – Level River St yesterday

Julia, 38 34 bytes

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

Dennis saved four bytes. Thanks!

Try it online!

share|improve this answer
    
Looks like I mixed up int's behavior across different versions of Julia (which, in my defense, is terribly inconsistent). Julia 0.4 (the version on TIO) rounds halves towards even, so this won't work as is. In Julia 0.3, you can use int(2angle(z)/pi+5) for the same byte count (negative powers cause an error for whatever reason). – Dennis 13 hours ago
    
Also, you can save a byte with !z=z+(z!=0)im^... in all versions. – Dennis 13 hours ago

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

Usage:

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

Try it online

share|improve this answer
    
I'm pretty sure that (x>0?x:-(x)) can be (x>0?x:-x). – TuukkaX yesterday
    
Unfortunately not, since the token x will be replaced by e.g. x+.5 which would just get -x+.5. – Anedar yesterday
    
Alright. I had a mindset where negation without parentheses flipped the sign :D – TuukkaX yesterday
    
Strictly speaking, you have used the C preprocessor (which is admittedly a part of C++, but is also shared with other C variants and descendants) – tucuxi 2 hours ago

JavaScript (ES6), 80 76 bytes

(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])
share|improve this answer

Haskell, 53 bytes

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

Takes two numbers, outputs a tuple. If the point is in the east section -x<=y<x, increase the second coordinate by 1. Otherwise, cycle the quadrants by rotating the input point 90 degrees, calling the function on it, then rotating back.

share|improve this answer

Racket 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 (directly translating figure directions to code without using any intermediate formula):

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

Testing:

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

Output:

'(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)
share|improve this answer

R, 131 110 bytes

A function that takes the two integers, x,y as inputs and writes the output to stdout. The solution follows @Dennis' control flow scheme but could probably be golfed.

EDIT: Updated code based on @JDL's suggestions and saved a bunch of bytes.

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
}
share|improve this answer
1  
I think some of the logical conditions can be shortened: as.logical(-1) is TRUE, so X==0|Y==0 can become !X|!Y, and the condition if(X!=Y...) can become if(X-Y). Also, if X==Y and X!=0 then Y!=0 is redundant. Actually, all the !=0 parts are redundant; if(X!=0) is equivalent to if(X). – JDL yesterday
1  
Also, given that "the I/O format is fairly flexible", it's probably fair game to output implicitly with c(x,y) instead of cat(x,y). – JDL yesterday
    
@JDL Those are some very useful golfing tips I never thought about, thanks alot! Updated the answer. – Billywob yesterday

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

Explanation:

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
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.