Here's my part 2 solution in #haskell. I ended up needing to do some substantial refactoring from my previous solution that I'd used for day 5 as well as part 1. My original version attempting to go for performance by using mutable vectors to store the program state, ostensibly allowing for more performant seeks and writes to the program state. I started to extend this approach using IORefs to program state and some other clever trickery. Although I managed to get constant memory utilization, the performance was so bad the program never actually finished running.
After profiling didn't help enough, and I verified that there was nothing unsound about my algorithm, I decided to start from the ground up with the simplest solution and went back to a pure implementation using record updates to manage all of the changes to start, and manually sending IO between the amplifiers. Once again proving that when it comes to optimization I'm never as clever as I think I am, the compiler did it's job and took my naive implementation and gave me a version that finished in a couple hundred milliseconds.
My new version needs some refactoring still, both for readability and ergonomics during future challenges, but here is the version left on my disk from when I finally finished up at 5am:
Here's my part 2 solution in #haskell. I ended up needing to do some substantial refactoring from my previous solution that I'd used for day 5 as well as part 1. My original version attempting to go for performance by using mutable vectors to store the program state, ostensibly allowing for more performant seeks and writes to the program state. I started to extend this approach using IORefs to program state and some other clever trickery. Although I managed to get constant memory utilization, the performance was so bad the program never actually finished running.
After profiling didn't help enough, and I verified that there was nothing unsound about my algorithm, I decided to start from the ground up with the simplest solution and went back to a pure implementation using record updates to manage all of the changes to start, and manually sending IO between the amplifiers. Once again proving that when it comes to optimization I'm never as clever as I think I am, the compiler did it's job and took my naive implementation and gave me a version that finished in a couple hundred milliseconds.
My new version needs some refactoring still, both for readability and ergonomics during future challenges, but here is the version left on my disk from when I finally finished up at 5am: