#AoC 2022 | Day 17 | Solutions & Spoilers

813 messages ยท Page 1 of 1 (latest)

gloomy hedge
#

๐ŸŒจ๏ธ ๐Ÿชจ ๐Ÿชจ

hot mantle
#

hi

tough plaza
#

hi

hot mantle
#

i haven't even ran my code yet

#

i'm just sitting here thinking "how does this work"

tough plaza
#

lol

spiral cedar
#

These elephants need to calm down

left lotus
#

my part 1 works for example input but not actual input

hot mantle
#

i think i got it but i actually don't

tough plaza
#

oh

peak lance
#
                    n_repeats = (1000000000000 - dropped) // d_dropped
                    dropped += n_repeats * d_dropped
                    extra_rows += n_repeats * d_max_y

Accidentally divided by d_max_y so it found way too many cycles

#

Also explains why it didn't work for the test until I changed extra_rows to be += instead of =

#

I wonder why it works better for the test than for the real input though

#

ยฏ_(ใƒ„)_/ยฏ

shrewd herald
#

In the part 2 example, no matter how I cut it, I'm consistently getting that every 15 rocks, the height increases by 23, so apart from an offset, shouldn't the answer be a fixed amount off of 1000000000000/15*23? I'm getting 1,533,333,333,338 when the real answer is 1,514,285,714,288... how am I off by billions and billions?

spiral cedar
#

I got every 35 rocks increase by 53 for the example, which gives 1,514,285,714,263 for 1,000,000,000,000//35*53

brazen fossil
#

OMG I DID IT

#

holy shit

midnight marten
#

what are yall's cycle times

brazen fossil
#

i want to die

midnight marten
#

because for me

#

i got different

#

cycle ranges

#

*change amounts

#

depending on how many

#

rows i went down

brazen fossil
#

i just noticed that every time i looped back to the start of the jets

#

i had the same board loadout & etc

#

so i just simulated 1000000000000 % rocks_per_cycle -> rocks_per_cycle being how many rocks i get through every time i loop back to 0

#

and then added 1000000000000 // rocks_per_cycle * height_per_cycle to the resulting height

eager barn
#

ah p2 was fun
I started by trying to use regex on the differences in height to try to find repetition but then I just moved to using vscode's repetition highlighting

eager barn
blissful bobcat
#

I see you people doing cycle detection in code while I output into a txt file and am did ctrl f

peak lance
#

Lol

midnight marten
#

god

#

finally

#

done

blissful bobcat
#

2634 is my cycle length lul

midnight marten
#

jesus christ

#

so many duplicated code fragments

eager barn
shrewd herald
hot mantle
#

i don't get why mine won't work

#

instead of doing |.####..| |....##.| |....##.| |....#..| |..#.#..| |..#.#..| |#####..| |..###..| |...#...| |..####.| +-------+ it does ```
|####...|
|....##.|
|....##.|
|....#..|
|..#.#..|
|..#.#..|
|#####..|
|..###..|
|...#...|
|..####.|
+-------+

shrewd herald
#

I kinda liked these two lines of my code feature 3 enumerates:

directions = iter(itertools.cycle(enumerate(data)))
for rocknum, (rockstyle, rock) in enumerate(itertools.cycle(enumerate(rocks)), 1):```
I can't decide if that is ugly or elegant, but it worked well for me.
shrewd herald
shrewd herald
# hot mantle this is confusing

The first one it falls from height 2 to 1, so that is clear. Then it sees if the left/right push works, and that is open. Finally, it tries to fall again, but this time something is blocking it, so it comes to a rest.

hot mantle
#

oh it works now

#

nvm something else is happening

#

it's off by 499

brazen fossil
#

rip

#

just add 499 ez

hot mantle
pallid epoch
#

bro

#

i wrote a rotation

#

not a side move

#

reading comprehension moment

atomic cedar
#

not sure if my brain is broken right now, but i can't think of a way to detect a cycle

left lotus
#

I would assume when the wind cycle repeats, but I'm not even done with part 1 so ๐Ÿคท

sullen tiger
sullen tiger
atomic cedar
#

hmm, word, thanks, i'll try that

pallid epoch
#

hi people

#

i

#

i've manually checked that my code is correct for all of the sample

#

but it continues to fail

pallid epoch
#

does anyone want to find the very easy bug

#

that i probably missed due to sleep deprive

#

(the result is half the expected)

wild rainBOT
#

Hey @fading sinew!

You either uploaded a .txt file or entered a message that was too long. Please use our paste bin instead.

pallid epoch
#

the paste bin says my log file is too long

wild rainBOT
#

Hey @pallid epoch!

You either uploaded a .txt file or entered a message that was too long. Please use our paste bin instead.

pallid epoch
#

brhu

#

its only 14 mb

fading sinew
pallid epoch
#

404 not found

silver light
#

exactly

#

haha

fading sinew
#

wtf

silver light
#

that's what mine looks like too...

fading sinew
#

The entire page freezes when I save

#

idk why

pallid epoch
silver light
#

How big are you pasting? Is there a limit?

pallid epoch
#

i mean when i try to paste the log of all the starting block positions

fading sinew
#

works now

pallid epoch
#

its like 18 million lines or so idk

pallid epoch
fading sinew
pallid epoch
#

i meant my log file

fading sinew
#

what are y'all runtimes?

pallid epoch
#

0.4s

#

for p1

#

(incorrect solution lol)

fading sinew
#

340 ms for 10**4299
170 ms for the actual solution both parts

left lotus
#

Finally done with part 1

pallid epoch
#

what was the issue, out of curiosity

left lotus
#

I was replacing existing rock with air

#

I forgot you could slide rocks underneath other rocks

#

Smh haven't played tetirs for too long

fading sinew
#

Elephant + 1000000000000 rocks = A heck of a lot of dead elephants ๐Ÿ’€

left lotus
fading sinew
pallid epoch
#

ok i found the error

#

the rocks were realizing they had common cause and revolting

toxic geyser
#

This was fun. I anticipated part two, spend way too much time on part one, and then had part two almost immediately.

fading sinew
#

Question:

why is
x=None
if x is None

like a billion times faster than

why is
x=1
if x is 1

toxic geyser
#

Is it that much faster?

#

!e
Ignoring the syntax warning:

import timeit


def check_none():
    a = None
    if a is None:
        return 2
    else:
        return 3


def check_one():
    a = 1
    if a is 1:
        return 2
    else:
        return 3


print(timeit.timeit(check_none))
print(timeit.timeit(check_one))
wild rainBOT
#

@toxic geyser :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | <string>:14: SyntaxWarning: "is" with a literal. Did you mean "=="?
002 | 0.08325721399160102
003 | 0.08740069600753486
silver light
#

They are the same when I test that too.

pallid epoch
#

maybe some impl about doing an actual identity check on 1

hot mantle
#

so 5 hours after this puzzle released i still don't know why my code is failing

#

no overlappings are occuring anymore

#

nvm i found the problem

fading sinew
#

fucking weird

hot mantle
#

oof

#

i got really really close

sullen tiger
hot mantle
#

ok now it returns 3127

#

with a bunch of overlappings

fading sinew
hot mantle
#

it's 3068

fading sinew
fading sinew
hot mantle
#

5 lines to be uncommented for visual debugging and 3 lines are currently uncommented to see if overlaps occured

fading sinew
fading sinew
#

and rch

hot mantle
# fading sinew wherre are the lch & fall fncs?
def fall(m,mx,my,x,y):
 if y==0:return 0
 for n in range(my):
  ty=n-1
  for i in range(mx):
   if m[n,i] and (n==0 or not m[n-1,i]) and arr[y+ty,i+x]:return 0
 return 1

def lch(m,my,x,y):
 if x==0:return 0
 x-=1
 for n in range(my):
  if m[n,0]and arr[y+n,x]:return 0
 return 1

def rch(m,mx,my,x,y):
 if (x:=x+mx)==7:return 0
 for n in range(my):
  if m[n,-1]and arr[y+n,x]:return 0
 return 1
fading sinew
#

what is the length of y'all's inputs?

#

it's 10091 characters for me

sullen tiger
fading sinew
sullen tiger
#

Ah right, I included the \n sorry.

#

Yeah, mine is 10091.

fading sinew
#

thanks, golfing rn lol

hot mantle
#

3127 was the right answer to my input in part 1

#

the wrong answer to the example input was the right answer to my input

fading sinew
#

sucks to be you, i guess ๐Ÿ˜ญ

hot mantle
#

what are the chances of this

#

i'm unluckily lucky

fading sinew
left lotus
#

finally

#

now I have to figure out why I am off by 21 on both parts for some reason

hot mantle
left lotus
#

probably by chance I would imagine

left lotus
fading sinew
left lotus
#

fine

fluid siren
fading sinew
fluid siren
#

i blame pycharm

#

i selected the console and then when i cmd c it highlights the code itself

#

for some odd reason

fading sinew
#

atleast for smaller codes. Pycharm over sublime for projects

fluid siren
#

is cycle detection with just the top five rows fine or do i need more rows

left lotus
#

5 probably isn't enough

#

or use the ||highest rocks in each column||

fluid siren
#

isn't that basically the same as using 5 tho

#

oh actually not ig

fluid siren
#

i think i might have a slight error in my code

peak lance
#

LMAO what on earth did you do

fluid siren
#
import antigravity
fluid siren
#

does a cycle always have to cycle back to the start here?

peak lance
#

No

fluid siren
#

right

#

that's annoying

peak lance
#

DW I made that wrong assumption too lol

fluid siren
#

hmm

peak lance
#

Actually you could probably make it work like that

fluid siren
#

i've managed to detect a cycle

peak lance
#

Might be shorter for the golf as well

fluid siren
#

it's just that idk where it starts

#

or how long it is

peak lance
#

You know there is one but not where or what ๐Ÿคฃ

#

Good enough for mathematics ๐Ÿ™ƒ

fluid siren
#

well

#

if i knew it cycled at the start i could just divide stuff by two

#

but i know it doesn't

#

so there's an offset

#

which is super annoying

#

actually no i can't even do that

#

bruh

livid nexus
#

Completely hacked together my solution for today with cycles using just my height after each rock. Time to get back to yesterday's problem

frank scaffold
#

i still don't know how my part2 solution works tbh

#

I thought the cycle length must just be lcm(len(movements), 5)

peak lance
frank scaffold
#

but no, it's weirdly different; I ended up just writing a search checking different cycle lengths. for my real input, the lcm was ~50k and the actual cycle length was ~40k

livid nexus
peak lance
fluid siren
#

are you guys like shifting the board down or anything

livid nexus
#

Going to slightly clean up my code then I'll share it

peak lance
#

Does your input end on a piece lock-in?

#

That's the only way I see that approach working

peak lance
livid nexus
#

What do you mean by piece lock-in?

peak lance
#

I just gave my program 5k rows to drop in lol

peak lance
frank scaffold
#

10k for me ๐Ÿฅด

#

except for pt2 I had to do ~200k rows

peak lance
#

For part 2 I switched to a defaultdict lol

livid nexus
#

Not sure what you mean, every piece locks in then?

peak lance
#

(technically I used aoc_helper.SparseGrid but I didn't actually use any of its methods lol)

fluid siren
#

hmm

peak lance
#

E.g. <><>

livid nexus
#

I think you might misunderstand what I'm doing. Will share code in a moment

peak lance
#

<>< locks in the first piece, then > moves a second piece without locking it in

fluid siren
#

some people said that their data cycled after just one cycle of the moves

#

so

#

hmm

#

so if i know i have a cycle

#

then i can use the turtle bunny algorithm thing

#

to find the cycle length

#

i think

livid nexus
#

Here's my hacked together solution. I'm hoping it'll work with any input and I wasn't just lucky with my input.

def part_two():
    rock_count = 10000
    cave_height = rock_count // 5 * 13
    cave = np.full((cave_height, 7), 0)
    height = 0
    heights = []
    idx = 0

    for i in range(rock_count):
        rock = rocks[i % 5]
        y = cave_height - height - rock.shape[0] - 3
        x = 2
        while (
            np.all(cave[y : y + rock.shape[0], x : x + rock.shape[1]] + rock <= 1)
            and y < cave_height
        ):
            match gas[idx]:
                case "<":
                    x = max(0, x - 1)
                    if np.any(
                        cave[y : y + rock.shape[0], x : x + rock.shape[1]] + rock > 1
                    ):
                        x += 1
                case ">":
                    x = min(7 - rock.shape[1], x + 1)
                    if np.any(
                        cave[y : y + rock.shape[0], x : x + rock.shape[1]] + rock > 1
                    ):
                        x -= 1
            idx = (idx + 1) % len(gas)
            y += 1
        y -= 1

        height = max(height, (cave_height - y))
        heights.append(height)
        cave[y : y + rock.shape[0], x : x + rock.shape[1]] += rock

    n = 1
    repeat = 0
    repeat_value = 0
    for i in range(1, 2000):
        if (
            heights[(n + 1) * i] - heights[(n) * i]
            == heights[(n + 2) * i] - heights[(n + 1) * i]
            == heights[(n + 3) * i] - heights[(n + 2) * i]
        ):
            repeat = i
            repeat_value = heights[(n + 1) * i] - heights[(n) * i]
            break

    offset = 1000000000000 % repeat
    return 1000000000000 // repeat * repeat_value + heights[offset - 1]
fluid siren
#

wait this isn't a function

#

nvm

#

i'm so confused

shrewd herald
fluid siren
#

right as i manage to figure it out for the test data

#

i try to use the real data

#

and i get 54

#

wtf

#

how does it work so nicely for the example

#

and then break so horribly in the actual data

slow belfry
fluid siren
#

no t spins sadly

slow belfry
#

no t sadly

#

finally restarted discord, now i get to complain about this font

midnight marten
#

does it like print things so fast

#

it seems like it's animating

slow belfry
midnight marten
#

how do you move the cursor?

slow belfry
#

with ansi escapes

midnight marten
#

these things?

slow belfry
#

yep

plain gyro
#

having a bit of trouble shifting the @

#

->

small current
peak lance
#

Yes

#

print('\x1b[4Ayourtexthere') will do it I believe

small current
#

i alwys thought cursor location can only be changed in the last line printed ๐Ÿ’€

peak lance
#

Won't work in conhost (CMD) or idle though

delicate marten
#

conhost doesn't deserve to exist

#

so that's okay

small current
#

whats conhost

peak lance
#

The terminal used if you run command prompt in Windows

#

It's not very good

small current
#

oh

peak lance
#

Use Windows Terminal

small current
#

powershell?

peak lance
#

Powershell would work I think

#

Not actually sure

small current
#

i dont know the difference between command prompt and terminal tbh

#

when i enter terminal it only shows me the cmd.exe

peak lance
#

Windows Terminal is ANSI-compliant though

peak lance
delicate marten
#

cmd is a shell, winterm is a good terminal emulator. when you open cmd.exe, however, it defaults to conhost, a really bad emulator.

peak lance
#

To conhost's credit it's more lightweight than Terminal

#

If I want to do something quick and dirty conhost is usually good enough

small current
#

but it will erase the lines below it

peak lance
#

...no?

#

Only if you print over them

#

You can use D (I think) to go back down

small current
#

need to print over the existing one i thought

peak lance
#

Yes but it doesn't erase the other lines unless you print over those too

#

FYI if you want to do cursor position stuff I've always used colorama

#

Includes a conhost compatibility thing too

small current
#

it does for me somehow

peak lance
#

Might be your shell, try printing 10 newlines

#
for i in range(20):
    print("Hello world",i)
print("\x1b[15Aasdfasfasdfasd")
print('\n' * 10)

If that doesn't work then I don't know

#

It should work

#

!e I'm curious, does it work in the bot?

for i in range(20):
    print("Hello world",i)
print("\x1b[15Aasdfasfasdfasd")
print('\n' * 10)
wild rainBOT
#

@peak lance :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | Hello world 0
002 | Hello world 1
003 | Hello world 2
004 | Hello world 3
005 | Hello world 4
006 | Hello world 5
007 | Hello world 6
008 | Hello world 7
009 | Hello world 8
010 | Hello world 9
011 | Hello world 10
... (truncated - too many lines)

Full output: https://paste.pythondiscord.com/orokuvapih.txt?noredirect

peak lance
#
Hello world 0
Hello world 1
Hello world 2
Hello world 3
Hello world 4
Hello world 5
Hello world 6
Hello world 7
Hello world 8
Hello world 9
Hello world 10
Hello world 11
Hello world 12
Hello world 13
Hello world 14
Hello world 15
Hello world 16
Hello world 17
Hello world 18
Hello world 19
15Aasdfasfasdfasd
#

I don't know if that got corrupted or just didn't work lol

#

Ok no it just didn't work

#

Wait ANSI doesn't render properly on mobile at all lol

keen frigate
#

i was so braindead

atomic cedar
#

haha

slow belfry
#

i've been going to bed super early last few days, i'm not willing to give up more sleep for aoc

blissful phoenix
#

I was doing that for most days and today I just fell asleep in my chair in the middle of AoC at midnight.

#

Probably a good thing I did though. I've been stuck in cycle detection for P2 for god knows how long now. It's right on the test input but wrong on my actual input. Only guess I have is it might have to do with overhangs. I'm looking for same piece type, same heights of each column, and same index on the jet pattern. If anyone has any ideas, I'm all ears at this point
https://paste.pythondiscord.com/cirubifume

pallid epoch
#

finally found why my p1 is wrong

#

at some step the list just starts eating itself and i have no idea why

#

looks like a standard memory corruption but this shouldnโ€™t happen in python?

#

like it seems like the list pointer is getting overwritten

brazen fossil
#

(might just be my own input but it might work for you idk)

keen frigate
#

i also have a shuttle and flight to catch early tomorrow morning, so it's time to drop down the leaderboard tonight ๐Ÿ˜Ž

peak lance
#

Rip

plain gyro
#

i have this function that is supposed to shift the falling rock. it works fine for left and right, but gets kinda weird when moving down :/

def shift_block(grid:list[str], dir: tuple[int,int]):

    dx, dy = dir
    positions = []
    for i in range(len(grid)):
        for j in range(len(grid[0])):
            if grid[i][j] == '@':
                positions.append((i, j))


    step = 1 if dx < 0 else -1
    for i, j in positions[::step]:
        grid[i+dy][j+dx] = '@'
        grid[i][j] = '.'
plain gyro
#

while rebuilding the shifted block this happens, and i have no idea why

midnight marten
#

did you try using a debugger or anything of the sort

plain gyro
#

my debugger doesnt work for some reason, was trying to figure that out as well :|

midnight marten
#

bro i'm so sorry

plain gyro
#

np

#

thx tho

midnight marten
#

can i see the arguments

#

you're passing in?

#

also what's step?

plain gyro
#

the step was to figure out in which order to remove and add the part of the blocks, but it only relevant if its an horizontal move

midnight marten
#

so in this case it's 1?

plain gyro
#

yeah

#

def shift_block(grid:list[str], dir: tuple[int,int]):
  

    dx, dy = dir
    positions = []
    for y in range(len(grid)):
        for x in range(len(grid[0])):
            if grid[y][x] == '@':
                positions.append((x, y))


    new_positions = [(x, y+1) for x, y in positions]
    
    for x, y in positions: # remove block
        grid[y][x] = '.'
    
    for x, y in new_positions: # build shifted block
        grid[y][x] = '@'

...
shift_block(grid, (0,1))    
...
midnight marten
#

and dir is what

#

oh 0, 1

#

alright

plain gyro
# plain gyro

this is what really blows my mind, how does this happen in one instruction grid[y][x] = '@'

#

it just added three @ out of nowhere

#

the length of the new_positions is 5, yet it places 7 @

#

how is that possible

midnight marten
#
def shift_block(grid: list[str], dir: tuple[int,int]):
    dx, dy = dir
    positions = []
    for y in range(len(grid)):
        for x in range(len(grid[0])):
            if grid[y][x] == '@':
                positions.append((x, y))


    new_positions = [(x, y+1) for x, y in positions]
    
    for x, y in positions: # remove block
        grid[y][x] = '.'
    
    for x, y in new_positions: # build shifted block
        grid[y][x] = '@'


grid = [
    list('...@...'),
    list('..@@@..'),
    list('...@...'),
    list('.......'),
    list('.......'),
    list('.......')
]

shift_block(grid, (0, 1))

for i in grid:
    print(''.join(i))
#

this seems to work fine for me?

plain gyro
#

what

midnight marten
#

uh

#

what's your grid look like

plain gyro
#

[['.', '.', '.', '@', '.', '.', '.'], ['.', '.', '@', '@', '@', '.', '.'], ['.', '.', '.', '@', '.', '.', '.'], ['.', '.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.', '.']]

#

wait a sec

#

['.', '.', '.', '@', '.', '.', '.']
['.', '.', '@', '@', '@', '.', '.']
['.', '.', '.', '@', '.', '.', '.']
['.', '.', '.', '.', '.', '.', '.']
['.', '.', '.', '.', '.', '.', '.']
['.', '.', '.', '.', '.', '.', '.']

midnight marten
#

that's your current thing?

#

what kinda piece is that lol

plain gyro
#

thing?

midnight marten
#

the grid you're testing w/

plain gyro
#

im so confused

midnight marten
#

yeah same for me

#

wait try running the code i posted

plain gyro
#

yeah it works

#

idk why it doesnt work on mine

midnight marten
#

remove the shift_block

#

just wanna make sure it's due to the shift_block and not bc of anything else

plain gyro
midnight marten
#

try printing out new_positions?

plain gyro
#

[(3, 1), (2, 2), (3, 2), (4, 2), (3, 3)]

#

which is right

midnight marten
#

try printing the grid after the loop with grid[y][x] = '.'

plain gyro
midnight marten
#

and after the

    for x, y in new_positions: # build shifted block
        grid[y][x] = '@'
```it's weird?
plain gyro
#

yeah

#

it does that in the last iteration

#

adds 3 @

midnight marten
#

print out y, x in each iteration

plain gyro
midnight marten
#

(gonna be honest i'm just throwing darts here, i've no clue what's wrong either)

plain gyro
#

yeah ive been like that for like two hours

midnight marten
#

and print out the grid after each individual iteration

plain gyro
#
1 3
-------
.......
...@...
.......
.......
.......
.......
2 2
-------
.......
...@...
..@....
.......
.......
.......
2 3
-------
.......
...@...
..@@...
.......
.......
.......
2 4
-------
.......
...@...
..@@@..
.......
.......
.......
3 3
-------
.......
...@...
..@@@..
...@...
...@...
...@...
-------
#

how??

midnight marten
#

what????

plain gyro
midnight marten
#

surprised pikachu face:

plain gyro
#

same

midnight marten
#

ok uh

#

just try setting

#

grid[3][3] = '@'

#

see what that does

#

OH WAIT

#

I THINK I KNOW

#

the last two elements

#

they're linked to the index 3 row

plain gyro
#

what the actual f-

midnight marten
#

like yknow how

x = [0, 1, 2, 3]
y = x
x[0] = 1234
print(y)  # [1234, 1, 2, 3]
plain gyro
midnight marten
#

i think that's the bug

plain gyro
#

i didnt get it

midnight marten
#

something similar to that is happening in your grid

#

because y didn't copy x
it's a reference to x

#

so if you change x, y will change along w/ it

plain gyro
#

but where is the bug

midnight marten
#

that's the bug

#

each row isn't independent

#

you might've screwed up grid initialization

plain gyro
#

okay, ill look into it, thanks a lot ^^

#

so the bugs here ๐Ÿง

def insert_rock(rock, grid, width):
   
    for i, line in enumerate(rock):
        grid.insert(i, ['.'] * 2 + list(line) + ["."] * (width - len(line) - 2))
    
    # resize_grid(grid, rock)
    rock_height = len(rock)
    space_between = ['.'] * width

    for _ in range(3):
        grid.insert(rock_height,space_between)

    return grid
midnight marten
#

maybe?

plain gyro
#

oh

#

i see it

#
space_between = ['.'] * width

    for _ in range(3):
        grid.insert(rock_height,space_between)
#

the space between is the same in the last 3 rows

midnight marten
#

yes

#

so space_between.copy() instead

plain gyro
#

god id never find this alone

#

tysm

midnight marten
#

np!

plain gyro
#

3 characters solved the problem...

#

ugh

warm zealot
#

This is driving me round the bend

#

For part 2, I've got a solution that works perfectly for the test case, agrees for every rock num I could be bothered to simulate, and yet doesn't give the correct answer for the main thing

quick meteor
#

I managed to complete part 1 with straightforward method which take roughly 20 seconds to execute. I see there is a repeating pattern on rock agencement but I'm too lazy to code this out...

lucid gulch
#

test case works perfectly fine up to the point that i can track, but completely off on the result

#
def play(inputs, count):
    types = [[(0, 0), (1, 0), (2, 0), (3, 0)],
             [(1, 0), (0, 1), (1, 1), (2, 1), (1, 2)],
             [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)],
             [(0, 0), (0, 1), (0, 2), (0, 3)],
             [(0, 0), (1, 0), (0, 1), (1, 1)]]

    field = []
    bottom = -1
    i = 0

    for r in range(count):
        while len(field) < bottom+8: # field padding for next rock
            field.append(['.']*7)

        rock = types[r % 5]
        x, y = 2, bottom+4
        dropped = False

        while not dropped:
            m = '< >'.index(inputs[i])-1
            # left/right
            if all(0 <= x+a+m < 7 and field[y+b][x+a+m] == '.'
                   for a, b in rock):
                x = x+m
            i = (i+1) % len(inputs)
            # down
            if y > 0 and all(field[y+b-1][x+a] == '.' for a, b in rock):
                y -= 1
            else: # block done
                for a, b in rock:
                    field[y+b][x+a] = '#'
                dropped = True
                bottom = max(y + b for _, b in rock)

    while field[-1] == ['.']*7: # cut off empty rows
        field.pop()
    return field


print(len(play('>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>', 2022)))``` any help appreciated, like I said, seems to emulate the test case perfectly fine but the endresult is off by a massive 500
lilac torrent
#

1'000'000'000'000

#

that's a lot of fckin rocks

#

it takes me a bit less than a second to process 100'000 rocks

#

looks like I have the wrong approach here

lucid gulch
#

possibly pattern repetition?

lilac torrent
#

maybe

lucid gulch
#

probably after len(input) * 5

lilac torrent
#

there's a few leads to improve perf further but the order of magnitude isn't good enough

lucid gulch
#

which should only be 50k

lilac torrent
#

you've done part 2 already ?

lucid gulch
#

no i'm still failing the test case lmao

#

but after len(input)*5 you should start a new cycle since that's where input index 0 and rock index 0 will overlap again

#

just have to be careful about how the cycles connect

#

well that's my guess anyways

lilac torrent
#

you're right for the example

#

welp I won't finish yesterday's puzzle tonight after all ๐Ÿ˜ข

lucid gulch
#

yea i'm also 2 behind now since i'll have to go to bed

lilac torrent
#

rip

#

oh

#

but

#

you actually don't have to handle the cycle connection do you

#

you can do 2 full circles and match the second with all of the other

lucid gulch
#

yea that works as well

#

@hot mantle what was your off by 500 error, I might be stuck at the same problem

hot mantle
#

โ€ซthe final revision of the code i wrote was off by 59

lucid gulch
hot mantle
#

oh that

hot mantle
lucid gulch
#

so it went down where it shouldn't?

hot mantle
lucid gulch
#

hmmm

#

a specific case by chance? can't see anything wrong with my logic

lucid gulch
#

ahhh so it doesn't eat inputs if it won't move

#

ok thank you! that will hopefully be it

#

maybe not hmm

lucid gulch
hot mantle
#

oh wait i found the problem with my latest revision

#

sort of

lucid gulch
#

congratz T.T

hot mantle
#

oh i got pretty close

#

14 off

#

68 off on actual input

#

anyways here's a visualization

jovial siren
#

i don't get the issue with my solution

#

welp

#

might be screwed today

#

i changed like nothing and now it works

#

that's pretty cool

fluid siren
#

welp

#

that was a pain to debug

#

but i finally got it

hard totem
#

wait what. today was pretty simple. if i had started earlier i would have earned points. ๐Ÿ˜ณ

tough plaza
#

๐Ÿ˜ณ

hard totem
#

place 100 for part 2 is 40:48

#

that's lots of time.

#

not exactly sure when i started. Think

small current
#

is todays second part another one of those

#

where a bad implementation iin part 1

#

leads to absurd amount of time necessary for computation?

hard totem
#

i don't think so.

#

i think part 2 should be easy independent of the specific part 1 implementation. lemon_thinking

#

okay, i just checked. apparently i spent about 45 minutes on part 1. ๐Ÿ˜…

#

lots of small errors here and there.

keen frigate
#

my part 2 was part 1 but extended

#

with cycle detection

#

but than that the code was basically the same

fluid siren
#

I rewrote my entire code for part 2

keen frigate
#

oh really? mine was adding a few variables and if statements here and there and it worked out

#

also i did some funny cursed shit with my Rock class

#

class Rock(namedtuple("Rock", "shape left_x bottom_y")):

    def __lshift__(self, value):
        return Rock(self.shape, self.left_x - value, self.bottom_y)

    def __rshift__(self, value):
        return Rock(self.shape, self.left_x + value, self.bottom_y)

    def __sub__(self, value):
        return Rock(self.shape, self.left_x, self.bottom_y - value)

    def __add__(self, value):
        return Rock(self.shape, self.left_x, self.bottom_y + value)

    @property
    def positions(self):
        return [
            (self.left_x + dx, self.bottom_y + dy)
            for dy, row in enumerate(self.shape)
            for dx, filled in enumerate(row)
            if filled
        ]

    def validate_move(self, grid):
        return all(0 <= pos[0] < 7 and pos[1] >= 0 and pos not in grid for pos in self.positions)
#

so then i could do

match jet:
    case ">": rock >>= 1
    case "<": rock <<= 1

rock -= 1
fluid siren
#

I had a really bad hashing method for the board state

#

so I just changed my board to a 200k tall numpy array

keen frigate
#

same

#

oh ๐Ÿ’€

#

i just hashed the previous 10 rows

fluid siren
#

I tried that

#

well I tried 25

#

wasn't enough

keen frigate
#

huh really? interesting

fluid siren
#

an I piece slid down like 40 rows in my input

keen frigate
#

oh i saved state for the entire grid in a set

#

that contained positions that were filled

#

and then hashed the last 10 rows

#

if i'm understanding what you're saying

fluid siren
#

yeah

#

I had to hash the last 50 rows

#

last 25 rows wasn't enough

#

because the I piece would fall down 40 rows and I'd get a cycle of length 1

keen frigate
#

oh i see

#

the four down piece

#

gotcha gotcha

brazen fossil
#

trust

hot mantle
keen frigate
keen frigate
brazen fossil
#

wtf does |- do

keen frigate
#

1 | -(jet < '>')

#

does that clear it up

brazen fossil
#

ah

#

i thought it was like that

#

also forgot that 1 | -1 = 1

#

oops

fluid siren
midnight marten
#

honestly today was kinda sus

#

because it relied on an i piece

#

not falling all the way to the bottom

#

unless someone can prove

#

that there's an upper bound on the maximum number of spots

#

a piece can fall down

fluid siren
#

I think someone on reddit said something about keeping track of the maximum number of drops of a piece

#

also all my days are kinda sus

#

well not all

#

a lot of my days

brazen fossil
#

honestly i'm still not really sure how to not "cheese" today's solution

#

not sure what to actually detect cycles in

tough plaza
#

i should think before posting, i forgot the thing was 7 wide

fluid siren
#

I mean you thought for quite a while before that already

tough plaza
#

i should think more

#

because my brain is slow

brazen fossil
#

shade

#

brain smooth head empty ๐Ÿ˜”

tough plaza
#

i am bad at aoc, unfortunately

fluid siren
#

you're like 3 digit ranked

#

wdym

tough plaza
#

so what

brazen fossil
#

3 digit ranked wym

tough plaza
#

pretty much everyone here is 2 or 3 digit

fluid siren
brazen fossil
#

pydis lb or aoc lb

fluid siren
#

actual

tough plaza
#

i can semi-consistently hit 3 digits for problems

brazen fossil
#

sub 1k generally isn't hard

tough plaza
#

but that doesn't mean much

brazen fossil
#

sub 100 though ๐Ÿ˜”

tough plaza
#

yeah exactly

#

i've never gotten into 2 digits

brazen fossil
#

it's not hard to get sub 1k if you start when it releases

tough plaza
#

^

fluid siren
#

from my perspective you guys are like really good at aoc

tough plaza
#

this is my first year, i'm pretty inexperienced

fluid siren
#

I've been taking like 6 hours to solve these last few days

brazen fossil
#

my second year after not doing it in 2021 ๐Ÿคทโ€โ™‚๏ธ

#

just remember this isn't like usaco

tough plaza
#

ye lol

brazen fossil
#

and the solution is what counts - not how you did it

tough plaza
#

sometimes i just waste 10 mins trying to optimize

#

only to realize that i can't

#

and it really was braindead simulation

brazen fossil
#

i.e. my today's solution looked like this

fluid siren
#

did you not need to simulate after all the cycles?

brazen fossil
#

wym

fluid siren
#

like

tough plaza
# brazen fossil i.e. my today's solution looked like this
C=D=E=a=0;Z=x=1j
K=input()
F,G={0},{}
L=lambda x:all([(p:=B+x+A).imag>0<=p.real<7,0][p in F]for A in I)
while 1:
 A=max(A.imag for A in F);Z=B=2+4j+A*x;I=((0,1,x,1+x),range(4),(1,x,2+x,1+2j),(0,1,2,2+x,2+2j),(0,x,2j,3j))[C:=-~C%5];E==2022>(a:=A)
 if(C,D)in G:N,O=G[C,D];P,Q=divmod(1e12-E,N-E);Q>=0<a>print(a,A+(O-A)*P)
 while Z:G[C,D]=E,A;B+=L(M:=ord(K[D])-61)*M;Z=L(-x);B-=x*Z;D=-~D%10091
 F|={B+A for A in I};E+=1```
brazen fossil
#

๐Ÿ’€

fluid siren
#

I had
(height before first cycle) + (cycle length)*(number of cycles) + (height of remaining partial cycle)

#

do you not need the remaining partial cycle?

brazen fossil
#

i basically noticed that every time jet loops around, a constant height is added, ergo that previous cycles don't matter

#

so i just simulated how much i needed to simulate (like 1000000000000 % rocks_per_cycle idk) how many rocks

#

and just added the height i get per cycle

#

very fun

#

hacky solution

tough plaza
#

i did every 5 times the jet looped

brazen fossil
#

wym

tough plaza
#

because the rocks could've been different

#

resulting in different heights

brazen fossil
#

it isn't-i made sure to check

tough plaza
#

and i didn't

#

which is why i did 5 times

brazen fossil
#

lmao

fluid siren
#

huh

#

did you guys not do any state storing

brazen fossil
#

wym

fluid siren
#

like

#

store the state of the last 40 lines

#

and then see if it's existed already

brazen fossil
#

if you wanted code that works for any input you probably should do that

fluid siren
#

wait

#

so your input cycled every single time the moves got to the end?

brazen fossil
#

i think everyone's did

#

every time jet looped back to 0

#

it was the same

fluid siren
#

huh

#

I thought I checked that yesterday

brazen fossil
#

๐Ÿคทโ€โ™‚๏ธ

midnight marten
#

who the heck pinged

lucid gulch
lucid gulch
#

my brain is toast

#

pattern search works for test but not for input

lucid gulch
#

am I right in the assumption that patterns only happen on a cycle basis i.e. len(input)*len(rock_shapes)?

plain gyro
#

my solution for p1 takes a couple minutes, pretty sure it would be an eternity to use it for part 2...

#

i have no idea how to optimize it

fluid siren
#

why does it take a couple minutes for your p1?

plain gyro
#

cause its not a very efficient solution, but its what i could get

wild rainBOT
#

Hey @plain gyro!

You either uploaded a .txt file or entered a message that was too long. Please use our paste bin instead.

plain gyro
#

because i was using deepcopy and it is very slow

#

but still, its not good enough

fluid siren
#

try profiling to find the bad bits

plain gyro
#

ill try, but i dont think it will be enough

#

at least enough for 3 trillion rocks

fluid siren
#

you aren't meant to brute force 3 trillion rocks

plain gyro
#

so i should approach the problem in a smarter way?

#

and not place and move every rock?

fluid siren
#

no

#

find a way to reduce the number of rocks you need to place by taking advantage of repeating stuff

plain gyro
#

i see

#

so theres a pattern

lilac torrent
#

I'm loosing my mind over part 2

past karma
#

Part 2 was weird for me in that I found it conceptually easy but really irritating to code

lilac torrent
#

I'm stuck trying to figure out the mathematical way

#

and I suck at math

past karma
#

mathematical as in trying to find the height per repeating group of rocks?

lilac torrent
#

here's where I'm at

#

heigh grow as a repetitive sequence

#

for the example, the sequences are 7 cycles long, the first 2 are useless, and then it repeats every 35 cycles, which is 5 sequeences of 7 cycles

#

one cycle being one rock

#

and rn I'm trying to figure out where those magic numbers come from

lucid gulch
#

my pattern recognition works for the test case but doesn't produce anything on input

#

sad stuff

past karma
lilac torrent
#

by looking at the datas

#

generating for n cycles and studying the output

past karma
#

right

#

so what you need to do is programatically derive the 35 cycle number

#

and I agree, it's much more annoying to do programmatically than just looking at the output

lilac torrent
#

but it's not always 35 isn't it ?

past karma
#

well no

#

it won't be for your real output

#

it's much larger

lilac torrent
#

what I'm thinking of

#

it looks like the number of flow mov / the numbers of shapes

#

that's what I'm working out rn

lucid gulch
#

@past karma is it related to len(input)*5 ?

#

thought that should obviously be it but so far only produced results for the test for me

past karma
lucid gulch
#

well my thought was that obviously things should repeat an some multiple of len(input)*5 because thats where both stones and the input will repeat, starting a new cycle

#

which works for the test case

#

but i've realized the problem with that logic, still thought it might be related nonetheless

past karma
#

oh right. yeah that was my initial thought as well

#

seems not to be the case

#

but there is a repeating group

lucid gulch
#

so just brute force pattern recognition?

lilac torrent
#

there's repeating groups before nb_flow * nb_shapes

past karma
lucid gulch
#

alright, i'm gonna do it as well then

past karma
#

if you do it as dumbly as I did then it takes 2 mins to run

lucid gulch
#

i kinda don't wanna mess with my play algorithm but doing it afterwards requires knowledge of how long to run

lilac torrent
#

@past karma so people have been doing pattern recognition ?

past karma
lilac torrent
#

I was ooking for a pure mathematical solution this whole time

lucid gulch
#
      if find_pattern:
            if pattern is None:
                for k in range(highest-49):
                    if grid[highest-49:highest+1] == grid[k:k+50]:
                        pattern = grid[k:k+50]
                        print(f'repeat at r: {r} height: {highest} against {k+50}')
            else:
                if grid[k:k+50] == pattern:
                    print(f'repeat at r: {r} height: {highest} against {k+50}')```
#

i get one immediate result but can't find anthing after that

past karma
#

not sure I follow what you did there, but I did a very dumb way of doing it

lucid gulch
#

i'm checking if the highest 50 lines can be found somewhere else in the grid, if so try to find it again after doing some more cycles so i know the pattern length

#

but trying to find it again doesn't produce anything

past karma
#

all I did was, after each rock fall, try and see if the grid could be split in 2 and have two halves exactly the same - but do that a number of times whilst progressively removing the bottom rows from the grid

lilac torrent
#

you're a genius

past karma
#

yeah well my genius solution takes two minutes to run lol

#
    def check_for_repeating_groups(self, group_no):
        for start, _ in enumerate(self._rocks_positional):
            sublist = self._rocks_positional[start:]
            if len(sublist) < 10:
                # we are looking for large repeating groups
                # use as quick and dirty way of ditching tiny repeating groups
                return False, None, None
            if len(sublist) % group_no != 0:
                # looking for exact repeating groups so need a sublist divisible into equal parts
                continue
            groups = more_itertools.divide(group_no, sublist)
            groups = iter(groups)
            first = list(next(groups))
            if all(first == list(x) for x in groups):
                # found
                group_len = len(first)
                offset_len = len(self._rocks_positional) - group_len * group_no
                return True, group_len, offset_len
        return False, None, None

"rocks_positional" is a list[set[int]] where each set represents a row in the chamber, and each int in a set is the horizontal position of a rock in that row

#

I actually check to see if the grid can be split in 2, then again in 3 to work out the number of rocks for a repeating group

lilac torrent
#

good lord finally

#

@past karma thanks for the hint

past karma
#

no problem! what was the solution runtime?

lilac torrent
#

the solution runtime ?

#

time wise ?

past karma
#

yh

lilac torrent
#

eh

#

I'd need to work on my benchmark function

small current
#

0ms

#

so fast

#

:-O

lilac torrent
#

well even in micro second it's not showing

#

oh wait I'm an idiot

past karma
#

pretty quick!

#

much quicker than mine lol

lilac torrent
#

I figured something : if you take the diff (between current and last elevation), the current flow, and the current shape

#

you could use that as an id to match when the first repeating line was happening

past karma
#

sounds like a good optimisation :)

lilac torrent
#

just took me 2 days lol

#

and there's still a magic number : at one place I had to add a "-1)

#

but it's working I'll never modify it again

#
long long part2(std::vector<Shape> const& shapes, std::string const& gas_flow)
{
    Tetris tetris(shapes, gas_flow);

    std::vector<long long> cumulated;
    std::unordered_map<RockInfos, long long, DfHash> rock_last_index;

    int time_to_stabilize = 14;
    int repeat_pattern_size = 35;

    int i = 0;
    while (true)
    {
        tetris.tick();
        cumulated.push_back(tetris.max_y);

        RockInfos rock{
            tetris.max_y - cumulated.back(),
            std::distance(tetris.gas_flow.begin(), tetris.current_flow_it),
            std::distance(tetris.shapes.begin(), tetris.current_shape_it)
        };

        auto [l_it, l_inserted] = rock_last_index.insert({ rock, i});
        if (!l_inserted)
        {
            repeat_pattern_size = i - l_it->second;
            time_to_stabilize = l_it->second - 1;
            break;
        }

        i++;
    }

    long long target    = 1'000'000'000'000;
    long long repeat    = target / repeat_pattern_size;
    long long remaining = target % repeat_pattern_size - time_to_stabilize;
    long long result    = cumulated[time_to_stabilize] 
                          + (cumulated[repeat_pattern_size + time_to_stabilize] - cumulated[time_to_stabilize]) * repeat
                          + cumulated[time_to_stabilize + remaining - 1] - cumulated[time_to_stabilize];
    return result;
}
#

for the curious

#

sorry it's in cpp

silver light
#

I'm pulling my hair out here. Part one works for the example, but it says the number is too low when using the puzzle input. I've gone over my code a bunch of times and even tried printing out the board after each step, but I can't find anything wrong.

past karma
#

want to post your code and see if we can figure out any issues?

wild rainBOT
silver light
#

Sorry for the delay - I had to help my kid fill out an application for school.

past karma
#

ah no worries :)

silver light
#

Just a hint please if you have one.

past karma
silver light
#

Yeah, but it gets the example right.

past karma
#

yes. same here. Very puzzling.

silver light
#

I thought the logic was good...

past karma
#

still looking into it

silver light
#

Thank you very much.

past karma
#

this is awkward lol - I ran the code on a different input which is why it crapped out

#

like, a different day's input

silver light
#

lol

#

I've done that.

past karma
#

and running it on my actual day 17 input, it does give the correct answer

silver light
#

WTF!

#

I just double checked my input...

#

Looks good.

past karma
#

maybe redownload it

silver light
#

Just did that.

#

Trying now.

#

It's still giving me 3202, which is too low.

#

And never mind... It accepted the answer. I must have fat-fingered the entry...

past karma
#

lol

#

PEBKAC error :)

silver light
#

I'm very sorry to have waited your time.

past karma
#

nah don't worry about it :)

silver light
#

Thank you very much!

#

Holy Carp! 1000000000000 rocks? I'm going to need some optimizations...

past karma
#

yes indeed lol

#

those judgy elephants...

silver light
#

I hope they don't forget what I'm doing for them here.

silver light
#

So I'm not seeing any loops in my input, so should I look for relationships at step intervals of the length of the input?

silver light
#

I've looked the bottom 10m records for any match to the first 10 and I haven't found a single match yet... does that sound right?

#

now i'm thinking that I can't use the bottom few rows.

lucid gulch
#

yea i think if you're gonna get a match it's gonna be xyzabcabcabc

lucid gulch
#

i think i'm on to something finally with my algorithm

lucid gulch
#

alright, thank you @past karma for the pointers you gave, i basically did what you said after converting my game to be set based instead of grid based python def find_pattern(grid, pattern=None): if pattern is None: for k in range(20, len(grid)//2): if grid[-k:] == grid[-k*2:-k]: pattern = grid[-k:] return pattern else: if grid[-len(pattern):] == pattern: return pattern and

        if count > 1000000:
            found = find_pattern(grid, repetition['pattern'])
            if found:
                if repetition['pattern'] is None:
                    repetition = {'pattern': found, 'cycle': r, 'height': len(grid)}
                else:
                    cycles_rem, remainder = divmod(count - repetition['cycle'], r-repetition['cycle'])
                    count = r + remainder
                    magic = (cycles_rem-1)*(len(grid)-repetition['height'])``` magic gets initialized to 0 and will always be added to the final return, count is the number of cycles to be run
#

ah and you can speed up your solution to basically instant by setting the min length of blocks to 2000+ since that seems to be in the ballpark for input solutions

past karma
#

Good to know!

silver light
#

Finally got it. I feel kind of bad tho. I searched for the repeated blocks manually so it only works with my puzzle input.

pine kelp
#

Not sure if I'm being incredibly dumb, but I cannot find the cycle in the test input. I've completed Part 1 (which fully simulates tetris the rocks falling), so I assume my code is doing the right thing. But even visually inspecting the board, I can't find a pattern.

Am I missing something obvious or have I somehow cheesed Part 1 :/

past karma
#

there is an "offset", if you like, before the pattern starts

#

So, for the test input, the cycle only begins after you get to 25 height. And then the cycle is a repeating group of 53 height.

#

that corresponds to 15 rocks for the offset, and 35 rocks per repeating group.

#

hopefully that helps :)

past karma
silver light
#

I will eventually do it, but I'm a little burnt out on that one. It took me hours to figure it out.

pine kelp
# past karma there is a pattern, but it doesn't start right at the bottom

Thanks for the tip. Stupidly I had changed how many rocks the simulation would run and didn't notice. So I never had quite enough of the chamber to find the pattern.

Annoyingly the maths I used to get the height for part 1 test using the repeating cycle doesn't work for part 2 test or actual input. As above, I've been at this on and off for days now. Gonna park it as I'm getting sick of rocks ๐Ÿ˜„

warm zealot
# pine kelp Thanks for the tip. Stupidly I had changed how many rocks the simulation would r...

A trick I used was not to store states at all, I just stored the heights so I didn't have to change my part1 solution much. Using the heights I calculated the deltas each time, and used a sliding window. So I iterated thru the windows (of arbitrary size like 150) until I found one that occurred later on. If a series of 150 deltas gets repeated you can be pretty sure it's a cycle
Idk if this helps peeposhrug

blazing mortar
#

10,091 :/ hrmmm

#

<3% done on brute. force

blazing mortar
#

so it took ~10 minutes to do ~3% by brute force, and an hour to program something to skip to the end, if my computer didn't hang on the brute force one it would have taken ~5 hours

#

time saved!

spare raptor
#

Does anyone have the final state of the test input for part 1? I'm getting the wrong answer, but I can't find a flaw in my simulation logic either :/

past karma
spare raptor
past karma
#

ok. I'll try a printout for you

spare raptor
#

perfect, thanks!

past karma
#

!paste

wild rainBOT
#

Pasting large amounts of code

If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/

After pasting your code, save it by clicking the floppy disk icon in the top right, or by typing ctrl + S. After doing that, the URL should change. Copy the URL and post it here so others can see it.

past karma
#

I knew my excessive unit testing would come in handy some day :)

spare raptor
#

Perfect! thank you!

spare raptor
#

And that's what I needed to find the bug! thanks, onto part 2 ๐Ÿ™‚

spare raptor
# past karma what was the bug btw?

The bit of code i has that checks for collisions between rocks was only looking at the bottom line of the falling rock for collisions, but for all lines of the rock. So the + ones would kind of get stuck on their corner. so instead of getting:

|     + |
|    +++|
| ####+ |

i'd get

|     + |
|    +++|
|     + |
| ####  |

does that make sense?

past karma
#

ah interesting

spare raptor
#

classic 'forgot to increase an iterator' bug :p But it didn't actually crop up until the 22nd rock, so it still seemed to be working for the test input and the simulation shown in the problem

past karma
#

yeah I just looked at the description example now - it's in none of the simulations

spare raptor
#

Hmm so now I'm thinking about part 2, seeing all the talk here about finding a repeating cycle. That seems pretty tough, but I have an idea to make it easier: instead of saving the lines as strings with one character per slot, i'll save them as integers, encoded as a bit mask (so the first line of the example would be 0011110. Then I could generate integer representations of a few hundred lines, and then just find the repeating cycle in that sequence of integers.

past karma
#

FYI I'm not saving the lines as string - internally they are saved in a structure similar to that (I use idx values from 0 - 6 but the concept is the same). I just print out when I need to (e.g. for easy unit testing)

spare raptor
#

Oh yeah I was only saving them as a string for easy printing out. But bit masks were the key for my day 16 solution so im looking for more ways to use that :p

#

Hmm i'm realizing that really only helps me to find the cycle in the output, but that's not enough to actually answer. I need to find the cycles in where the rocks end up

past karma
spare raptor
#

well if I only look at the individual lines of the output, I can't easily distinguish between the individual rocks.

#

I also am assuming that the final cycle will be truncated, and I'll have to reconstruct that one to get the true final height

past karma
spare raptor
#

naturally

past karma
spare raptor
#

Well, thank you for sharing your experience! saving me some stress for sure ๐Ÿ™‚

spare raptor
#

@past karma I finally got around to implementing a solution based on the cycles stuff, and it worked on the first try ๐Ÿ˜„