solution to https://adventofcode.com/2016/day/1 part 2, uses reduce(), nearly functional
#!/usr/bin/env python3 | |
# solution to https://adventofcode.com/2016/day/1 part 2 | |
# in a functional style with python 3.3+ enhanced accumulate() and dropwhile() | |
# Mark Jenkins <mark@markjenkins.ca> | |
from itertools import accumulate, dropwhile, chain | |
MOVEMENTS = ((0,1), (1,0), (0,-1), (-1,0)) | |
DIRECTION_CHANGES = {"R": 1, "L": -1} | |
def next_pos(state, token): | |
displacement, direction = state | |
change_dir = DIRECTION_CHANGES[token[0]] | |
change_magnitude = int(token[1:]) | |
new_direction = (direction + change_dir) % len(MOVEMENTS) | |
move = (change_magnitude*MOVEMENTS[new_direction][0], | |
change_magnitude*MOVEMENTS[new_direction][1] ) | |
new_displacement = (displacement[0] + move[0], displacement[1] + move[1]) | |
locations_visited = frozenset( | |
(displacement[0] + i*MOVEMENTS[new_direction][0], | |
displacement[1] + i*MOVEMENTS[new_direction][1]) | |
for i in range(1, change_magnitude+1) | |
) | |
return new_displacement, new_direction, locations_visited | |
def next_pos_with_history(state, token): | |
(displacement, direction, | |
last_locations_visited, old_locations_visited) = state | |
combined_locations_visited = old_locations_visited.union( | |
last_locations_visited) | |
new_displacement, new_direction, new_locations_visited = \ | |
next_pos((displacement, direction),token) | |
return (new_displacement, new_direction, | |
new_locations_visited, combined_locations_visited) | |
initial_state = ((0, 0), 0, frozenset(), frozenset()) | |
history_accumulation = accumulate( | |
chain( (initial_state,), input().split(", ") ), | |
next_pos_with_history | |
) # accumulate | |
def no_repeat_of_history(state): | |
(displacement, direction, | |
last_locations_visited, old_locations_visited) = state | |
return not any( new_loc in old_locations_visited | |
for new_loc in last_locations_visited) | |
# find the first repeat of history | |
success=next(dropwhile(no_repeat_of_history, history_accumulation), None) | |
if success == None: | |
print("no repeat of location found") | |
else: | |
assert( not no_repeat_of_history(success) ) | |
(displacement, direction, | |
last_locations_visited, old_locations_visited) = success | |
repeat_location = next( | |
dropwhile( lambda new_loc: new_loc not in old_locations_visited, | |
last_locations_visited ) # dropwhile | |
) # next | |
print( abs(repeat_location[0]) + abs(repeat_location[1]) ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment