# Dig to Australia - antipodes

## Background

Countless generations of children have wondered where they would end up if they dug a hole directly downwards. It turns out that this would, unsurprisingly, be rather dangerous, but anyway...

Antipodes are points that are directly opposite each other on the Earth's surface. This means that if a line was drawn between the two points, it would pass through the centre of the Earth.

## Challenge

Write a program or function that, given a point, finds its antipode.

In this challenge, points are represented using the longitude-latitude system and degrees, arc minutes and arc seconds. To find the antipode, swap the directions of each ordinate (N <-> S and W <-> E) and subtract the longitude ordinate from 180 degrees.

Example:
Take the point N 50 26 23 W 4 18 29. Swap the directions to give S 50 26 23 E 4 18 29. Subtract the longitude ordinate from 180 0 0 to give 175 41 31, leaving the antipode coordinates as S 50 26 23 E 175 41 31.

## Rules

### Input

A set of latitude-longitude coordinates, in any reasonable format, where each ordinate contains a direction, a number of degrees, a number of arc minutes, and a number of arc seconds.

### Output

The latitude-longitude coordinates of the antipode, in any reasonable format, where each ordinate contains a direction, a number of degrees, a number of arc minutes, and a number of arc seconds.

Take reasonable to mean that each part of the coordinate can be distinguished unambiguously.

### Specs

• The direction for the latitude ordinate is N or S, and that for the longitude ordinate is W or E.
• All coordinate values are integers. The degree value will be between 0 and 90 for latitude, and between 0 and 180 for longitude. The arc minute and arc second values for both ordinates will be between 0 and 59.
• If all the values for an ordinate are 0, either direction is acceptable.
• There is no need to zero-pad any values.
• No latitude ordinate will ever be larger than 90 degrees, and no longitude ordinate will ever be larger than 180 degrees.
• Standard loopholes apply.

## Test cases

N 50 26 23 W 4 18 29 -> S 50 26 23 E 175 41 31

S 43 9 9 E 0 0 5     -> N 43 9 9 W 179 59 55

N 0 0 0 E 0 0 0      -> S/N 0 0 0 W/E 180 0 0 (either direction fine in each case)

S 1 2 3 W 4 5 6      -> N 1 2 3 E 175 54 54

S 9 21 43 W 150 7 59 -> N 9 21 43 E 29 52 1

S 27 40 2 W 23 0 0   -> N 27 40 2 E 157 0 0

N 0 58 37 W 37 0 0   -> S 0 58 37 E 143 0 0


This is , so the shortest answer in bytes wins!

• Is this a reasonable format? Four inputs: array of 3 numbers, char, array of three numbers; separated by newlines – Luis Mendo Jul 5 '16 at 22:02
• @LuisMendo Unless I am misunderstanding you, I can only see three inputs; I assume you would want an extra char? I would say that that is a reasonable format. By reasonable, I essentially mean that each part of the coordinate can be distinguished unambiguously. – TheBikingViking Jul 5 '16 at 22:25
• Yes, I forgot the first char. Thanks! – Luis Mendo Jul 5 '16 at 22:27
• "Rather dangerous"? Mate, the real danger is once you get here. – Andrew Grimm Jul 6 '16 at 4:05
• @busukxuan Apologies for not responding sooner. I would say that both of those formats are not reasonable, since the spec requires N, S, E, or W as a direction, while the redundant 0 introduces ambiguity as to which value represents which component of the ordinate. – TheBikingViking Jul 6 '16 at 20:12

## 05AB1E, 37 34 bytes

60©3L<Rm*O3°648*s-®‰s®‰s‚˜)'€ÃÂ‡


Explained

                                      # split input to 4 lines with longitude on top
60©3L<Rm*O                            # convert longitude to seconds
3°648*                     # longitude 180 0 0 in seconds
s-                   # subtract our longitude from this
®‰                # get seconds part
s®‰             # get minute and degrees part
s‚˜)         # join to list
'€ÃÂ‡    # translate directions


Try it online

Edit: Saved 3 bytes thanks to Adnan.

• You can compress "NEWS" to ‘€Ã‘ or even '€Ã if lowercase is allowed. – Adnan Jul 7 '16 at 11:09
• @Adnan: Nice! Didn't think of compressing since the string was so small already. – Emigna Jul 7 '16 at 11:13

## JavaScript (ES6), 88 bytes

(a,b,c,d,e,f,g,h)=>[a<'S'?'S':'N',b,c,d,e<'W'?'W':'E',!(g|h)+179-f,g|h&&!h+59-g,h&&60-h]


Takes 8 parameters and returns an array as the result. Expects a to be one of N or S and similarly e to be one of W or E. Calculations:

• f needs to be subtracted from 179 if either g or h is nonzero but 180 if both g and h are zero (because there is no borrow), thus !(g|h) is added to the 179.
• g needs to be zero if both g and h are zero, thus g|h&&, otherwise it needs to be subtracted from 59 if h is nonzero but 60 if h is zero (because there is no borrow), thus !h is added to the 59.
• h needs to be zero if it was already zero, otherwise it is simply subtracted from 60.

Another way to look at this is to notice that subtracting in binary is achieved by adding the 1s complement plus an additional 1. Translated to this problem, we take 179-f, 59-g and 59-h and add 1. 59-h + 1 is 60-h, but if this is 60 then it carries, so the desired result is zero if h was originally zero. We add 1 to 59-g if there's a carry from h, i.e. if h was originally zero. Again we have to allow for a carry, which this time happens if both g and h are zero, and we add 1 to 179-f in this case.

# MATL, 51 bytes

'NS'tPXEii'WE'tPXE648e3i60:qXJZA-JYAtn3-?2:&)wJZAwh


Input format:

'N'
[50 26 23]
'W'
[4 18 29]


Output format:

S
50 26 23
E
175  41  31


Try it online!

### Explanation

'NS'tPXE     % Take input (string) implicitly. Exchange 'N' and 'S'
i            % Take input (array)
i'WE'tPXE    % Take input (string). Exchange 'W' and 'E'
648e3        % Push 648000
i            % Take input (array)
60:qXJ       % Push [0 1 ... 59]. Copy into clipboard J
ZA           % Convert second input array from base 60 to decimal
-            % Subtract
JYA          % Convert to base 60
tn3-?        % If length exceeds 3
2:&)       %   Split into first two elements and then the rest
w          %   Swap
JZA        %   Convert from base 60 to decimal
wh         %   Swap, concatenate

• There's a typo in your explanation on the second to last line: bnase. – TheBikingViking Jul 31 '16 at 23:19
• @TheBikingViking Thank you! Corrected – Luis Mendo Jul 31 '16 at 23:27

# Racket, 199 bytes

(λ(l)(cons(cons(if(eq?(caar l)'n)'s'n)(cdar l))(cons(if(eq?(cadr l)'e)'w'e)(list (- 180(+(caddr l)(sgn(foldl + 0(cdddr l)))))(modulo(- 60(+(fourth l)(sgn(fifth l))))60)(modulo(- 60(fifth l))60)))))


That's horribly long. There's probably some things I could do to shorten it further, but shudders I'm completely done.

Takes a cons pair of two lists: one for the latitude and one for the longitude. Each list has the direction (as a lowercase Racket symbol) as its first item and following it the degrees, arc-minutes, and arc-seconds. Outputs in the same format

Racket will interpret this pair of two lists as a single list with another list as its first element. This is perfectly fine, since you can still access both latitude and longitude as if they were two lists in a pair.

Usage:

>    (
(λ(l)(cons(cons(if(eq?(caar l)'n)'s'n)(cdar l))(cons(if(eq?(cadr l)'e)'w'e)(list (- 180(+(caddr l)(sgn(foldl + 0(cdddr l)))))(modulo(- 60(+(fourth l)(sgn(fifth l))))60)(modulo(- 60(fifth l))60)))))
(cons (list 's 43 9 9) (list 'e 0 0 5)))
'((n 43 9 9) w 179 59 55)


Which can be interpreted by future code as '((n 43 9 9) (w 179 59 55)), two lists.

# Pyth, 414543 35 bytes

K60-"NS"ww-"EW"wA.D-*3^K3iEKK+.DGKH


Uses base-60 conversion to turn degrees and minutes into seconds.

I/O format:

N
[1,2,3]
E
[4,5,6]


It prints a line every time you input a line, so to have a good-looking format, you can either use the CLI and pipe the input, or more conveniently, use the online Pyth implementation.

In pseudocode:

K60                                              K = 60
-"NS"w                                        "NS".remove(input())
w                                       print(input())
-"EW"w                                 "EW".remove(input())
A.D                              G,H = divmod(
-*3^K3                          3*K**3 -
iEK                         baseToDec(input(),K)),
K                      K)
+.DGKH              divmod(G,K)+H

• @LuisMendo same as yours, but comma separated lists, and no quotes – busukxuan Jul 6 '16 at 0:35

## Python 2, 140 122 bytes

Updated:

def f(c):x=([180,0,0],[179,59,60])[1<sum(c[6:8])];print['NS'['N'in c]]+c[1:4]+['EW'['E'in c]]+map(lambda x,y:x-y,x,c[5:8])


This uses a slightly different approach: setting the values to subtract from the longitude based on the minutes and seconds. If there are 0 mins and seconds, it subtracts 180 from the degrees, and if there are >0 mins and secs, it subtracts 179, 59, and 60 from the d, m, s respectively.

Original:

def f(c):v=divmod;m,s=v((180-(c+c/60.+c/3600.))*3600,60);d,m=v(m,60);print['NS'['N'in c]]+c[1:4]+['EW'['E'in c]]+map(round,[d,m,s])


Takes input as a list: f(['N', 0, 0, 0, 'E', 0, 0, 0]), converts the longitude to decimal degrees, subtracts from 180, then converts back to degrees, minutes, seconds and re-constructs the list, flipping the directions in the process.

Un-golfed:

def f(c):
minutes,seconds=divmod((180-(c+c/60.+c/3600.))*3600,60)
degrees,minutes=divmod(minutes,60)
print ['NS'['N'in c]]+c[1:4]+['EW'['E'in c]]+map(round,[degrees,minutes,seconds])


Try it

# JavaScript, 138137129124112 110

2 bytes improvement inspired by @Neil´s code

f=a=>a.map((v,i,a)=>i%4?i>6?v&&60-v:i>5?(59-v+!a)%60:i>4?179-v+!(a|a):v:'NEWS'[3-'NEWS'.indexOf(v)]);

• input = output = array containing 2x(1 uppercase char and 3 int)
• tested in Firefox

ungolfed

f=a=>a.map((v,i,a)=>
i%4?
i>6?v&&60-v              // 7: invert seconds - old: (60-v)%60
:i>5?(59-v+!a)%60     // 6: invert minutes, increase if seconds are 0
:i>4?179-v+!(a|a)  // 5: invert degrees, increase if seconds and minutes are 0
:v                       // 1,2,3: unchanged
:'NEWS'[3-'NEWS'.indexOf(v)] // 0,4: swap directions
);


tests

<table id=out border=1><tr><th>in</th><th>out<th>expected</th><th>ok?</th></tr></table>
<script>

samples=[
'N',50,26,23,'W',4,18,29,   'S',50,26,23,'E',175,41,31,
'S',43,9,9,'E',0,0,5,       'N',43,9,9,'W',179,59,55,
'N',0,0,0,'E',0,0,0,        'S',0,0,0,'W',180,0,0,
'S',1,2,3,'W',4,5,6,        'N',1,2,3,'E',175,54,54,
'S',9,21,43,'W',150,7,59,   'N',9,21,43,'E',29,52,1,
'S',27,40,2,'W',23,0,0,     'N',27,40,2,'E',157,0,0,
'N',0,58,37,'W',37,0,0,     'S',0,58,37,'E',143,0,0,
];
while (samples.length)
{
x=samples.splice(0,8);
e=samples.splice(0,8);
test(x,e,h);
test(e,x,h);
}
</script>

• ah I just see @Neil had the same idea, but some shorter parametrizing – Titus Jul 6 '16 at 15:19

# Python 3, 131 130 bytes

def f(w,x,y,z):S=60;d=divmod;a,b,c=y;l,m=d(648e3-c-S*b-S*S*a,S);return w,"N" if x=="S" else "S",d(l,S)+(m,),"E" if z=="W" else "W"


Formats: angles are tuples of the form (deg,min,sec), directions are of the form N. Outputs a quadruple of 2 angles, each followed by its direction.

Ungolfed version:

def f(latitude,NS,longitude,EW):
degree,minute,second=longitude
minute,second=divmod(648000-second-60*minute-60*60*degree,60)
return latitude, "N" if NS=="S" else "S", divmod(minute,60)+(second,), "E" if EW=="W" else "W"

• You can get this down to 120 bytes by doing def f(w,x,y,z):S=60;d=divmod;a,b,c=y;l,m=d(648e3-c-S*b-S*S*a,S);return w,["S","N"][x=="S"],d(l,S)+(m,),["W","E"][z=="W"] This works by using the fact that True and False can be interpreted as 1 and 0 , and hence a if b else c is equivalent to [c, a][b]. On a side note, I think that your original code has a typo; should x=="W" be z=="W"? – TheBikingViking Jul 6 '16 at 19:31

# C#, 310 269 bytes

float[]t(string[]a,int n)=>a.Skip(n).Take(3).Select(float.Parse).ToArray();string A(string i){var s=i.Split(' ');var w=t(s,5);float a=180-(w+w/60+w/3600),b=a%1*60;return(s>82?"N":"S")+$" {string.Join(" ",t(s,1))} {(s<70?'W':'E')} {a} {b} "+b%1*60;}  The input is one string. You can try it on .NetFiddle. Code float[]t(string[]a,int n)=>a.Skip(n).Take(3).Select(float.Parse).ToArray(); string A(string i) { var s=i.Split(' ');var w=t(s,5);float a=180-(w+w/60+w/3600),b=a%1*60; return (s>82?"N":"S") +$" {string.Join(" ",t(s,1))} {(s<70?'W':'E')} {a} {b} "+b%1*60;
}


If I don't take a string as input but a char, float[], char, float[], I can do:

# C#, 167166165163152148147 139 bytes

(s,n,e,w)=>{float a=180-(w+w/60+w/3600),b=a%1*60;return(s>82?"N":"S")+$" {string.Join(" ",n)} {(e<70?'W':'E')} {a} {b} "+b%1*60;};  Code (s,n,e,w) => { float a=180-(w+w/60+w/3600),b=a%1*60; return(s>82?"N":"S")+$" {string.Join(" ",n)} {(e<70?'W':'E')} {a} {b} "+b%1*60;
};


Also I can remove the 3600 and use ฐ instead to move to 164 characters and 166 bytes. Should I use it?

# C#, 150 bytes

(s,n,m,p,e,w,x,y)=>{var t=new TimeSpan(180,0,0)-new TimeSpan(w,x,y);return(s>82?"N":"S")+$" {n} {m} {p} {(e<70?'W':'E')} {t.TotalHours} {t:%m\\ s}";};  Code (s,n,m,p,e,w,x,y) => { var z=new TimeSpan(180,0,0)-new TimeSpan(w,x,y); return(s>82?"N":"S")+$" {n} {m} {p} {(e<70?'W':'E')} {z.TotalHours} {z:%m\\ s}";
};


A more .NET way! I delegate all the logic to the .NET struct TimeSpan and I abuse the string formatting logic. Input is char, int, int, int, char, int, int, int. I share this one to give some ideas. Maybe someone will improve in a better way than me.

• That is unfortunately verbose. – Steven H. Jul 5 '16 at 23:41
• @Fawful I post another version with different arguments. Less verbose isn't? I still can't get rid of string.Join()... – aloisdg moving to codidact.com Jul 6 '16 at 3:30
• Do note that this is C# 6.0 – Yytsi Jul 6 '16 at 9:12
• @TuukkaX since it is the lastest version of C#, I didn't specify it. I will if I use some un release feature like C#7 feature. – aloisdg moving to codidact.com Jul 6 '16 at 11:11
• Well, I don't see a return, I had to add it myself... Using your test a('N', new float[] { 50, 26, 23 }, 'W', new float[] { 4, 18, 29 }) I get S 50 26 23 E 175.6919 41.51642 30.98511 - would you consider this a pass? – onedaywhen Jul 6 '16 at 11:40

# Java, 199 177 or 151 or 134 Bytes

177 Bytes solution which prints result

void t(int...a){int i=648000-(a*3600+a*60+a);System.out.println(a=='N'?"S":"N"+" "+a+" "+a+" "+a+" "+(a=='E'?"W":"E")+" "+i/3600+" "+i/60%60+" "+i%60);}


151 Bytes solution which returns result as array

Object[]y(int...a){int i=648000-(a*3600+a*60+a);return new Object[]{a=='N'?"S":"N",a,a,a,a=='E'?"W":"E",i/3600,i/60%60,i%60};}


134 Bytes if we used lambda notation

a->{int i=648000-a*3600-a*60-a;return new Object[]{a=='N'?"S":"N",a,a,a,a=='E'?"W":"E",i/3600,i/60%60,i%60};}


# C, 188

main(int c,char**v){int n=*v==78?83:78,e=*v==69?87:69,b=648000-(atoi(v)*3600+atoi(v)*60+atoi(v));printf("%c %s %s %s %c %d %d %d\n",n,v,v,v,e,b/3600,b/60%60,b%60);}


Requires 8 program arguments, will fail otherwise. Pass arguments like N 50 26 23 W 4 18 29. Direction indicators N, S, E, W, must be capitalized.

# PostGIS, 123 bytes

The Tool-For-The-Job is disappointingly verbose, partly because of SQL wordiness and partly due to the need to cast to geometry and back:

CREATE FUNCTION f(p geography)
RETURNS geography
AS 'SELECT ST_Affine(p::geometry,1,0,0,-1,180,0)::geography' LANGUAGE sql;


On the other hand, this single function will transform points, collections of points, or more complex shapes (such as the entire coastline of Australia and New Zealand).

# PHP, 148 bytes

same approach as my JavaScript answer, look there for a breakdown

• +17 for $ signs • +12 for parantheses (different operator precedence) • +4 for foreach because PHP´s array_map has a huge overhead • +1 for (60-$v)%60 because $v&&60-$v casts to boolean in PHP
• -8 by working on the original
• -4 by using chr, ord and some arithmetics on the direction swap

function f(&$a){foreach($a as$i=>$v)$a[$i]=$i%4?($i>6?(60-$v)%60:($i>5?(59-$v+!$a)%60:($i>4?179-$v+!($a|$a):$v))):chr(($i?156:161)-ord($v));}  • function works on original • format: array with 2x (1 uppercase char, 3 int) tests function out($a){if(!is_array($a))return$a;$r=[];foreach($a as$v)$r[]=out($v);return'['.join(',',$r).']';}
function cmp($a,$b){if(is_numeric($a)&&is_numeric($b))return 1e-2<abs($a-$b);if(is_array($a)&&is_array($b)&&count($a)==count($b)){foreach($a as$v){$w = array_shift($b);if(cmp($v,$w))return true;}return false;}return strcmp($a,$b);}
$samples=[ N,50,26,23,W,4,18,29, S,50,26,23,E,175,41,31, S,43,9,9,E,0,0,5, N,43,9,9,W,179,59,55, N,0,0,0,E,0,0,0, S,0,0,0,W,180,0,0, S,1,2,3,W,4,5,6, N,1,2,3,E,175,54,54, S,9,21,43,W,150,7,59, N,9,21,43,E,29,52,1, S,27,40,2,W,23,0,0, N,27,40,2,E,157,0,0, N,0,58,37,W,37,0,0, S,0,58,37,E,143,0,0, ]; while ($samples)
{
$xx=$x=array_splice($samples,0,8);$ee=$e=array_splice($samples,0,8);
func($x); test($xx,$ee,$x);
func($e); test($ee,$xx,$e);
}


abandoned ideas

• no loop approach with carry flags: +5
• loop backwards with carry flags: +7
• I could turn this into a program for PHP<5.4, but never mind: -3

# Befunge, 122114 111 Bytes (110 characters)

~"N"-v
v"N"_"S"
v>,&.&.&.~"W"-
_"E"v"W"
+:v >,&"´"\-&"Z"*&
v\_\.00..@.-\"<".-1\ <
>1-.:"Z"/"<"\-\"Z"%:#^_\..@


Input format:

N 50 26 23W 4 18 29


Notice the longitude direction and the arc seconds must be huddled together

You may test the code here