106 lines
3.6 KiB
Python
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()
|