advent-of-code/2022/python/day13.py

106 lines
3.6 KiB
Python
Raw Normal View History

2022-12-13 05:47:25 +00:00
import matrix
import shared
import itertools
2022-12-13 07:30:36 +00:00
import functools
2022-12-13 05:47:25 +00:00
2022-12-13 06:33:34 +00:00
2022-12-13 05:47:25 +00:00
def part1(rows):
groups = [list(v) for k, v in itertools.groupby(rows, key=lambda x: not x) if not k]
2022-12-13 06:33:34 +00:00
indexes = []
2022-12-13 05:47:25 +00:00
for idx, (left, right) in enumerate(groups):
left = eval(left)
right = eval(right)
2022-12-13 07:30:36 +00:00
# print(f"== Pair {idx+1} ==")
passes = check_group(left, right)
if passes:
2022-12-17 03:07:17 +00:00
indexes.append(idx + 1)
2022-12-13 07:30:36 +00:00
# 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}")
2022-12-13 06:33:34 +00:00
print(sum(indexes))
2022-12-13 05:47:25 +00:00
2022-12-13 07:30:36 +00:00
def check_group(left, right):
if isinstance(left, list) and isinstance(right, list):
2022-12-17 03:07:17 +00:00
# if both items are lists, loop over both
2022-12-13 07:30:36 +00:00
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)
2022-12-13 06:33:34 +00:00
else:
2022-12-13 07:30:36 +00:00
# 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
2022-12-17 03:07:17 +00:00
# Otherwise, the inputs are the same integer; continue checking the next part of the input.
2022-12-13 07:30:36 +00:00
elif left == right:
return None
2022-12-13 05:47:25 +00:00
2022-12-17 03:07:17 +00:00
2022-12-13 07:30:36 +00:00
def part2(rows):
2022-12-13 07:36:36 +00:00
two, six = 0, 0
2022-12-13 07:30:36 +00:00
rows = [eval(r) for r in rows if r]
rows.append([[2]])
rows.append([[6]])
def cmp(x, y):
2022-12-17 03:07:17 +00:00
return {
True: 1,
False: -1,
}[check_group(x, y)]
2022-12-13 07:30:36 +00:00
2022-12-17 03:07:17 +00:00
idx = 0 # ew 1 based lists, jeeeze AoC
2022-12-13 07:36:36 +00:00
for r in sorted(rows, key=functools.cmp_to_key(cmp), reverse=True):
idx += 1
2022-12-13 07:30:36 +00:00
if r == [[2]]:
2022-12-13 07:36:36 +00:00
two = idx
2022-12-13 07:30:36 +00:00
if r == [[6]]:
2022-12-13 07:36:36 +00:00
six = idx
2022-12-17 03:07:17 +00:00
break # will come 2nd logically, so we can break here to save time
2022-12-13 07:30:36 +00:00
print(two * six)
2022-12-13 05:47:25 +00:00
def main():
rows = shared.load_rows(13)
with shared.elapsed_timer() as elapsed:
part1(rows)
2022-12-13 07:30:36 +00:00
print("🕒", elapsed())
with shared.elapsed_timer() as elapsed:
2022-12-17 03:07:17 +00:00
part2(rows)
print("🕒", elapsed())
2022-12-13 05:47:25 +00:00
if __name__ == "__main__":
main()