Skip to content

Instantly share code, notes, and snippets.

@markjenkins
Last active December 7, 2016 07:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markjenkins/b2b4a9251cb3e14224bd3214e1a377df to your computer and use it in GitHub Desktop.
Save markjenkins/b2b4a9251cb3e14224bd3214e1a377df to your computer and use it in GitHub Desktop.
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