Skip to content
advent of code 2023

day 01

trebuchet?!

approach

each line's calibration value is its first digit times ten plus its last digit, read from the list of digit characters in the line. part 1 sums those.

part 2 also counts spelled-out digits. instead of scanning for every word, replace finds only the leftmost spelled-out digit (smallest find) and the rightmost one (largest rfind) and writes the matching digit in next to them; the rest of the line is left alone, so overlapping words like twone don't get in each other's way. the same calibration function then runs on the rewritten lines.

there is also a rust version that does exactly the same, with the same leftmost/rightmost rewrite.

the trick

only the first and last spelled-out digits matter, so rewrite just those two and leave overlaps alone.

python
lmn = min(((i, sn) for sn in snums if (i := line.find(sn)) != -1), default = None)
rmx = max(((i, sn) for sn in snums if (i := line.rfind(sn)) != -1), default = None)

if lmn is None and rmx is None:
    return line
elif lmn == rmx:
    i, sn = lmn
    return line[:i] + snums[sn] + line[i + len(sn):]
else:
    li, lsn = lmn
    ri, rsn = rmx
    left = line[:li] + snums[lsn]
    mid = line[li + len(lsn):ri]
    right = line[ri:] + snums[rsn] + line[ri + len(rsn):]
    return left + mid + right