Tracking Santa

December 24, 2010

Each year since 1955, Norad has tracked Santa Claus on his annual journey to deliver toys to good little girls and boys around the world. Since Santa must file his flight plan in advance, we already know where his journey will take him: the route at http://www.noradsanta.org/js/data.js is reproduced on the next page.

Your task is to calculate the number of miles that Santa will travel during his journey; you might find Wikipedia’s Great-circle distance page helpful. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2 3

8 Responses to “Tracking Santa”

1. […] today’s Programming Praxis, our task is to calculate the total distance traveled by Santa based on data […]

```import Data.List.HT
import Text.HJson
import Text.HJson.Query

dist :: RealFloat a => (a, a) -> (a, a) -> a
dist (lat1, lng1) (lat2, lng2) =
let toRad d = d * pi / 180
haversin x = sin (toRad \$ x / 2) ^ 2
a = haversin (lat2 - lat1) +
cos (toRad lat1) * cos (toRad lat2) * haversin (lng2 - lng1)
in 2 * 6371 * atan2 (sqrt a) (sqrt (1 - a))

coords :: Json -> [(Double, Double)]
coords = map ((\[JString lat, JString lng] -> (read lat, read lng)) .
getFromKeys ["lat", "lng"]) . getFromArr

totalMiles :: RealFloat a => [(a, a)] -> Int
totalMiles = round . (* 0.621371192) . sum . mapAdjacent dist

main :: IO ()
main = either print (print . totalMiles . coords) . fromString .
```
3. Hey guys,

I’m new to Ruby so I did my best to throw this together in about 30 min…

My solution

Any help and comments are welcome!

4. Jebb said

With the file data.js saved in the same directory, having deleted the ‘var locations = ‘ bit at the beginning:

```#!/usr/bin/python2.7

import json
f = open(file_name, 'r')
f.close()
return locations

def distance(pointA, pointB):
from math import radians, cos, acos
dlat = lat2 - lat1
ang_dist = acos(cos(dlat) - cos(lat1) * cos(lat2) * (1 - cos(dlong)))
return 6371 * ang_dist

def main():
journey = 0
for i in range(len(locations) - 1):
journey += distance(locations[i], locations[i+1])
print 'Total distance traveled %.0f km' % journey

if __name__ == '__main__':
main()
```

that’s 320,627 km to the metric-inclined.

5. Graham said

A few days late, but here’s my Python
version. I went with the arctangent formula given by Wikiepdia, which it calls
“a more complicated formula that is accurate for all distances.” I also followed
Jebb’s lead of saving “data.js” with the `var locations = ` portion
removed. This can be run (at least on my system) with `./santa.py data.js`.

6. Actually I screwed up my first solution, this is correct I believe: http://pastebin.com/6maXGn80

7. Mike said

Another Python version.

Download the data.js and save to santaflightpath.py. Edit the first line to remove “var “, so it starts with “location =”.
Remove the “;” from the last line. This creates a python compatible statement defining ‘locations’ to be a list of dictionaries. Importing ‘santaflightpath’ executes the code in the file, so there are clearly security implications.

pairwise is from the recipies in the itertools documentation.

Of interest, the flight plan is 28 hours long; stays within 600 miles of the north pole for the first 4 hours; doesn’t appear to visit Antarctica; and doesn’t return to the starting point.

from santaflightplan import locations
from math import asin, sin, cos, radians, sqrt
from itertools import starmap
from utils import pairwise

def distance(p1, p2):
dlat = lat1 – lat2
dlng = lng1 – lng2
ang = 2*asin(sqrt(sin(dlat/2)**2 + cos(lat1)*cos(lat2)*sin(dlng/2)**2))

locs = ((float(p[‘lat’]),float(p[‘lng’])) for p in locations)
print sum(starmap(distance, pairwise(locs)))
[/sourcecode/

8. With a little delay, my commented Python version (looks like the one above http://www.gleocadie.net/?p=572&lang=en)

```def get_coords():
f = open("data.js", encoding='utf-8')
f.close()
return l

def distance(o1, o2):
from math import radians, cos, sin, acos
sins = sin(lat1) * sin(lat2)
coss = cos(lat1) * cos(lat2)
da = acos(sins + coss * cos(radians(lng2 - lng1)))
return 6372.8 * da * 0.621371192

def track_santa():
l = get_coords()
res = 0
for i in range(len(l) - 1):
res = res + distance(l[i], l[i+1])
return res

if __name__ == "__main__":
d = track_santa()
print(d)
```