Advertisement
Guest User

AOC 2021 Day 3

a guest
Dec 4th, 2021
632
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.39 KB | None | 0 0
  1. # aoc202103.py
  2.  
  3. import pathlib
  4. import sys
  5. from typing import Any
  6.  
  7.  
  8. def parse(puzzle_input: str) -> list[list[str]]:
  9.     """ Parse input """
  10.     # Return a 2-D array
  11.     return [[c for c in line] for line in puzzle_input.splitlines()]
  12.  
  13.  
  14. def transpose_array(array: list[list[Any]]) -> list[list[Any]]:
  15.     """ Transpose a 2-D array of any type """
  16.     return list(zip(*array))
  17.  
  18.  
  19. def most_frequent(seq: list[str], preferred: str) -> str:
  20.     """ Return most frequent item in a list seq """
  21.     first, sec = list(set(seq))
  22.     # Deal with equal count
  23.     if seq.count(first) == seq.count(sec):
  24.         return preferred
  25.     return max(set(seq), key=seq.count)
  26.  
  27.  
  28. def least_frequent(seq: list[str], preferred: str) -> str:
  29.     """ Return most frequent item in a list seq """
  30.     first, sec = list(set(seq))
  31.     # Deal with equal count
  32.     if seq.count(first) == seq.count(sec):
  33.         return preferred
  34.     return min(set(seq), key=seq.count)
  35.  
  36.  
  37. def binary_product(a: str, b: str) -> int:
  38.     """ Take two binary numbers as strings and return their product as an int """
  39.     return int(a, 2) * int(b, 2)
  40.  
  41.  
  42. def flatten(t: list[list[Any]]) -> list[Any]:
  43.     """ Flatten a nested list """
  44.     return [item for sublist in t for item in sublist]
  45.  
  46.  
  47. def get_rating(array: list[list[str]],
  48.                columns: int,
  49.                low: bool = False) -> list[str]:
  50.     """ Find one row in an array that matches the bit_criteria """
  51.     for col in range(columns):
  52.         cols = transpose_array(array)
  53.         # For the CO2 scrubber rating
  54.         if low:
  55.             bit = least_frequent(cols[col], "0")
  56.         # For the oxygen generator rating
  57.         else:
  58.             bit = most_frequent(cols[col], "1")
  59.         # Only include the rows which meet the criteria
  60.         target = [row for row in array if row[col] == bit]
  61.         array = target[:]
  62.         # Bail out early if target identified
  63.         if len(array) == 1:
  64.             break
  65.     # Just in case...
  66.     if len(array) != 1:
  67.         raise ValueError("Unique target not found")
  68.     # Unnest the list and return
  69.     return flatten(target)
  70.  
  71.  
  72. def part1(data: list[list[str]]) -> int:
  73.     """ Solve part 1 """
  74.     # Transpose the array
  75.     cols = transpose_array(data)
  76.     # Get the most frequent values from cols
  77.     gamma = ''.join(most_frequent(col, '1') for col in cols)
  78.     # Get the least frequent values from cols
  79.     epsilon = ''.join(least_frequent(col, '0') for col in cols)
  80.     return binary_product(gamma, epsilon)
  81.  
  82.  
  83. def part2(data: list[str]) -> int:
  84.     """ Solve part 2 """
  85.     # Transpose the array
  86.     cols = transpose_array(data)
  87.     # Get the oxygen generator rating
  88.     oxy = ''.join(get_rating(data, len(cols)))
  89.     # Get the CO2 scrubber rating
  90.     co2 = ''.join(get_rating(data, len(cols), low=True))
  91.     return binary_product(oxy, co2)
  92.  
  93.  
  94. def solve(puzzle_input: str) -> tuple[int, int]:
  95.     """ Solve the puzzle for the given input """
  96.     data = parse(puzzle_input)
  97.     solution1 = part1(data)  # Correct answer was 2498354 (with my data)
  98.     solution2 = part2(data)  # Correct answer was 3277956 (with my data)
  99.  
  100.     return solution1, solution2
  101.  
  102.  
  103. if __name__ == "__main__":
  104.     for path in sys.argv[1:]:
  105.         print(f"{path}:")
  106.         puzzle_input = pathlib.Path(path).read_text().strip()
  107.         solutions = solve(puzzle_input)
  108.         print('\n'.join(str(solution) for solution in solutions))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement