with open('data-2025-02.txt', 'r') as f:
inp = f.read().splitlines()
id = inp[0].split(',')
idn = [[int(x.split('-')[0]), int(x.split('-')[1])] for x in id]Advent of Code 2025 Day 2
— Day 2: Gift Shop —
A silly elf has produced some invalid IDs. Repeated sequences of digits make an ID invalid.
What do you get if you add up all of the invalid IDs?
Is it possible to do this by hand?
The numbers need to be an even number of digits - 131 cannot be an invalid number.
There are some sequences that look like palindromes which makes me think that could be part two.
9226492264, 9226592265, 9226692266 (3)
(0)
4242, 4343, 4444, up to 6363 (22)
687687 up to 835835 (149)
Ah, wait, I can work out how many there are, but I cannot work out the sum of all of these very easily.
# test the lengths
s = []
for i in idn:
s.append((len(str(i[0])), len(str(i[1]))))
# set(s)
t = list(set(s))
t.sort(key=lambda x: x[0])
t[(1, 2),
(2, 3),
(2, 2),
(3, 3),
(4, 4),
(4, 5),
(5, 5),
(6, 7),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10)]
Lengths look OK, none go from 3 to 5 digits, which means I can test for odds, which cannot be invalid.
I need to check for odd/even and even/odd in a nice way.
summer = 0
for i in idn:
if len(str(i[0])) % 2 == 1 and len(str(i[1])) % 2 == 1:
# both are odd amount of digits, cannot be invalid
# print('odds')
pass
elif len(str(i[0])) in (8, 10):
# only need to loop by the first half of the numbers
# and then see if any of those repeat
# print('large')
ia = str(i[0])
ib = str(i[1])
mn = ia[:len(ia)//2]
mx = ib[:len(ib)//2]
for m in range(int(mn), int(mx)+1):
if i[0] < int(str(m) + str(m)) < i[1]:
# print(str(m) + str(m))
summer += int(str(m) + str(m))
else:
# print('small')
# just use a regular loop
for m in range(i[0], i[1]+1):
if len(str(m)) % 2 == 0:
# only check the even ones
ms = str(m)
if ms[:len(ms)//2] == ms[len(ms)//2:]:
summer += m
summer38158151648
— Part Two —
The elf made other kinds of repeating digits, anything repeated at least twice. All sequences could have repeats, even if it is the same number repeated i.e. 111. Check every pair of digits, but only with factors, i.e. 1 into two digits; 1 into 3; 1 and 2 into 4; 1 into 5; 1, 2, 3 into 6; 1 into 7.
Or, alternatively, 2 into half; 3 into 3 pieces; 4 into 4 and 2; 5 into 5, 6 into 6, 3, 2; 7 into 7 pieces.
What do you get if you add up all of the invalid IDs using these new rules?
summer = 0
ppp = False
def all_same_num(f):
# i.e. 111
if len(set(str(f))) == 1:
if ppp: print(f)
return f
else:
return 0
def halves_num(f):
# i.e. 2323
fs = str(f)
if fs[:len(fs)//2] == fs[len(fs)//2:]:
if ppp: print(f)
return f
else:
return 0
def pairs_num(f):
# i.e. 454545
fs = str(f)
f1 = fs[:2]
if fs == (f1 * (len(fs)//2)):
if ppp: print(fs)
return f
else:
return 0
def all_same_range(mn, mx, k):
ss = 0
a1 = int(str(mn)[0])
a2 = int(str(mx)[0])
for a in range(a1, a2+1):
if mn <= int(str(a) * k) <= mx:
if ppp: print(int(str(a) * k))
ss += int(str(a) * k)
return ss
def halves_range(ma, mb):
# used for 8 and 10 length
ss = 0
ia = str(ma)
ib = str(mb)
mn = ia[:len(ia)//2]
mx = ib[:len(ib)//2]
for m in range(int(mn), int(mx)+1):
if (ma <= int(str(m) + str(m)) <= mb) and \
not all_same_num(int(str(m) + str(m))):
if ppp: print(str(m) + str(m))
ss += int(str(m) + str(m))
return ss
def pairs_range(ma, mb, k):
# used for 8 and 10 length
ss = 0
ia = str(ma)
ib = str(mb)
mn = ia[:2]
mx = ib[:2]
for m in range(int(mn), int(mx)+1):
if (ma <= int(str(m) * (k//2)) <= mb) and \
not all_same_num(int(str(m) * (k//2))) and \
not halves_num(int(str(m) * (k//2))):
if ppp: print(str(m) * (k//2))
ss += int(str(m) * (k//2))
return ss
def threes_range(ma, mb):
# only used for 9
ss = 0
ia = str(ma)
ib = str(mb)
mn = ia[:3]
mx = ib[:3]
for m in range(int(mn), int(mx)+1):
if ma <= int(str(m) * 3) <= mb:
if ppp: print(str(m) * 3)
ss += int(str(m) * 3)
return ss
for i in idn:
k = len(str(i[0]))
if k in (3,5,7):
# odd numbers with all repetition
# print('odd')
summer += all_same_range(i[0], i[1], k)
elif k in (1, 2):
# short numbers
for j in range(i[0], i[1]+1):
if len(str(j)) == 1:
pass
else:
summer += all_same_num(j)
elif k == 4:
for j in range(i[0], i[1]+1):
g = len(str(j))
if g == 5:
summer += all_same_num(j)
elif str(j)[0] == str(j)[1]:
# check for all same
summer += all_same_num(j)
else:
# check for halves
summer += halves_num(j)
elif k == 6:
for j in range(i[0], i[1]+1):
g = len(str(j))
if g == 7:
summer += all_same_num(j)
elif all_same_num(j):
# check for all same
summer += j
else:
# check for halves
summer += halves_num(j)
# check pairs
summer += pairs_num(j)
elif k == 8:
summer += all_same_range(i[0], i[1], k)
summer += halves_range(i[0], i[1])
summer += pairs_range(i[0], i[1], k)
elif k == 9:
summer += all_same_range(i[0], i[1], k)
summer += threes_range(i[0], i[1])
elif k == 10:
summer += all_same_range(i[0], i[1], k)
summer += halves_range(i[0], i[1])
summer += pairs_range(i[0], i[1], k)
summer
# 54340905136 too high
# 45253714604 too low
# 45253714615 too low
# 4528368455545283684555
I added 11 and removed duplicates - some numbers can qualify for more than one category.
I think brute force will be fine, the numbers are big but the ranges are not that bad. Loop without any reference to length.
def threes_num(f):
# i.e. 456456456
fs = str(f)
f1 = fs[:3]
if fs == (f1 * 3):
print(fs)
return f
else:
return 0
summer = 0
for i in idn:
for j in range(i[0], i[1] + 1):
if len(str(j)) == 1:
pass # cannot have single digits
elif all_same_num(j):
summer += j
elif halves_num(j):
summer += j
elif pairs_num(j):
summer += j
elif threes_num(j):
summer += j
summer
# 39021058338 lower than the other numbers that are too low
# fixed it 829829829
45283688628