AdventOfCode/2024/11/solution.py

144 lines
4.2 KiB
Python

#!/bin/python3
import sys,time,re
from pprint import pprint
from collections import deque
sys.path.insert(0, '../../')
from fred import list2int,get_re,nprint,lprint,loadFile
start_time = time.time()
input_f = 'input'
part = 1
#########################################
# #
# Part 1 #
# #
#########################################
# Part 1 was first done using a list and each
# number in the input list was converted to ints
# then each new list was created and passed through
# again.
# I also did the Part 1 using deque, but this wasn't
# any faster at all.
def rule2(number):
num_str = str(number)
middle = len(num_str) // 2
return [int(num_str[:middle]), int(num_str[middle:])]
def part1(input_f):
instructions = []
with open(input_f) as file:
instructions = list2int(file.readline().strip().split(' '))
new_inst = []
for x in range(25):
for idx,inst in enumerate(instructions):
if inst == 0:
new_inst.append(1)
else:
if len(list(str(inst))) % 2 == 0:
new_inst += rule2(inst)
else:
new_inst.append(instructions[idx] * 2024)
instructions = new_inst
new_inst = []
return len(instructions)
def part1_dq(input_f):
dq = []
with open(input_f) as file:
dq = deque(file.readline().strip().split(' '))
new_inst = deque([])
for r in range(25):
i = 0
while_time = time.time()
while i < len(dq):
if dq[i] == 0:
new_inst.append(1)
else:
if len(str(dq[i])) % 2 == 0:
x = rule2(dq[i])
new_inst.append(x[0])
new_inst.append(x[1])
else:
new_inst.append(int(dq[i]) * 2024)
i += 1
dq = new_inst
new_inst = deque([])
return len(dq)
start_time = time.time()
print('Part 1:',part1(input_f), '\t\t\t(list)\t', round((time.time() - start_time)*1000), 'ms')
start_time = time.time()
print('Part 1:',part1(input_f), '\t\t\t(deque)\t', round((time.time() - start_time)*1000), 'ms')
#########################################
# #
# Part 2 #
# #
#########################################
# Part 2 was not possible using either list or deque.
# I tested various calculations to see if there was a
# pattern but i couldn't find one.
# I started using simple recursion in hopes that
# would speed it up. That was not the case.
# I ended up splitting the function in two and the part
# that returns a value from the rules, would be stored
# in a dict where the number and the current blink count
# would be the key.
# If a number+blink combo was already in the dict, it
# would use the already calculated result, instead
# of calculating it again.
# I tested using functools.cache on the rules() function
# but that gave the same compute time.
def rule2(number):
num_str = str(number)
middle = len(num_str) // 2
return [str(int(num_str[:middle])), str(int(num_str[middle:]))]
def genNewNumbers(start,end):
if end == 0:
return 1
end -= 1
if (start,end) not in values:
values[(start,end)] = rules(start,end)
result = values[(start,end)]
return result
def rules(start,end):
if start == '0':
result = genNewNumbers('1',end)
else:
if len(start) % 2 == 0:
x = rule2(start)
result = 0
result += genNewNumbers(x[0],end)
result += genNewNumbers(x[1],end)
else:
result = genNewNumbers(str(int(start)*2024),end)
return result
values = {}
def part2(input_f):
numbers = []
with open(input_f) as file:
numbers = file.readline().strip().split(' ')
result = 0
for i in numbers:
result += genNewNumbers(i,75)
return result
start_time = time.time()
print('Part 2:',part2(input_f), '\t(cache)\t', round((time.time() - start_time)*1000), 'ms')