Skip to content

Riddle 2: Spotting invalid ids

We reuse the headers from 1.md

Reading in is a tad different, but lets make a list of pairs

#reading2
with open(argv[1]) as f:
    pairs : [(int, int)] = [ (int(val) for val in pair.split("-")) for pair in f.read().rstrip('\n').split(',') ]

Now a function to find al invalid ids:

#findinvalid
def find_invalid(start, end):
    startlen = len(str(start))
    if startlen % 2 == 0:
        # Extract the high half
        high = start//10**math.ceil(startlen/2)
    else:
        # Just start at the next possible number
        high = 10**math.floor(startlen/2)

    while True:
        val = high + high * 10**len(str(high))
        # Increase the high half and reconstruct possible invalid values
        high += 1
        if val < start:
            continue
        if val > end:
            break
        yield val

Tying it all together:

file: 2a.py
<<headers>>
<<reading2>>
<<findinvalid>>
all_invalids = it.chain.from_iterable([find_invalid(*pair) for pair in pairs])
with open("docs/output/2a.txt","w") as f:
    f.write(f"{sum(all_invalids)}")

Which gives us the answer:

Answer 2a
28846518423

Part 2

Now we have to find numbers repeated at least twice, the setup should be similar, but we need a new more modular find_invalid function

This could be done smarter by iterating over the possible repeated values instead of every value, but it is fast enough for now

#findinvalid2
def divisors(n):
    return [(x,int(n/x)) for x in range(1, math.floor(n/2)+1) if n % x == 0]

def find_invalid2(start,end):
    val = start-1
    while val < end:
        # Dont be smart, iterate everything
        val += 1
        strlen = len(str(val))
        strval = str(val)            
        # Get divisors
        for x, times in divisors(strlen):
            if strval[0:x]*times == strval:
                yield val
                break
file: 2b.py
<<headers>>
<<reading2>>
<<findinvalid2>>
all_invalids = it.chain.from_iterable([find_invalid2(*pair) for pair in pairs])
with open("docs/output/2b.txt","w") as f:
    f.write(f"{sum(all_invalids)}")

Which gives us the answer:

Answer 2b
31578210022