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