Solved 2015/14 P1+P2

This commit is contained in:
FrederikBaerentsen 2024-12-15 00:11:39 +01:00
parent 4c9a134bd4
commit 4e67cca173
2 changed files with 165 additions and 0 deletions

73
2015/14/14.md Normal file
View File

@ -0,0 +1,73 @@
## \-\-- Day 14: Reindeer Olympics \-\--
This year is the Reindeer Olympics! Reindeer can fly at high speeds, but
must rest occasionally to recover their energy. Santa would like to know
which of his reindeer is fastest, and so he has them race.
Reindeer can only either be *flying* (always at their top speed) or
*resting* (not moving at all), and always spend whole seconds in either
state.
For example, suppose you have the following Reindeer:
- Comet can fly *14 km/s for 10 seconds*, but then must rest for *127
seconds*.
- Dancer can fly *16 km/s for 11 seconds*, but then must rest for *162
seconds*.
After one second, Comet has gone 14 km, while Dancer has gone 16 km.
After ten seconds, Comet has gone 140 km, while Dancer has gone 160 km.
On the eleventh second, Comet begins resting (staying at 140 km), and
Dancer continues on for a total distance of 176 km. On the 12th second,
both reindeer are resting. They continue to rest until the 138th second,
when Comet flies for another ten seconds. On the 174th second, Dancer
flies for another 11 seconds.
In this example, after the 1000th second, both reindeer are resting, and
Comet is in the lead at *`1120`* km (poor Dancer has only gotten `1056`
km by that point). So, in this situation, Comet would win (if the race
ended at 1000 seconds).
Given the descriptions of each reindeer (in your puzzle input), after
exactly `2503` seconds, *what distance has the winning reindeer
traveled*?
Your puzzle answer was `2660`.
## \-\-- Part Two \-\-- {#part2}
Seeing how reindeer move in bursts, Santa decides he\'s not pleased with
the old scoring system.
Instead, at the end of each second, he awards one point to the reindeer
currently in the lead. (If there are multiple reindeer tied for the
lead, they each get one point.) He keeps the traditional 2503 second
time limit, of course, as doing otherwise would be [entirely
ridiculous]{title="It also risks choosing a duration that isn't coprime with the cycle times of each reindeer."}.
Given the example reindeer from above, after the first second, Dancer is
in the lead and gets one point. He stays in the lead until several
seconds into Comet\'s second burst: after the 140th second, Comet pulls
into the lead and gets his first point. Of course, since Dancer had been
in the lead for the 139 seconds before that, he has accumulated 139
points by the 140th second.
After the 1000th second, Dancer has accumulated *`689`* points, while
poor Comet, our old champion, only has `312`. So, with the new scoring
system, Dancer would win (if the race ended at 1000 seconds).
Again given the descriptions of each reindeer (in your puzzle input),
after exactly `2503` seconds, *how many points does the winning reindeer
have*?
Your puzzle answer was `1256`.
Both parts of this puzzle are complete! They provide two gold stars:
\*\*
At this point, you should [return to your Advent calendar](/2015) and
try another puzzle.
If you still want to see it, you can [get your puzzle
input](14/input).

92
2015/14/solution.py Normal file
View File

@ -0,0 +1,92 @@
#!/bin/python3
import sys,time,re
from pprint import pprint
sys.path.insert(0, '../../')
from fred import list2int,get_re,nprint,lprint,loadFile
start_time = time.time()
input_f = 'input'
def loadRaindeers(input_f):
"""Load raindeer info from file into a dict
Args:
input_f (str): filename
Returns:
dict: Returns a dict of raindeer into
"""
raindeers = {}
with open(input_f) as file:
for line in file:
match = get_re(r"^(\w+).*fly (\d+).*for (\d+).* for (\d+) seconds.$",line.rstrip())
raindeers[match.group(1)] = {
'speed': int(match.group(2)),
'time': int(match.group(3)),
'rest': int(match.group(4)),
'distance' : 0,
'score': 0
}
return raindeers
#########################################
# #
# Part 1 #
# #
#########################################
def part1():
raindeers = loadRaindeers(input_f)
print(raindeers)
seconds = 2503
max_dist = 0
for r in raindeers:
speed = raindeers[r]['speed']
time = raindeers[r]['time']
rest = raindeers[r]['rest']
cycle = (time+rest)
number_cycles = seconds//cycle
remainder = seconds%cycle
distance = speed * (number_cycles*time+min(remainder,time))
if distance > max_dist:
max_dist = distance
return max_dist
start_time = time.time()
print('Part 1:',part1(), '\t\t', round((time.time() - start_time)*1000), 'ms')
#########################################
# #
# Part 2 #
# #
#########################################
def part2():
raindeers = loadRaindeers(input_f)
seconds = 2503
for i in range(1,seconds+1):
for r in raindeers:
speed = raindeers[r]['speed']
time = raindeers[r]['time']
rest = raindeers[r]['rest']
cycle = (time+rest)
# Cycle 0 to time+rest, but distance is only updated while
# the cycle is less than time.
if i % cycle <= time and i % cycle != 0:
raindeers[r]['distance'] += speed
current_winner = max(raindeers[r]['distance'] for r in raindeers)
ties = [k for k, r in raindeers.items() if r['distance'] == current_winner]
for t in ties:
raindeers[t]['score'] += 1
return max(raindeers[r]['score'] for r in raindeers)
start_time = time.time()
print('Part 2:',part2(), '\t\t', round((time.time() - start_time)*1000), 'ms')