#!/usr/bin/env python # https://adventofcode.com/2025/day/5 import re, operator from functools import reduce f = open("day06input.txt", "r") #f = open("testinput.txt", "r") d = [l.strip("\n") for l in f.readlines()] r = re.compile("\s+") def get_op(s: str) -> callable: if s == "*": return operator.mul elif s == "+": return operator.add else: raise Exception("Unknown operator!") def prep_data(raw_data: list[str]) -> list[str]: # split lines raw_data = [r.split(l) for l in raw_data] # remove empty first/last element(s) if present (these occur when there are spaces before a data line's first or fater its final number/operator) for d in raw_data: if d[0] == "": d.pop(0) if d[-1] == "": d.pop() # make sure all data lines have the same length assert all([len(raw_data[j+1]) - len(raw_data[j]) == 0 for j in range(len(raw_data) - 1)]) return raw_data def part1(data: list[str]) -> int: data = prep_data(data) total = 0 # loop over number of elements per data line for i in range(len(data[0])): total += reduce(get_op(data[-1][i]), [int(data[j][i]) for j in range(len(data) - 1)]) return total def part2(data: list[str]) -> int: # get length of longest number in each column # actually I'm counting the number of spaces between each operator but this value is equal to what we're looking for num_lengths = [len(x) for x in r.findall(data[-1])] # final num_length is too small b/c there's no single-space gap to the next element num_lengths[-1] += 1 ops = prep_data([data[-1]])[0] total = 0 r_left = re.compile("(^\s+)") r_right = re.compile("(\s+$)") for j in range(len(num_lengths)): stripes = [] for i in range(len(data) - 1): # cut out correct part of data line d = data[i][:num_lengths[j]] # replace spaces with dummy character at the start of the substring m = r_left.search(d) if m: a, b = m.span() d = "X" * (b - a) + d[b:] # replace spaces with dummy character at the end of the substring m = r_right.search(d) if m: a, b = m.span() d = d[:a] + "X" * (b - a) # store the prepped substring stripes.append(d) # clip substring from data line data[i] = data[i][num_lengths[j]+1:] # calculate the actual numbers actual_nums = [] for i in range(len(stripes[0])): num = "".join([stripes[k][i] for k in range(len(stripes))]) actual_nums.append(int(num.strip("X"))) # print(actual_nums) # print(f"{j}\t{ops[j]}\t{get_op(ops[j])}\t{reduce(get_op(ops[j]), actual_nums)}") total += reduce(get_op(ops[j]), actual_nums) return total print(part1(d)) print(part2(d))