Triangular Manhattan Distance
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