commit 993f9555566d97b99f9853aa741fb62f494dc9a1
parent 2a907e61f669b35fe9260f01175bc8e4b8ed8c46
Author: Eamon Caddigan <eamon.caddigan@gmail.com>
Date: Wed, 8 Dec 2021 14:34:48 -0500
(Finally implemented a) solution to day 8, part 1
Diffstat:
M | day08_part1.py | | | 75 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/day08_part1.py b/day08_part1.py
@@ -26,12 +26,16 @@ displays"""
# each line of puzzle input! But...
# I'm not going to implement it yet, because "good programmers are lazy", and
# maybe part 2 will throw me for a loop? Regardless, figuring this out has
-# influenced my decision about how to represent the data; i.e., we're doing a
+# influenced my decision about how to represent the data; e.g., we're doing a
# lot of set operations, so I'm going to use sets for everything, and since
# it's easy to imagine wanting to use these sets of lit segments as dictionary
# keys, we'll use immutable `frozenset`s specifically (which can be `dict`
# keys).
+
+import pandas as pd
+from utils import get_puzzle_input, convert_lines_to_series
+
EXAMPLE_INPUT = \
"""be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
@@ -44,3 +48,72 @@ bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbg
egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce
"""
+
+def convert_input_to_df(input_string):
+ """Convert the puzzle input to a five-column df: the first a string of
+ unique segment sets, and the next four `frozenset` objects representing the
+ display digits"""
+ display_df= (
+ convert_lines_to_series(input_string)
+ .str.rsplit(' ', 4, expand=True)
+ .rename(columns=dict(enumerate(('segments', 'digit_1', 'digit_2',
+ 'digit_3', 'digit_4'))))
+ )
+ display_df.loc[:, 'digit_1':'digit_4'] = (
+ display_df.loc[:, 'digit_1':'digit_4'].applymap(frozenset)
+ )
+ return display_df
+
+def create_mapper_from_segments(segment_sequence):
+ """Given the observed sequence of segment sets (which isn't actually used
+ for anything here), return a function that maps a `frozenset` of segments
+ to a digit"""
+ # Another example of getting ready for what part 2 might look like: this is
+ # more complicated than necessary but if we do need to decode every line
+ # then this function is one of the few that would need to be changed.
+ def part_1_mapper(segments):
+ """This is the simple mapping function that we need for part 1, that
+ identifies the digits '1', '4', '7', and '8' based on the number of
+ segments that are lit. Returns the matching digit as a string or `None`
+ if its not one of these"""
+ return (
+ {2: '1', 3: '7', 4: '4', 7: '8'}
+ .get(len(segments), None)
+ )
+ return part_1_mapper
+
+def apply_mappers_to_digits(display_df, mapper_creator):
+ """Given a df that contains the unique segment sequence and four columns of
+ digits, use the `mapper_creator` function to make a mapping function for
+ each row of segment sequences and apply that function to the digits from
+ the same row, then return a df with the digits"""
+ # I don't love how this is coded, not one bit
+ digits_dict = {}
+ for col in [f"digit_{i}" for i in range(1, 5)]:
+ digits_dict[col] = [f(x) for f, x in \
+ zip(display_df['segments'].map(mapper_creator),
+ display_df[col])]
+ return pd.DataFrame(digits_dict)
+
+def count_visible_digits(digits_df):
+ """Given a four-column df of digit displays, return the number of 'visible'
+ digits (one of '1', '4', '7', or '8') present"""
+ return int(digits_df.count().sum())
+
+def solve_puzzle(input_string):
+ """Return the numeric solution to the puzzle"""
+ return count_visible_digits(
+ apply_mappers_to_digits(
+ convert_input_to_df(input_string),
+ create_mapper_from_segments
+ )
+ )
+
+def main():
+ """Run when the file is called as a script"""
+ assert solve_puzzle(EXAMPLE_INPUT) == 26
+ print("Number of easily decoded digits:",
+ solve_puzzle(get_puzzle_input(8)))
+
+if __name__ == "__main__":
+ main()