diff --git a/src/Year_2016/P15.py b/src/Year_2016/P15.py new file mode 100644 index 0000000..33ed384 --- /dev/null +++ b/src/Year_2016/P15.py @@ -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() diff --git a/src/Year_2016/files/P15.txt b/src/Year_2016/files/P15.txt new file mode 100644 index 0000000..17fed19 --- /dev/null +++ b/src/Year_2016/files/P15.txt @@ -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. diff --git a/src/Year_2017/P15.py b/src/Year_2017/P15.py new file mode 100644 index 0000000..7eda8c4 --- /dev/null +++ b/src/Year_2017/P15.py @@ -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() diff --git a/src/Year_2017/files/P15.txt b/src/Year_2017/files/P15.txt new file mode 100644 index 0000000..46491bf --- /dev/null +++ b/src/Year_2017/files/P15.txt @@ -0,0 +1,2 @@ +Generator A starts with 618 +Generator B starts with 814