I might have to look for help on this one.
Day 11 Part 2 Hint
Itās not necessary to keep track of each individual stone. Just keep track of each unique stone value and the quantity of each.
I looked at this after I solved it. Thanks for posting it though.
Day 11 spoiler
My struggle was how to keep track of the growth considering that each stone could ultimately spawn itself.
My first epiphany was when I realized that only when there are an even number of digits does the number of stones increase, and then only by 1.
My next epiphany is that I could consider each stone by itself and just keep adding to my result. There was no need to keep manipulating an array.
My next epiphany was that I could cache the result of a stone instead of recalculating it.
My next epiphany was that 0-9 could be calculated easily and could save time of caching.
My final epiphany was that I could cache how much a stone added to the final result over a given number of blinks.
Once compiled, my solution takes about 300 ms.
As I rule I try to avoid string manipulation. In this case, I didnāt, and it cost me. Day 11 part 2 dropped from 300 ms to around 100 ms when I replaced my manipulated string key with a calculated integer.
Day 11 Spoiler
I used a pair of dictionaries with the stone value as the key, and the quantity of each as the dictionaryās stored value. After 75 iterations there were only 3772 dictionary entries, so it ran in about 250ms. (All integer calculations, but running on older MacBook.)
Public Sub Day11part2()
LoadData
var inpData() As String = Split(pzlData," ")
var dStone(1) As Dictionary 'use 2 dictionaries to prevent corruption during updates
dStone(0) = new Dictionary
dStone(1) = new Dictionary
var v() As Variant
var k() As Variant
var cu As Integer = 1
var pv As Integer = 1-cu
for i as Integer = 0 to inpData.LastIndex 'Load dict with starting values
dStone(cu).Value(inpData(i).ToInteger)=dStone(cu).Lookup(inpData(i).ToInteger,0)+1
next i
for blink as Integer = 1 to 75
pv = cu 'switch current and previous dictionary indices
cu = 1-cu
dStone(cu).RemoveAll
v = dStone(pv).Values
k = dStone(pv).Keys
for i as Integer = 0 to k.LastIndex
var stn As Integer = k(i)
if stn=0 then 'change 0 to 1
dStone(cu).Value(1)=dStone(cu).Lookup(1,0)+v(i)
Else
var nd As Integer = DigitCount(stn)
if IsEven(nd) then 'split into two values
var b As Integer = 10^(nd\2)
var t As Integer = stn mod b
dStone(cu).Value(t)=dStone(cu).Lookup(t,0)+v(i)
t = stn\b
dStone(cu).Value(t)=dStone(cu).Lookup(t,0)+v(i)
Else 'multiply by 2024
var t As Integer = stn*2024
dStone(cu).Value(t)=dStone(cu).Lookup(t,0)+v(i)
end if
end if
next i
next blink
var sTotal As Integer =0
v=dStone(cu).Values
for i as Integer = 0 to v.LastIndex
sTotal = sTotal+v(i) 'sTotal is the puzzle solution
next i
End Sub
Day 11 Spoiler
I wrote a recursive solution for Part 1 assuming that Iād need another approach for Part 2. Fortunately simply adding a cache dictionary was all that was needed.
Public Function CountStones(n as integer, blinks as Integer) As Integer
Static cache as New Dictionary
dim lookupKey as Integer = n * 1024 + blinks
if cache.HasKey( lookupKey ) then
Return cache.Value( lookupKey )
end
dim result as Integer
if blinks = 0 then
result = 1
elseif n = 0 then
result = CountStones( 1, blinks-1 )
else
dim digits as Integer = Log10MBS( n ) + 1 // Log(n) / Log(10) is wrong for 1000
if ( digits mod 2 ) <> 0 then
// odd number of digits
result = CountStones( n * 2024, blinks-1 )
else
// even number of digits
dim factor as Integer = 10 ^ (digits/2)
dim n1 as Integer = n \ factor
dim n2 as Integer = n mod factor
result = result + CountStones( n1, blinks-1 )
result = result + CountStones( n2, blinks-1 )
end
end
cache.Value( lookupKey ) = result
Return result
End Function
Mine looks similar to yours.
For Day 12 part 2, thereās some code I wrote many years ago that will solve it. The only problem is that itās written in 6502 assembly language. So either I have to translate it into XOJO, or else write a 6502 emulator.
I had guessed that for part 2 of Day 12, the twist was going to be that the grid repeated a million times in various directions. Was relieved to see the actual part 2.
Day 13 was easy for a change.
Meanwhile, Iām still working towards a solution to Day 12 Part 2. Iāve got my old 6502 ASM routine rewritten in Xojo, but still need to add a bit more code to it. I know that Iām over-complicating this, but itās all useful code that Iām adding to my Point2D class.
Day 14 was also straightforward, although part 2 added an interesting twist. Will be interested to see how others approach this.
I fell way behind.
Dealing with some family issues (my parents are making the transition from their home to a Senior Living Center) as well as very busy work schedule, and, having āa bad bugā (which is what people want to seem to call Covid these days ĀÆ\(ć)/ĀÆ )
I donāt know how the Advent of Code works/ends?
Will I still be able to catch up over the Christmas break or is it all over on the 25th? I was really enjoying the challenge!
Very few of us have the time necessary to spend on these as the puzzles get more difficult and it gets closer to Christmas. Iām falling behind now too. But, you can continue to work on them as long as you want. They wonāt disappear.
All of the previous years are still there to work on too, if you run out of things to do.
Same boat here, minus the bad bug. Work at your own pace.
Just finished Day 14.
Day 14 spoiler
It happened that my data came up with 8 or so robots in the center, but thatās not guaranteed, i.e., the tree can be anywhere on the board.
My ultimate solution runs in less than a second compiled and goes like this:
- I cycle through each second starting at 1.
- I create a MemoryBlock of size (height * width).
- For each robotās position, I set the byte corresponding to that index (y * width + x) to 1.
- Using a Ptr, I cycle through the MemoryBlock looking for an UInt64 of
&h0101010101010101
, or 8 robots in a row. - If that doesnāt exist, I continue to next second. If it does, I have my answer.
I found an even faster way. Now Day 14 runs in under 200 ms.
Day 14 spoiler
I create and fill in the MemoryBlock as above, but using the value &h44
, which is āDā (just for convenience).
After positioning all the robots, I convert my MemoryBlock to a string and use IndexOfBytes( "DDDDDDDD" ) <> -1
.
Day 14 spoiler
For part 1 the final positions can be calculated directly without any iteration. So part 1 execution is very fast (3 ms).
For part 2 there didnāt seem to be any choice but to do the calculation for each iteration until a feature was found that might signify the Easter Egg. Trying to figure out what an easily detectable feature might be, I guessed that a sequence of contiguous robots (signified by 1ās in my output array) would occur somewhere in a horizontal line. So, I just created a variable to count contiguous ones. If/when the count hit 10 (10 robots in a horizontal line), I assumed that was the feature I was looking for. It turned out to be a correct assumption. Part 2 runs in about 500 ms on my older macbook.
Just finished Day 15.
Day 15 spoiler
Part 1 is pretty straightforward. I created a string array and for every move I check for a gap in that direction. If I hit a wall first, I ignore the instruction. If the gap is right next to the robot, I just move it. Otherwise, I move the box directly next to the robot the gap, then move the robot to the now-empty space.
Part 2 is tricker. Again, I look for a gap in the right direction. If I canāt find one, I move on, If itās right next to the robot, I move the robot. Otherwise, if the move is horizontal, I shift everything over as required.
If the move is vertical, I send the square above (or below) the robot to a recursive method that collects each point that is affected. If it finds a wall, it returns nil. Otherwise, it returns a Dictionary with the points as a key and the character that point contains as a value. I then use that information to shift the characters in the grid and move the robot.
This all happens practically instantly even in the IDE.
I was part way through Day 15 part 2, but got interrupted, and havenāt had time to get back to it. Hopefully tomorrow. Or if Day 19 looks too intimidating, I may try to finish Day 15 tonight instead.
Iāve given up on Day 12 part 2 for now, Iāll circle back to it later.