Triangular Manhattan Distance The Manhattan distance on a regular grid is the number of orthogonal steps one needs to take to reach one cell from another. Orthogonal steps are those that go through the edges of the grid cells (as opposed to the corners, which would give us the Chebyshev distance).
We can define a similar distance on other grids, for example the triangular grid. We can address the individual cells in the grid with the following indexing scheme, where each cell contains an x,y pair:
    ____________________________________...
   /\      /\      /\      /\      /\
  /  \ 1,0/  \ 3,0/  \ 5,0/  \ 7,0/  \
 / 0,0\  / 2,0\  / 4,0\  / 6,0\  / 8,0\
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,1/  \ 2,1/  \ 4,1/  \ 6,1/  \ 8,1/
  \  / 1,1\  / 3,1\  / 5,1\  / 7,1\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  /  \ 1,2/  \ 3,2/  \ 5,2/  \ 7,2/  \
 / 0,2\  / 2,2\  / 4,2\  / 6,2\  / 8,2\  
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,3/  \ 2,3/  \ 4,3/  \ 6,3/  \ 8,3/
  \  / 1,3\  / 3,3\  / 5,3\  / 7,3\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  .  .    .  .    .  .    .  .    .  .
 .    .  .    .  .    .  .    .  .    .

Now the Manhattan distance on this grid is again the minimal number of steps across edges to get from one cell to another. So you can move from 3,1 to 2,1, 4,1 or 3,2, but not to any other triangle, since those would be crossing points rather than edges.
For instance, the distance from 2,1 to 5,2 is 4. The shortest path is generally not unique, but one way to make the distance in 4 steps is:
2,1 --&gt; 3,1 --&gt; 3,2 --&gt; 4,2 --&gt; 5,2

The Challenge
Given two coordinate pairs x1,y1 and x2,y2 from the above addressing scheme, return the Manhattan distance between them.
You may assume that all four inputs are non-negative integers, each less than 128. You may take them in any order and arbitrarily grouped (four separate arguments, a list of four integers, two pairs of integers, a 2x2 matrix, ...).
You may write a program or a function and use any of the 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 code-golf, so the shortest valid answer – measured in bytes – wins.
Test Cases
Each test case is given as x1,y1 x2,y2 =&gt; result.
1,2 1,2 =&gt; 0
0,1 1,1 =&gt; 1
1,0 1,1 =&gt; 3
2,1 5,2 =&gt; 4
0,0 0,127 =&gt; 253
0,0 127,0 =&gt; 127
0,0 127,127 =&gt; 254
0,127 127,0 =&gt; 254
0,127 127,127 =&gt; 127
127,0 127,127 =&gt; 255
75,7 69,2 =&gt; 11
47,58 36,79 =&gt; 42
77,9 111,23 =&gt; 48
123,100 111,60 =&gt; 80
120,23 55,41 =&gt; 83
28,20 91,68 =&gt; 111
85,107 69,46 =&gt; 123
16,25 100,100 =&gt; 159
62,85 22,5 =&gt; 160
92,26 59,113 =&gt; 174
62,22 35,125 =&gt; 206
JavaScript (ES6), 84 78 bytes

Saved 6 bytes thanks to Neil

(a,b,c,d,x=a&gt;c?a-c:c-a,y=b&gt;d?b-d:d-b,z=x&gt;y?x:y)=&gt;y+z+(x+z&amp;1?a+b+(b&gt;d)&amp;1||-1:0)


Test cases



let f =

(a,b,c,d,x=a&gt;c?a-c:c-a,y=b&gt;d?b-d:d-b,z=x&gt;y?x:y)=&gt;y+z+(x+z&amp;1?a+b+(b&gt;d)&amp;1||-1:0)

console.log(f(  1,  2,  1,  2)); // =&gt; 0
console.log(f(  0,  1,  1,  1)); // =&gt; 1
console.log(f(  1,  0,  1,  1)); // =&gt; 3
console.log(f(  2,  1,  5,  2)); // =&gt; 4
console.log(f(  0,  0,  0,127)); // =&gt; 253
console.log(f(  0,  0,127,  0)); // =&gt; 127
console.log(f(  0,  0,127,127)); // =&gt; 254
console.log(f(  0,127,127,  0)); // =&gt; 254
console.log(f(  0,127,127,127)); // =&gt; 127
console.log(f(127,  0,127,127)); // =&gt; 255
console.log(f( 75,  7, 69,  2)); // =&gt; 11
console.log(f( 47, 58, 36, 79)); // =&gt; 42
console.log(f( 77,  9,111, 23)); // =&gt; 48
console.log(f(123,100,111, 60)); // =&gt; 80
console.log(f(120, 23, 55, 41)); // =&gt; 83
console.log(f( 28, 20, 91, 68)); // =&gt; 111
console.log(f( 85,107, 69, 46)); // =&gt; 123
console.log(f( 16, 25,100,100)); // =&gt; 159
console.log(f( 62, 85, 22,  5)); // =&gt; 160
console.log(f( 92, 26, 59,113)); // =&gt; 174
console.log(f( 62, 22, 35,125)); // =&gt; 206




Initial recursive solution, 100 88 81

Saved 12 bytes thanks to ETHproductions
Saved 7 bytes thanks to Neil

f=(a,b,c,d,e=b==d|a+b+(b&gt;d)&amp;1)=&gt;a-c|b-d&amp;&amp;f(e?a+1-2*(a&gt;c):a,e?b:b+1-2*(b&gt;d),c,d)+1


How it works

Although it still essentially applies to the current version, the following explanation more specifically refers to the initial version:

f=(a,b,c,d)=&gt;b-d?a+b+(b&gt;d)&amp;1?f(a+1-2*(a&gt;c),b,c,d)+1:f(a,b+1-2*(b&gt;d),c,d)+1:Math.abs(a-c)


Going from (x0, y) to (x1, y) is trivial because we can go across lateral edges all the way from the source triangle to the target one. The Manhattan distance in this case is | x0 - x1 |.

The tricky part is the vertical steps. To go from row y0 to row y1, we have to take these two parameters into account:


The orientation of the current triangle
Whether y0 is less or greater than y1


The orientation of a triangle is given by the parity of x + y:


if it's even, the triangle is up-pointing
if it's odd, the triangle is down-pointing


We can go downwards from an up-pointing triangle (useful when y0 &lt; y1) and upwards from a down-pointing triangle (useful when y0 > y1).

By combining the orientation of the triangle with the comparison between y0 and y1, we get the formula x + y0 + (y0 > y1 ? 1 : 0) whose result is even if we can go in the desired direction and odd if not.

If we can't reach the next row directly, we first need to get a correct alignment by updating x:


if x is not yet equal to x1, we definitely want to move in the correct direction, so we increment it if x is less than x1 and we decrement it if x is greater than x1
if x already equals x1, we can either increment or decrement it


Test cases



f=(a,b,c,d)=&gt;b-d?a+b+(b&gt;d)&amp;1?f(a+1-2*(a&gt;c),b,c,d)+1:f(a,b+1-2*(b&gt;d),c,d)+1:Math.abs(a-c)

console.log(f(  1,  2,  1,  2)); // =&gt; 0
console.log(f(  0,  1,  1,  1)); // =&gt; 1
console.log(f(  1,  0,  1,  1)); // =&gt; 3
console.log(f(  2,  1,  5,  2)); // =&gt; 4
console.log(f(  0,  0,  0,127)); // =&gt; 253
console.log(f(  0,  0,127,  0)); // =&gt; 127
console.log(f(  0,  0,127,127)); // =&gt; 254
console.log(f(  0,127,127,  0)); // =&gt; 254
console.log(f(  0,127,127,127)); // =&gt; 127
console.log(f(127,  0,127,127)); // =&gt; 255
console.log(f( 75,  7, 69,  2)); // =&gt; 11
console.log(f( 47, 58, 36, 79)); // =&gt; 42
console.log(f( 77,  9,111, 23)); // =&gt; 48
console.log(f(123,100,111, 60)); // =&gt; 80
console.log(f(120, 23, 55, 41)); // =&gt; 83
console.log(f( 28, 20, 91, 68)); // =&gt; 111
console.log(f( 85,107, 69, 46)); // =&gt; 123
console.log(f( 16, 25,100,100)); // =&gt; 159
console.log(f( 62, 85, 22,  5)); // =&gt; 160
console.log(f( 92, 26, 59,113)); // =&gt; 174
console.log(f( 62, 22, 35,125)); // =&gt; 206