123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- import logging
-
- from itertools import pairwise
- from sys import stdout
-
- logger = logging.Logger(__name__)
- logger_2 = logging.Logger(f"{__name__}_2")
- formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
- sh = logging.StreamHandler(stdout)
- sh.setLevel(logging.INFO)
- sh.setFormatter(formatter)
- fh = logging.FileHandler("./day02-2.log", mode="w", encoding="utf-8")
- fh_2 = logging.FileHandler("./day02-2_round2.log", mode="w", encoding="utf-8")
- fh.setLevel(logging.DEBUG)
- fh.setFormatter(formatter)
- fh_2.setLevel(logging.DEBUG)
- fh_2.setFormatter(formatter)
- logger.addHandler(sh)
- logger.addHandler(fh)
- logger_2.addHandler(fh_2)
-
- # So, a report only counts as safe if both of the following are true:
-
- # The levels are either all increasing or all decreasing.
- # Any two adjacent levels differ by at least one and at most three.
-
- # The Problem Dampener is a reactor-mounted module that lets the reactor
- # safety systems tolerate a single bad level in what would otherwise be a
- # safe report. It's like the bad level never happened!
-
- # Now, the same rules apply as before, except if removing a single level
- # from an unsafe report would make it safe, the report instead counts as safe.
-
- def report(msg, i=0, spotter=20, use_2=False):
- if i % spotter == 0:
- logger.info(msg)
- else:
- logger.debug(msg)
- if use_2:
- logger_2.debug(msg)
-
- def test_line(line):
- pw_l = list(pairwise(line))
- raw_distances = [(y-x) for x,y in pw_l]
- abs_distances = [abs(x) for x in raw_distances]
- # -1 if the pair is going from high to low
- # 1 if the pair is going from low to high
- # 0 if the pair is equal
- directions = [-1 if x > y else (0 if x == y else 1) for x,y in pw_l]
- pure_ascending = all([d > 0 for d in directions])
- pure_descending = all([d < 0 for d in directions])
- pure_and_close = (pure_ascending or pure_descending) and all([1 <= d <= 3 for d in abs_distances])
- report(f"""Line {line}:
- Pairs: {pw_l}
- Raw distances: {raw_distances}
- Absolute distances: {abs_distances}
- Directions: {directions}
- Pure ascending: {pure_ascending}
- Pure descending: {pure_descending}
- Pure and close: {pure_and_close}""", spotter=100, use_2=True)
- return {
- "Pairwise": pw_l,
- "Raw distances": raw_distances,
- "Absolute distances": abs_distances,
- "Directions": directions,
- "Pure ascending": pure_ascending,
- "Pure descending": pure_descending,
- "Pure and close": pure_and_close
- }
-
- def main():
- with open("input02.txt", "r", encoding="utf-8") as f:
- lines = [list(map(int,l.split(" "))) for l in f.readlines()]
-
- line_stats = []
- safe_lines = 0
- for i, line in enumerate(lines):
- base_stats = test_line(line)
- line_stats.append(base_stats)
- if base_stats["Pure and close"]:
- safe_lines += 1
- continue
- break_out = False
- j = 0
- while not break_out and j < len(line):
- new_line = line[:j] + line[j+1:]
- report(f"Checking variant of line {line}: {new_line}")
- nl_stats = test_line(new_line)
- if nl_stats["Pure and close"]:
- safe_lines += 1
- break_out = True
- continue
- j += 1
-
-
-
- report(f"Number of safe lines: {safe_lines}")
-
- if __name__ == "__main__":
- main()
|