Solution to problem 15 in Python
This commit is contained in:
parent
9eeba7ff77
commit
c88edc6f06
105
src/Year_2016/P15.py
Normal file
105
src/Year_2016/P15.py
Normal file
@ -0,0 +1,105 @@
|
||||
# --- Day 15: Timing is Everything ---
|
||||
|
||||
# The halls open into an interior plaza containing a large kinetic sculpture.
|
||||
# The sculpture is in a sealed enclosure and seems to involve a set of identical
|
||||
# spherical capsules that are carried to the top and allowed to bounce through
|
||||
# the maze of spinning pieces.
|
||||
|
||||
# Part of the sculpture is even interactive! When a button is pressed, a capsule
|
||||
# is dropped and tries to fall through slots in a set of rotating discs to
|
||||
# finally go through a little hole at the bottom and come out of the sculpture.
|
||||
# If any of the slots aren't aligned with the capsule as it passes, the capsule
|
||||
# bounces off the disc and soars away. You feel compelled to get one of those
|
||||
# capsules.
|
||||
|
||||
# The discs pause their motion each second and come in different sizes; they
|
||||
# seem to each have a fixed number of positions at which they stop. You decide
|
||||
# to call the position with the slot 0, and count up for each position it
|
||||
# reaches next.
|
||||
|
||||
# Furthermore, the discs are spaced out so that after you push the button, one
|
||||
# second elapses before the first disc is reached, and one second elapses as the
|
||||
# capsule passes from one disc to the one below it. So, if you push the button
|
||||
# at time=100, then the capsule reaches the top disc at time=101, the second
|
||||
# disc at time=102, the third disc at time=103, and so on.
|
||||
|
||||
# The button will only drop a capsule at an integer time - no fractional seconds
|
||||
# allowed.
|
||||
|
||||
# For example, at time=0, suppose you see the following arrangement:
|
||||
|
||||
# Disc #1 has 5 positions; at time=0, it is at position 4.
|
||||
# Disc #2 has 2 positions; at time=0, it is at position 1.
|
||||
|
||||
# If you press the button exactly at time=0, the capsule would start to fall;
|
||||
# it would reach the first disc at time=1. Since the first disc was at position
|
||||
# 4 at time=0, by time=1 it has ticked one position forward. As a five-position
|
||||
# disc, the next position is 0, and the capsule falls through the slot.
|
||||
|
||||
# Then, at time=2, the capsule reaches the second disc. The second disc has
|
||||
# ticked forward two positions at this point: it started at position 1, then
|
||||
# continued to position 0, and finally ended up at position 1 again. Because
|
||||
# there's only a slot at position 0, the capsule bounces away.
|
||||
|
||||
# If, however, you wait until time=5 to push the button, then when the capsule
|
||||
# reaches each disc, the first disc will have ticked forward 5+1 = 6 times (to
|
||||
# position 0), and the second disc will have ticked forward 5+2 = 7 times (also
|
||||
# to position 0). In this case, the capsule would fall through the discs and
|
||||
# come out of the machine.
|
||||
|
||||
# However, your situation has more than two discs; you've noted their positions
|
||||
# in your puzzle input. What is the first time you can press the button to get
|
||||
# a capsule?
|
||||
|
||||
import re
|
||||
|
||||
with open("files/P15.txt") as f:
|
||||
arrangements = [
|
||||
tuple(map(int, re.findall("\d+", line))) for line in f.readlines()
|
||||
]
|
||||
|
||||
|
||||
def part_1():
|
||||
tik = 0
|
||||
while True:
|
||||
for i, (_, positions, _, position) in enumerate(arrangements, start=1):
|
||||
if not (position + tik + i) % positions:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
print(tik)
|
||||
break
|
||||
tik += 1
|
||||
|
||||
|
||||
# --- Part Two ---
|
||||
|
||||
# After getting the first capsule (it contained a star! what great fortune!),
|
||||
# the machine detects your success and begins to rearrange itself.
|
||||
|
||||
# When it's done, the discs are back in their original configuration as if it
|
||||
# were time=0 again, but a new disc with 11 positions and starting at position 0
|
||||
# has appeared exactly one second below the previously-bottom disc.
|
||||
|
||||
# With this new disc, and counting again starting from time=0 with the
|
||||
# configuration in your puzzle input, what is the first time you can press the
|
||||
# button to get another capsule?
|
||||
|
||||
|
||||
def part_2():
|
||||
arrangements.append((1, 11, 0, 0))
|
||||
tik = 0
|
||||
while True:
|
||||
for i, (_, positions, _, position) in enumerate(arrangements, start=1):
|
||||
if not (position + tik + i) % positions:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
print(tik)
|
||||
break
|
||||
tik += 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
part_1()
|
||||
part_2()
|
6
src/Year_2016/files/P15.txt
Normal file
6
src/Year_2016/files/P15.txt
Normal file
@ -0,0 +1,6 @@
|
||||
Disc #1 has 7 positions; at time=0, it is at position 0.
|
||||
Disc #2 has 13 positions; at time=0, it is at position 0.
|
||||
Disc #3 has 3 positions; at time=0, it is at position 2.
|
||||
Disc #4 has 5 positions; at time=0, it is at position 2.
|
||||
Disc #5 has 17 positions; at time=0, it is at position 0.
|
||||
Disc #6 has 19 positions; at time=0, it is at position 7.
|
170
src/Year_2017/P15.py
Normal file
170
src/Year_2017/P15.py
Normal file
@ -0,0 +1,170 @@
|
||||
# --- Day 15: Dueling Generators ---
|
||||
|
||||
# Here, you encounter a pair of dueling generators. The generators, called
|
||||
# generator A and generator B, are trying to agree on a sequence of numbers.
|
||||
# However, one of them is malfunctioning, and so the sequences don't always
|
||||
# match.
|
||||
|
||||
# As they do this, a judge waits for each of them to generate its next value,
|
||||
# compares the lowest 16 bits of both values, and keeps track of the number of
|
||||
# times those parts of the values match.
|
||||
|
||||
# The generators both work on the same principle. To create its next value, a
|
||||
# generator will take the previous value it produced, multiply it by a factor
|
||||
# (generator A uses 16807; generator B uses 48271), and then keep the remainder
|
||||
# of dividing that resulting product by 2147483647. That final remainder is the
|
||||
# value it produces next.
|
||||
|
||||
# To calculate each generator's first value, it instead uses a specific starting
|
||||
# value as its "previous value" (as listed in your puzzle input).
|
||||
|
||||
# For example, suppose that for starting values, generator A uses 65, while
|
||||
# generator B uses 8921. Then, the first five pairs of generated values are:
|
||||
|
||||
# --Gen. A-- --Gen. B--
|
||||
# 1092455 430625591
|
||||
# 1181022009 1233683848
|
||||
# 245556042 1431495498
|
||||
# 1744312007 137874439
|
||||
# 1352636452 285222916
|
||||
|
||||
# In binary, these pairs are (with generator A's value first in each pair):
|
||||
|
||||
# 00000000000100001010101101100111
|
||||
# 00011001101010101101001100110111
|
||||
|
||||
# 01000110011001001111011100111001
|
||||
# 01001001100010001000010110001000
|
||||
|
||||
# 00001110101000101110001101001010
|
||||
# 01010101010100101110001101001010
|
||||
|
||||
# 01100111111110000001011011000111
|
||||
# 00001000001101111100110000000111
|
||||
|
||||
# 01010000100111111001100000100100
|
||||
# 00010001000000000010100000000100
|
||||
|
||||
# Here, you can see that the lowest (here, rightmost) 16 bits of the third value
|
||||
# match: 1110001101001010. Because of this one match, after processing these
|
||||
# five pairs, the judge would have added only 1 to its total.
|
||||
|
||||
# To get a significant sample, the judge would like to consider 40 million
|
||||
# pairs. (In the example above, the judge would eventually find a total of 588
|
||||
# pairs that match in their lowest 16 bits.)
|
||||
|
||||
# After 40 million pairs, what is the judge's final count?
|
||||
|
||||
import re
|
||||
from copy import copy
|
||||
|
||||
with open("files/P15.txt") as f:
|
||||
gens = list(map(int, re.findall("\d+", f.read())))
|
||||
|
||||
|
||||
def part_1():
|
||||
a, b = copy(gens)
|
||||
npairs = 0
|
||||
|
||||
for _ in range(40000000):
|
||||
a = (a * 16807) % 2147483647
|
||||
b = (b * 48271) % 2147483647
|
||||
|
||||
if a & 0xFFFF == b & 0xFFFF:
|
||||
npairs += 1
|
||||
|
||||
print(f"The judge final count is {npairs}")
|
||||
|
||||
|
||||
# --- Part Two ---
|
||||
|
||||
# In the interest of trying to align a little better, the generators get more
|
||||
# picky about the numbers they actually give to the judge.
|
||||
|
||||
# They still generate values in the same way, but now they only hand a value to
|
||||
# the judge when it meets their criteria:
|
||||
|
||||
# Generator A looks for values that are multiples of 4.
|
||||
# Generator B looks for values that are multiples of 8.
|
||||
|
||||
# Each generator functions completely independently: they both go through values
|
||||
# entirely on their own, only occasionally handing an acceptable value to the
|
||||
# judge, and otherwise working through the same sequence of values as before
|
||||
# until they find one.
|
||||
|
||||
# The judge still waits for each generator to provide it with a value before
|
||||
# comparing them (using the same comparison method as before). It keeps track of
|
||||
# the order it receives values; the first values from each generator are
|
||||
# compared, then the second values from each generator, then the third values,
|
||||
# and so on.
|
||||
|
||||
# Using the example starting values given above, the generators now produce the
|
||||
# following first five values each:
|
||||
|
||||
# --Gen. A-- --Gen. B--
|
||||
# 1352636452 1233683848
|
||||
# 1992081072 862516352
|
||||
# 530830436 1159784568
|
||||
# 1980017072 1616057672
|
||||
# 740335192 412269392
|
||||
|
||||
# These values have the following corresponding binary values:
|
||||
|
||||
# 01010000100111111001100000100100
|
||||
# 01001001100010001000010110001000
|
||||
|
||||
# 01110110101111001011111010110000
|
||||
# 00110011011010001111010010000000
|
||||
|
||||
# 00011111101000111101010001100100
|
||||
# 01000101001000001110100001111000
|
||||
|
||||
# 01110110000001001010100110110000
|
||||
# 01100000010100110001010101001000
|
||||
|
||||
# 00101100001000001001111001011000
|
||||
# 00011000100100101011101101010000
|
||||
|
||||
# Unfortunately, even though this change makes more bits similar on average,
|
||||
# none of these values' lowest 16 bits match. Now, it's not until the 1056th
|
||||
# pair that the judge finds the first match:
|
||||
|
||||
# --Gen. A-- --Gen. B--
|
||||
# 1023762912 896885216
|
||||
|
||||
# 00111101000001010110000111100000
|
||||
# 00110101011101010110000111100000
|
||||
|
||||
# This change makes the generators much slower, and the judge is getting
|
||||
# impatient; it is now only willing to consider 5 million pairs. (Using the
|
||||
# values from the example above, after five million pairs, the judge would
|
||||
# eventually find a total of 309 pairs that match in their lowest 16 bits.)
|
||||
|
||||
# After 5 million pairs, but using this new generator logic, what is the judge's
|
||||
# final count?
|
||||
|
||||
|
||||
def part_2():
|
||||
a, b = copy(gens)
|
||||
npairs = 0
|
||||
|
||||
for _ in range(5000000):
|
||||
while True:
|
||||
a = (a * 16807) % 2147483647
|
||||
if a % 4 == 0:
|
||||
break
|
||||
|
||||
while True:
|
||||
b = (b * 48271) % 2147483647
|
||||
if b % 8 == 0:
|
||||
break
|
||||
|
||||
if a & 0xFFFF == b & 0xFFFF:
|
||||
npairs += 1
|
||||
|
||||
print(f"The judge final count is {npairs}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
part_1()
|
||||
part_2()
|
2
src/Year_2017/files/P15.txt
Normal file
2
src/Year_2017/files/P15.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Generator A starts with 618
|
||||
Generator B starts with 814
|
Loading…
Reference in New Issue
Block a user