Solution to http://adventofcode.com/2016/day/2 using reduce and accumulate
#!/usr/bin/env python3 | |
# Solution to http://adventofcode.com/2016/day/2 part 1 | |
# using reduce and accumulate for awesome functional programing style points | |
# Mark Jenkins <mark@markjenkins.ca> | |
from sys import stdin | |
from functools import reduce | |
from itertools import chain, accumulate, islice | |
START_LOCATION = "5" | |
ROW_SIZE = 3 | |
FIRST_NUM = 1 | |
LAST_NUM = 9 | |
def same_row(num, num_next): | |
# integer arithmatic, shifting over to a 0-8 scale means that | |
# assert(0//3 == 1//3 == 2//3) | |
# assert(3//3 == 4//3 == 5//3) | |
# assert(6//3 == 7//3 == 8//3) | |
if not (FIRST_NUM<=num<=LAST_NUM): | |
return False | |
else: | |
return (num-1)//ROW_SIZE == (num_next-1)//ROW_SIZE | |
def move_graph_entry(num): | |
return { | |
"U": num if num-ROW_SIZE < FIRST_NUM else num-ROW_SIZE, | |
"D": num if num+ROW_SIZE > LAST_NUM else num+ROW_SIZE, | |
"R": num if not same_row(num, num+1) else num+1, | |
"L": num if not same_row(num, num-1) else num-1, | |
} | |
def stringified_move_graph_entry(int_move_graph): | |
return { key: str(val) for key,val in int_move_graph.items() } | |
MOVE_GRAPH = { | |
str(num): stringified_move_graph_entry(move_graph_entry(num)) | |
for num in range(FIRST_NUM, LAST_NUM+1) | |
} | |
def reduce_location_and_line_to_location(location, line): | |
return reduce( | |
lambda loc, character: MOVE_GRAPH[loc][character], | |
line, # sequence of characters | |
location) | |
location = START_LOCATION | |
# finish this the imperative way | |
# for line in stdin: | |
# location = reduce_location_and_line_to_location(location, line.strip() ) | |
# print(location, end='') | |
# print() | |
# or, finish this with accumulate() feeding ''.join(), because we can | |
print( ''.join( islice( accumulate( | |
chain( (START_LOCATION,), | |
(line.strip() for line in stdin) ), | |
lambda loc, line: reduce_location_and_line_to_location(loc, line) ), | |
1, None | |
) # islice | |
) # join | |
#!/usr/bin/env python3 | |
# Solution to http://adventofcode.com/2016/day/2 part 2 | |
# Simply patch my solution to part 1 with a different MOVE_GRAPH | |
# Mark Jenkins <mark@markjenkins.ca> | |
from sys import stdin | |
from functools import reduce | |
from itertools import chain, accumulate, islice | |
START_LOCATION = "5" | |
ROW_SIZE = 3 | |
FIRST_NUM = 1 | |
LAST_NUM = 9 | |
def same_row(num, num_next): | |
# integer arithmatic, shifting over to a 0-8 scale means that | |
# assert(0//3 == 1//3 == 2//3) | |
# assert(3//3 == 4//3 == 5//3) | |
# assert(6//3 == 7//3 == 8//3) | |
if not (FIRST_NUM<=num<=LAST_NUM): | |
return False | |
else: | |
return (num-1)//ROW_SIZE == (num_next-1)//ROW_SIZE | |
def move_graph_entry(num): | |
return { | |
"U": num if num-ROW_SIZE < FIRST_NUM else num-ROW_SIZE, | |
"D": num if num+ROW_SIZE > LAST_NUM else num+ROW_SIZE, | |
"R": num if not same_row(num, num+1) else num+1, | |
"L": num if not same_row(num, num-1) else num-1, | |
} | |
def stringified_move_graph_entry(int_move_graph): | |
return { key: str(val) for key,val in int_move_graph.items() } | |
MOVE_GRAPH_OLD = { | |
str(num): stringified_move_graph_entry(move_graph_entry(num)) | |
for num in range(FIRST_NUM, LAST_NUM+1) | |
} | |
MOVE_GRAPH_PATCH = { | |
str(num): str(num+1) | |
for num in range(FIRST_NUM, 3+1) | |
} | |
MOVE_GRAPH_PATCH.update( | |
{ str(num): str(num+2) | |
for num in range(4,6+1) | |
} | |
) | |
MOVE_GRAPH_PATCH.update( | |
{ num: new_let | |
for num, new_let in zip( "789", "ABC") | |
} | |
) | |
MOVE_GRAPH = { | |
MOVE_GRAPH_PATCH[key]: {direction: MOVE_GRAPH_PATCH[destination] | |
for direction, destination in value.items() | |
} | |
for key, value in MOVE_GRAPH_OLD.items() | |
} | |
MOVE_GRAPH.update( | |
{ '1': {'U':'1', 'R':'1', 'D':'3', 'L': '1'}, | |
'9': {'U':'9', 'R':'9', 'D':'9', 'L': '8'}, | |
'D': {'U':'B', 'R':'D', 'D':'D', 'L': 'D'}, | |
'5': {'U':'5', 'R':'6', 'D':'5', 'L': '5'}, | |
} ) | |
MOVE_GRAPH['3']['U'] = '1' | |
MOVE_GRAPH['8']['R'] = '9' | |
MOVE_GRAPH['B']['D'] = 'D' | |
MOVE_GRAPH['6']['L'] = '5' | |
def reduce_location_and_line_to_location(location, line): | |
return reduce( | |
lambda loc, character: MOVE_GRAPH[loc][character], | |
line, # sequence of characters | |
location) | |
location = START_LOCATION | |
# finish this the imperative way | |
# for line in stdin: | |
# location = reduce_location_and_line_to_location(location, line.strip() ) | |
# print(location, end='') | |
# print() | |
# or, finish this with accumulate() feeding ''.join(), because we can | |
print( ''.join( islice( accumulate( | |
chain( (START_LOCATION,), | |
(line.strip() for line in stdin) ), | |
lambda loc, line: reduce_location_and_line_to_location(loc, line) ), | |
1, None | |
) # islice | |
) # join | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment