Advent of Code 2018 - 25x2 coding puzzles for December

It’s not that it’s hard. Just… read it carefully before starting. A few times.

3 Likes

…Like when your program is working perfectly, but you didn’t read what answer the damn contest is asking for.

Dammit, Day 5.

Admittedly, I wasted a bunch of time trying to get the /U and /L RegEx operators working in Powershell, until I gave up and just coded each letter combination manually.

2 Likes

If it helps at all, I did the same exact thing. And then wasted time trying to re-do my program with a more complicated method that for some reason didn’t quite do things correctly (I’ll have to go back and troubleshoot it later to figure out where I went wrong).

And it sounds like we ended up with the same method in the end. :smiley:

1 Like

Yeah, this one was incredibly straightforward. If those bloody backreference case conversion operators had worked for me, I would have been done in five minutes.

My loop would have just been:


do {
  $input = $input -creplace "(([A-Z])/L/1|([a-z])/U/1)",""
} while ($input -cmatch "(([A-Z])/L/1|([a-z])/U/1)" -ne "")

Sadly, no joy.

I solved Part 1 pretty quickly, but part 2 is a big ball of WTF. I’m pretty much certain I’m getting the right value and calculating it correctly but it’s just not working.

Here’s my part 1 solution. It runs in less than 1s so I guess it can’t be too sub-optimal. I did cheat a little by using SortedDictionary for sorting my dates (but it’s not against the rules).

Set-StrictMode -Version Latest
$input = '...'
$sr = [System.IO.StringReader]::new($input)
$actions = [System.Collections.Generic.SortedDictionary[datetime,string]]::new() # yeah, this is kind of cheating but this will sort by time
$guardsSleepTime = @{}
$guardActions = @{}

while($null -ne ($v = $sr.ReadLine())) {
    $m = [regex]::Match($v, "\[(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)\] (.*)")
    $action = $m.Groups[6].Value
    $date = [datetime]::new([int]$m.Groups[1].Value, [int]$m.Groups[2].Value, [int]$m.Groups[3].Value, [int]$m.Groups[4].Value, [int]$m.Groups[5].Value, 0)
    $actions[$date] = $action
}

$guard = [int]0
$lastSleepTime = [datetime]::MinValue
$actions.GetEnumerator() | foreach {
    $date = $_.Key
    $action = $_.Value

    if($action.StartsWith('Guard') -eq $true) {
        $guard = [int][regex]::Match($action, ".*\#(\d+)\s+.*").Groups[1].Value
        if($guardActions.ContainsKey($guard) -eq $false) {
            $guardActions[$guard] = @{}
        }
    } elseif($action -eq "falls asleep") {
        $lastSleepTime = $date
    } elseif($action -eq "wakes up") {
        $sleepMinutes = $date.Subtract($lastSleepTime).Minutes
        $guardsSleepTime[$guard] += $sleepMinutes
        for($i = 0; $i -lt $sleepMinutes; $i++) {
            $guardActions[$guard][$lastSleepTime.Minute + $i] += 1
        }
    }
}

$sleepiestGuard = [int]($guardsSleepTime.GetEnumerator() | sort {$_.Value } -Descending | Select -First 1).Key

# We've got the sleepiest guard, now let's figure out when they are most often asleep
$sleepiestGuard * ($guardActions[$sleepiestGuard].GetEnumerator() | sort { $_.Value } -Descending | Select -First 1).Key

Are you multiplying the right two numbers together?

1 Like

I’ll have to look at it more tomorrow. My laptop battery died and I took that as a cue to pack it in for this evening.

I ended up rewriting my method to use a dictionary like @nonentity suggested. Now all of the tests for both day one and two take less than 1 second. Also, my modified method is now significantly simpler.

In other news, there are now five members on the leaderboard.

2 Likes

I finally figured out what I was getting wrong with day 4 part 2 – when getting the sleep range, I wasn’t subtracting 1 from the waking time (duh). After using their sample set, walking through the debugger, and cursing a few times I got it fixed pretty fast.

Here’s my day 4 part 2:

Set-StrictMode -Version Latest

$input = '...'

$sr = [System.IO.StringReader]::new($input)
$actions = [System.Collections.Generic.SortedDictionary[datetime,string]]::new() # yeah, this is kind of cheating but this will sort by time
$guardsSleepTime = @{}
$guardsSleepMins = @{}

while($null -ne ($v = $sr.ReadLine())) {
    $m = [regex]::Match($v, "\[(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d)\] (.*)")
    $action = $m.Groups[6].Value
    $date = [datetime]::new([int]$m.Groups[1].Value, [int]$m.Groups[2].Value, [int]$m.Groups[3].Value, [int]$m.Groups[4].Value, [int]$m.Groups[5].Value, 0)
    $actions[$date] = $action
}

$guard = [int]0
$lastSleepTime = [datetime]::MinValue
$actions.GetEnumerator() | foreach {
    $date = $_.Key
    $action = $_.Value

    if($action.StartsWith('Guard') -eq $true) {
        $guard = [int][regex]::Match($action, ".*\#(\d+)\s+.*").Groups[1].Value
        if($guardActions.ContainsKey($guard) -eq $false) {
            $guardActions[$guard] = @{}
        }
    } elseif($action -eq "falls asleep") {
        $lastSleepTime = $date
    } elseif($action -eq "wakes up") {
        $sleepMinutes = $date.Subtract($lastSleepTime).Minutes - 1 # -1 because we don't count the waking minute
        if($guardsSleepMins.ContainsKey($guard) -eq $false) {
            $guardsSleepMins[$guard] = @{}
        }
        
        ($lastSleepTime.Minute..($lastSleepTime.AddMinutes($sleepMinutes).Minute)) | foreach {
            $guardsSleepMins[$guard][$_] += 1
        }
    }
}

$highGuard = 0
$highValue = 0
$highMinute = 0
$guardsSleepMins.GetEnumerator() | foreach {
    $g = $_.Key

    $_.Value.GetEnumerator() | foreach {
        $min = $_.Key
        $count = $_.Value
        
        if($count -gt $highValue) {
            $highGuard = $g
            $highValue = $count
            $highMinute = $min
        } 
    }
}

$highGuard * $highMinute

I’ve decided not to participate at midnight anymore. I just haven’t been able to let my mind wind down in any reasonable time after finishing, which means sleeping poorly and spending the next day exhausted.

I will still be doing the challenges, but at a more reasonable hour.

5 Likes

I’m the new person on the leaderboard. I saw this last night and thought it sounded like fun, but I wanted to try to catch up on the first few puzzles before I started unblurring the spoiler tags and participating in this thread.

I made a decent start last night, and was excited to get back to it this evening, so naturally I’ve spent the last couple hours trying figure out how to roll back an auto-updating extension that’s borked my environment since literally just this morning. :rage: :crazy_face: :man_shrugging:

4 Likes

Day 5 part 1 went pretty smoothly – my solution isn’t efficient (it takes a few minutes to run) but it works. Using a StringBuilder saved me a huge amount of computation cycles compared to string.

Set-StrictMode -Version Latest

$input = '...'

$sb = [System.Text.StringBuilder]::new($input) # string is to costly in terms of performance

$it = 0
$lastRun = $sb.Length

# We could be so much more efficient here, but fuck it. Just brute force it.
while($true) {
    $it++
    Write-Host "Iteration: $it Length: $($sb.Length)"
    
    for($i = 0; $i -lt ($sb.Length-1); $i++) {
        $cur = $sb[$i]
        $next = $sb[$i+1]
        if($cur -ceq $next) {
            continue
        } elseif($cur -ine $next) {
            continue
        }

        $curIsLower = [regex]::IsMatch($cur, '[a-z]')
        $nextIsLower = [regex]::IsMatch($next, '[a-z]')

        if($curIsLower -ne $nextIsLower -and $cur -ieq $next) {
            $sb.Remove($i,2) | Out-Null
            $i++
            continue
        }
    }

    if($lastRun -eq $sb.Length) {
        break
    }

    $lastRun = $sb.Length
}

$poly = $sb.ToString()
Write-Host "Final value: $poly"
Write-Host "Final length: "
$($poly.Length)

However part 2 isn’t working for me and it’s not any sense to me as to why. I’ve added the following to the beginning:

$polyCount = @{}
for($i = 0; $i -lt ($sb.Length - 1); $i++) {
    if($sb[$i] -ieq $sb[$i+1]) {
        $polyCount[[char]::ToLower($input[$i])] += 1
    }
}

$letter = ''
$count = 0
$polyCount.GetEnumerator() | foreach {
    if($_.Value -gt $count) {
        $letter = $_.Key
        $count = $_.Value
    }
}

Write-Host "Most: $letter : $count"
for($i = 0; $i -lt $sb.Length; $i++) {
    if([char]::ToLower($sb[$i]) -eq $letter) {
        $sb.Remove($i,1) | Out-Null
        $i--
    }
}

This code finds the letter with the most occurrences and then strips it out of the result but the count I’m getting isn’t matching what the web site wants.

Annoyingly when I run the code against their sample, I get the expected text result and count, so I’m not sure what I’m getting wrong here.

ETA: I think I may have seen where I was getting it wrong. Unfortunately I was getting it wrong in a way that just happened to pass my unit test. Sigh. I’ll try again tomorrow after some sleep.

dabAcCaCBAcCcaDA
Most: c : 3
dabAaBAaDA
Iteration: 1 Length: 10
Iteration: 2 Length: 8
Iteration: 3 Length: 6
Iteration: 4 Length: 4
Final value: daDA
Final length: 
4
2 Likes

This might be able to get the right answer depending on the input, but my understanding was that the correct letter to remove is not necessarily the one that has the most occurrences.

3 Likes

Yeah, I cycled through all of them.

2 Likes

That’s what I was afraid of. I didn’t find the description to be entirely clear this time around.

1 Like

Ooof. I am glad I didn’t tackle this last night. I’m wide awake (-ish) and I’m still having trouble seeing a way through Day 6.

Edit: Okay, now I can see how to determine the infinite part.

Edit 2: apparently, I can’t math. I’ve spent an extra hour on this thing because I was stubbornly convinced that 400x400=1600.

2 Likes

I’ve read Day 6’s description some 10 times and it’s just gobbledygook to me.

I think I’m going to have to sit this one out.

(I have a severe math block and even looking at some of the solutions on Reddit isn’t proving particularly enlightening.)

3 Likes

I finally got it (Day 5 pt 2) – I didn’t cycle through everything, I just popped in the first answer for the first letter it was able to strike and reduce and that happened to be the right one. (Kind of cheating, but my code takes so long to run I didn’t feel like waiting for it to complete if I didn’t have to.)

3 Likes

(posting a bit out of order, but still playing catch-up on the puzzles, so please bear with me.)

I finished the day 3 puzzles earlier this afternoon and it was a bit of a roller coaster ride of emotions.

I’m a big fan of PowerShell (which is what I’ve been using for these puzzles), but every so often I’ll come across some feature that seems familiar at first, because I’ve seen it in other languages, but turns out to work not quite like I expect it to in subtle ways. And then I go down the rabbit hole trying to figure out exactly what PowerShell is doing, and why, and I usually learn something interesting in the process, so that’s nice, but it’s still kind of vexing.

Today I learned that PowerShell doesn’t really have multidimensional arrays (unless you cast to a .NET type), but it does have collections of collections, which are effectively close enough for many practical purposes, but they’re tricky to declare and initialize.

In any case, after many digressions, I finally get the data structure I want, and fairly quickly after that a solution to the first puzzle. Yay, me! It took a while, but I learned a couple new-to-me operators and some of the finer points of PowerShell arrays.

The second problem from day 3 is a pretty straightforward extension of the first problem, so I gin up a new solution based on the first one and quickly arrive at an answer, which I then confidently paste into the form, only to be greeted with this:

That’s not the right answer. If you’re stuck, there are some general tips on the about page, or you can ask for hints on the subreddit. Please wait one minute before trying again. (You guessed #724.) [Return to Day 3]

So I run it again. Same result. #724.

I review my code, line by line, looking for typos or other dumb mistakes. Everything looks good. I save and run it again, and get the same result: #724.

I debug it against a tiny set of sample data, set against a 10x10 grid, small enough that I can print out and manually inspect the intermediate steps of my calculations. My logic is sound. There’s nothing wrong with my code, at least for the trivial cases.

I revert back to the official puzzle data and run it again. I get the same result as every time before. #724.

I stand up and pace around for a bit. I wander into the other room. I refresh my drink and pick some new music to listen to. I do a little dance, because the music is kind of funky.

I return to my desk, sit quietly, and stare into the display.

I ponder.

I pull up the Advent puzzle page, and into the answer text box I type these characters: 724. And I’m presented with this:

That’s the right answer! You are one gold star closer to fixing the time stream.

grrrrrrrr. :face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth:

but also: huzzah! I figured it out! :tada::confetti_ball::sparkler::boom::balloon::sparkles:

5 Likes

Day 6 Part 1 was a nightmare.

It’s all downhill from there (so far), though. My program for Day 6 Part 2 is probably a quarter or less of the length of my Part 1 solution, and Day 7 is just plain easy (even though I made myself put off doing Part 2 so I could sleep; I know just about exactly how I’ll solve it when I get home tonight).

1 Like