import matrix import shared import itertools import functools def part1(rows): groups = [list(v) for k, v in itertools.groupby(rows, key=lambda x: not x) if not k] indexes = [] for idx, (left, right) in enumerate(groups): left = eval(left) right = eval(right) # print(f"== Pair {idx+1} ==") passes = check_group(left, right) if passes: indexes.append(idx + 1) # if passes is True: # print(f"{idx+1} {matrix.colors.GREEN}{passes}{matrix.colors.ENDC}") # elif passes is False: # print(f"{idx+1} {matrix.colors.RED}{passes}{matrix.colors.ENDC}") # else: # print(f"{idx+1} {matrix.colors.BLUE}{passes}{matrix.colors.ENDC}") print(sum(indexes)) def check_group(left, right): if isinstance(left, list) and isinstance(right, list): # if both items are lists, loop over both for idx in range(min(len(left), len(right))): check = check_group(left[idx], right[idx]) # bubble up the int comparisons, or list length comparisons if check is False: return False elif check is True: return True # is None, continue on! TALLY HO! else: # If the left list runs out of items first, the inputs are in the right order. if len(left) < len(right): return True # If the right list runs out of items first, the inputs are not in the right order. if len(left) > len(right): return False # If the lists are the same length and no comparison makes a decision about the order, continue checking the next part of the input. return None elif isinstance(left, int) and isinstance(right, list): # If exactly one value is an integer, convert the integer to a list which contains # that integer as its only value, then retry the comparison. left = [left] return check_group(left, right) elif isinstance(left, list) and isinstance(right, int): # If exactly one value is an integer, convert the integer to a list which contains # that integer as its only value, then retry the comparison. right = [right] return check_group(left, right) else: # both ints now # If the left integer is lower than the right integer, the inputs are in the right order. if left < right: return True # If the left integer is higher than the right integer, the inputs are not in the right order. elif left > right: return False # Otherwise, the inputs are the same integer; continue checking the next part of the input. elif left == right: return None def part2(rows): two, six = 0, 0 rows = [eval(r) for r in rows if r] rows.append([[2]]) rows.append([[6]]) def cmp(x, y): return { True: 1, False: -1, }[check_group(x, y)] idx = 0 # ew 1 based lists, jeeeze AoC for r in sorted(rows, key=functools.cmp_to_key(cmp), reverse=True): idx += 1 if r == [[2]]: two = idx if r == [[6]]: six = idx break # will come 2nd logically, so we can break here to save time print(two * six) def main(): rows = shared.load_rows(13) with shared.elapsed_timer() as elapsed: part1(rows) print("🕒", elapsed()) with shared.elapsed_timer() as elapsed: part2(rows) print("🕒", elapsed()) if __name__ == "__main__": main()