advent-of-code/2022/python/day13.py
2022-12-16 22:07:17 -05:00

106 lines
3.6 KiB
Python

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()