Skip to content

Latest commit

 

History

History
237 lines (188 loc) · 6.18 KB

17.md

File metadata and controls

237 lines (188 loc) · 6.18 KB

Day 17

Part 1 Part 2 Total
Time 1:29:11 >24h >24h

(Total time approximately 25:30:00.)

Another one, wow.

Part 1

from helpers.datagetter import data_in, submit
from helpers.matrix import Matrix
import re
from collections import Counter, defaultdict
import time
import math

ans = 0
din = data_in(split=True, numbers=False)

gas = [*din[0]]
print(gas)

rock_patterns = [
    [[1, 1, 1, 1]],
    [[0, 1, 0], [1, 1, 1], [0, 1, 0]],
    [[0, 0, 1], [0, 0, 1], [1, 1, 1]],
    [[1], [1], [1], [1]],
    [[1, 1], [1, 1]]
]


def move_rock(rock, x, y):
    global placed_rocks
    for i in range(len(rock)):
        for j in range(len(rock[0])):
            if rock[i][j] == 1 and placed_rocks[f"{x+j},{y-i}"] == 1:
                return False
    return True


def place_rock(rock, x, y):
    global placed_rocks, highest
    for i in range(len(rock)):
        for j in range(len(rock[0])):
            if rock[i][j] == 1:
                placed_rocks[f"{x+j},{y-i}"] = 1


placed_rocks = defaultdict(int)
for i in range(7):
    placed_rocks[f"{i},{0}"] = 1
highest = 0
j = 0
for i in range(2022):
    rock = rock_patterns[i % len(rock_patterns)]
    x = 2
    y = highest + 3 + len(rock)
    #print("start", x, y)
    while True:
        # Move by jets
        oldx = x
        if gas[j % len(gas)] == '>':
            x += 1
            print("right")
        else:
            x -= 1
            print("left")
        j += 1

        if x + len(rock[0]) > 7:
            x = 7 - len(rock[0])
        elif x < 0:
            x = 0

        if not move_rock(rock, x, y):
            print("bad move")
            x = oldx

        # Move down
        print(x, y, highest)
        if not move_rock(rock, x, y-1):
            break
        else:
            y -= 1

    place_rock(rock, x, y)
    highest = max(highest, y)
    print(rock, x, y)
    print()

ans = highest
print(ans)
submit(ans)

Part 2

I was very quick to figure out the cycle (and that we needed to use one), but I kept getting off by one or two for the example input, so I threw in the towel way too late. Should have just gone to bed and come at it with a fresh set of eyes in the morning. Anyways, after I finished Day 18, I went back to this, did some debugging, and finally got it!

Essentially, it finds a cycle of states where the top 2000 rows are the same, and at the same place in the jet pattern. Then it multiplies the difference between the heights at the starts of two consecutive cycle loops for however many loops are needed to reach the limit. Then it adds the difference of the remainging heights when the cycle does not evenly divide the cycle. I also needed to add the height that was present at the start of the first cycle.

I'm not sure why 2000 rows works, but some lower numbers don't. I just kept increasing it until it worked. I'm sure there's some smarter way to look for cycles. For example, using 2000 rows on my input finds a cycle of length 1745 and takes 40 seconds to run, but I think there is a shorter one of length ~384 which would be much much faster to compute.

from helpers.datagetter import data_in, submit
from helpers.matrix import Matrix
import re
from collections import Counter, defaultdict
import time
import math
from tqdm import tqdm

ans = 0
din = data_in(split=True, numbers=False)

gas = [*din[0]]

rock_patterns = [
    [[1, 1, 1, 1]],
    [[0, 1, 0], [1, 1, 1], [0, 1, 0]],
    [[0, 0, 1], [0, 0, 1], [1, 1, 1]],
    [[1], [1], [1], [1]],
    [[1, 1], [1, 1]]
]


def move_rock(rock, x, y):
    global placed_rocks
    for i in range(len(rock)):
        for j in range(len(rock[0])):
            if rock[i][j] == 1 and placed_rocks[f"{x+j},{y-i}"] == 1:
                return False
    return True


def place_rock(rock, x, y):
    global placed_rocks, highest
    for i in range(len(rock)):
        for j in range(len(rock[0])):
            if rock[i][j] == 1:
                placed_rocks[f"{x+j},{y-i}"] = 1


placed_rocks = defaultdict(int)
for i in range(7):
    placed_rocks[f"{i},{0}"] = 1
highest = 0
j = 0
options = {}

first = 0
start = 0
end = 0
p = []

for i in tqdm(range(10000000)):
    rock = rock_patterns[i % len(rock_patterns)]
    x = 2
    y = highest + 3 + len(rock)
    orig_j = j
    #print("start", x, y)
    while True:
        #print(x, y)
        # Move by jets
        oldx = x
        if gas[j % len(gas)] == '>':
            x += 1
        else:
            x -= 1
        j += 1

        if x + len(rock[0]) > 7:
            x = 7 - len(rock[0])
        elif x < 0:
            x = 0

        if not move_rock(rock, x, y):
            x = oldx

        # Move down
        if not move_rock(rock, x, y-1):
            break
        else:
            y -= 1

    place_rock(rock, x, y)
    highest = max(highest, y)

    #print(i, i % len(rock_patterns), highest, orig_j % len(gas))
    #if i % len(rock_patterns) == 0:
    thing = []

    for a in range(2000):
        temp = []
        for z in range(7):
            temp.append(str(placed_rocks[f"{z},{highest-a}"]))
        thing.append(",".join(temp))

    #thing.append("1,1,1,1,1,1,1")

    #print("|".join(thing) + "." + str(j % len(gas)))
    if "|".join(thing) + "." + str(orig_j % len(gas)) in options:
        index = list(options.keys()).index("|".join(thing) + "." + str(orig_j % len(gas))) + 1
        if first == 0:
            first = index
            end = highest
        #print("FOUND AT ", list(options.keys()).index("|".join(thing) + "." + str(orig_j % len(gas))) + 1)
        if list(options.keys()).index("|".join(thing) + "." + str(orig_j % len(gas))) + 1 == len(options):
            start = p[first-1]
            break

    p.append(highest)
    options["|".join(thing) + "." + str(orig_j % len(gas))] = 1
    #print("Length", len(options))


pattern_length = len(options) - first + 1
pattern_diff = end - start

print("Pattern Length", pattern_length)
print("Pattern Diff", pattern_diff)

limit = 1000000000000
#limit = 1999
ans += (start) + (((limit - first) // (pattern_length)) * (pattern_diff))
print("ANS", ans)
print((limit - first + 1) % (pattern_length))
print(first - 1 + ((limit - first + 1) % (pattern_length)))
ans += p[first - 1 + ((limit - first) % (pattern_length))] - p[first - 1]

print("ANS", ans)
submit(ans)