Advent Of Code 2016 Day 1 Part 1: No Time for a Taxicab
but requires understanding of complex numbers.
descending into obfuscation.
Definitions:
#!/usr/bin/env python3
'''First, a very straightforward readable solution.
Coordinates are in tuples.'''
from math import sin, cos, radians
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
def manhattan_distance(*points):
return sum(
abs(coordinate1 - coordinate2)
for coordinate1, coordinate2 in zip(*points))
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=(0., 0.), # (east, north) Unit is 1 block for each coordinate.
):
course = starting_course
location = starting_location
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
location = tuple(
coordinate + distance * func(radians(course))
for coordinate, func in zip(location, (sin, cos)))
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location = (0, 0)
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination, starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
raw_routes = (
('20161202-aoc-day1part1-test', 'R5, L5, R5, R3'),
# from https://github.com/hakim89/adventofcode/raw/master/day01/part-01.py
('20161202-aoc-day1part1-long',
'''
R4, R5, L5, L5, L3, R2, R3, R2, L1, R5, R1, L5, R2, L2, L4, R3,
L1, R4, L5, R4, R3, L5, L3, R4, R2, L5, L5, R2, R3, R5, R4, R2,
R1, L1, L5, L2, L3, L4, L5, L4, L5, L1, R3, R4, R5, R3, L5, L4,
L3, L1, L4, R2, R5, R5, R4, L2, L4, R3, R1, L2, R5, L5, R1, R1,
L1, L5, L5, L2, L1, R5, R2, L4, L1, R4, R3, L3, R1, R5, L1, L4,
R2, L3, R5, R3, R1, L3'''),
)
for filename, raw_instructions in raw_routes:
with open(filename, 'w') as f:
f.write(raw_instructions)
for filename, _ in raw_routes:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'Use vector math with numpy.'
from math import sin, cos, radians
from numpy import array
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
def manhattan_distance(vector):
return sum(map(abs, vector))
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=array([0., 0.]), # [east, north] Unit is 1 block for each coordinate.
):
course = starting_course
location = starting_location.copy()
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
v = array([func(radians(course)) for func in (sin, cos)])
location += distance * v
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location=array([0., 0.])
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination - starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
for filename in route_filenames:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12.0 blocks away. Easter Bunny HQ is 44.0 blocks away.
import cmath
from math import radians
cmath.rect(10., radians(30))
(8.660254037844387+4.999999999999999j)
#!/usr/bin/env python3
'''Use complex numbers to simplify code.
The location calculation is particularly nice.'''
from math import radians
import cmath
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
def manhattan_distance(vector):
return sum(map(abs, (vector.real, vector.imag)))
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=0+0j, # north + east j Unit is 1 block.
):
course = starting_course
location = starting_location
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
location += cmath.rect(distance, radians(course))
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location=0.+0.j
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination - starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
for filename in route_filenames:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'''Use functional approach to obfuscate the code.
Look ma, no for loops.'''
from math import radians
import cmath
from itertools import accumulate, starmap, chain, islice
NORTH = 0
def manhattan_distance(vector):
return sum(map(abs, (vector.real, vector.imag)))
def deflection(move):
deflection_of_turn = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
turn_code = move[:1]
return deflection_of_turn[turn_code]
def distance(move):
distance = move[1:]
return float(distance)
def follow_route(
moves=None, # sequence of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=0+0j, # north + east j Unit is 1 block.
):
distances = map(distance, moves)
deflections = map(deflection, moves)
courses = islice(accumulate(chain(
[starting_course], deflections)), 1, None)
courses = map(radians, courses)
legs = starmap(cmath.rect, zip(distances, courses))
return starting_location + sum(legs)
def process_route(raw_instructions):
instructions = tuple(map(
lambda s: s.strip(),
raw_instructions.split(',')))
starting_location=0+0j
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination - starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
list(map(
process_route,
map(lambda f: f.read(), map(open, route_filenames))))
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'''Continue functional approach to obfuscate the code.
This time with no temporary variables in follow_route().'''
from math import radians
import cmath
from itertools import accumulate, starmap, chain, islice
NORTH = 0
def manhattan_distance(vector):
return sum(map(abs, (vector.real, vector.imag)))
def deflection(move):
deflection_of_turn = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
turn_code = move[:1]
return deflection_of_turn[turn_code]
def distance(move):
distance = move[1:]
return float(distance)
def follow_route(
moves=None, # sequence of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=0+0j, # north + east j Unit is 1 block.
):
return starting_location + sum(
starmap(
cmath.rect,
zip(
map(distance, moves),
map(radians, islice(
accumulate(chain(
[starting_course], map(deflection, moves))),
1,
None)))))
def process_route(raw_instructions):
instructions = tuple(map(
lambda s: s.strip(),
raw_instructions.split(',')))
starting_location=0+0j
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination - starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
list(map(
process_route,
map(lambda f: f.read(), map(open, route_filenames))))
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'Use lambdas for more obfuscation.'
from math import radians
import cmath
from itertools import accumulate, starmap, chain, islice
NORTH = 0
def manhattan_distance(vector):
return sum(map(abs, (vector.real, vector.imag)))
deflection = dict(map(
lambda x: (x[0][0], x[1]),
zip(
('RIGHT', 'LEFT'),
(+90, -90) # Unit of values is one degree clockwise.
)
))
def follow_route(
moves=None, # sequence of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=0+0j, # north + east j Unit is 1 block.
):
return starting_location + sum(starmap(
cmath.rect,
zip(
map(lambda move: float(''.join(move[1:])), moves),
map(
radians,
islice(
accumulate(chain(
[starting_course],
map(lambda move: deflection[move[:1]], moves)
)),
1,
None)))))
def process_route(raw_instructions):
instructions = tuple(map(
lambda s: s.strip(),
raw_instructions.split(',')))
starting_location=0.+0.j
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination - starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
list(map(
process_route,
map(lambda f: f.read(), map(open, route_filenames))))
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
Back to trying to write clean code. Explores using namedtuple and classes based on namedtuples and complex numbers.
#!/usr/bin/env python3
'Use namedtuple.'
from math import sin, cos, radians
from collections import namedtuple
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
Point = namedtuple('Point', ['East', 'North'])
def manhattan_distance(*points):
return sum(
abs(coordinate1 - coordinate2)
for coordinate1, coordinate2 in zip(*points))
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=Point(0., 0.), # Unit is 1 block for each coordinate.
):
course = starting_course
location = starting_location
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
location = Point(*(
coordinate + distance * func(radians(course))
for coordinate, func in zip(location, (sin, cos))))
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location = Point(0., .0)
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
distance = round(manhattan_distance(destination, starting_location))
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=distance))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
for filename in route_filenames:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'Use class based on namedtuple.'
from math import sin, cos, radians
from collections import namedtuple
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
class Point(object):
Point = namedtuple('Point', ['North', 'East'])
def __init__(self, north, east):
self.point = self.Point(North=north, East=east)
def __len__(self):
return len(self.point)
def __getitem__(self, i):
return self.point[i]
def __str__(self):
return '{p.North}N, {p.East}E'.format(p=self.point)
def __repr__(self):
return '{p.North} North, {p.East} East'.format(p=self.point)
def __add__(self, value):
return Point(*(
c1 + c2 for c1, c2 in zip(self.point, value.point)))
def __sub__(self, value):
return Point(*(
c1 - c2 for c1, c2 in zip(self.point, value.point)))
def __round__(self, ndigits=0):
return Point(*(
round(coordinate, ndigits=ndigits)
for coordinate in self.point
))
def __abs__(self):
'manhattan distance'
return sum(map(abs, self.point))
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=Point(0.,0.), # Unit is 1 block for each coordinate.
):
course = starting_course
location = starting_location
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
location = Point(*(
coordinate + distance * func(radians(course))
for coordinate, func in zip(location, (cos, sin))))
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location = Point(0., .0)
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=round(abs(destination - starting_location))))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
for filename in route_filenames:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.
#!/usr/bin/env python3
'Use classes based on complex numbers.'
from math import sin, cos, radians
import cmath
deflection = { # Unit of values is one degree clockwise.
'R': +90,
'L': -90,
}
NORTH = 0
class Point(object):
def __init__(self, north=None, east=None):
self.point = north + east*1j
def __str__(self):
return '{p.real}N {p.imag}E'.format(p=self.point)
def __repr__(self):
return '{p.real} North, {p.imag} East'.format(p=self.point)
def __mul__(self, value):
p = self.point * value
return Point(p.real, p.imag)
def __rmul__(self, value):
return self.__mul__(value)
def __add__(self, value):
p = self.point + value.point
return Point(p.real, p.imag)
def __sub__(self, value):
p = self.point - value.point
return Point(p.real, p.imag)
def __round__(self, ndigits=0):
return Point(
round(self.point.real, ndigits=ndigits),
round(self.point.imag, ndigits=ndigits),
)
def __abs__(self):
'manhattan distance'
return sum(map(abs, (self.point.real, self.point.imag)))
class Vector(Point):
def __init__(self, length=1., azimuth=0.):
self.point = cmath.rect(length, azimuth)
def follow_route(
moves=None, # iterable of [RL]<distance> strings
# Unit of distance is 1 block.
starting_course=None, # Unit is 1 degree clockwise. 0 is North.
starting_location=Point(0.,0.), # Unit is 1 block for each coordinate.
):
course = starting_course
location = starting_location
for turn_code, *distance_chars in moves:
course += deflection[turn_code]
distance = float(''.join(distance_chars))
location += distance * Vector(azimuth=radians(course))
# The following works also.
# location += Vector(length=distance, azimuth=radians(course))
return location
def process_route(raw_instructions):
instructions = (s.strip() for s in raw_instructions.split(','))
starting_location = Point(0., .0)
destination = follow_route(
moves=instructions,
starting_course=NORTH,
starting_location=starting_location,
)
print('Easter Bunny HQ is {distance} blocks away.'.format(
distance=round(abs(destination - starting_location))))
def main():
route_filenames = (
'20161202-aoc-day1part1-test',
'20161202-aoc-day1part1-long',
)
for filename in route_filenames:
with open(filename) as f:
raw_instructions = f.read()
process_route(raw_instructions)
if __name__ == '__main__':
main()
Easter Bunny HQ is 12 blocks away. Easter Bunny HQ is 44 blocks away.