Skip to content

Instantly share code, notes, and snippets.

@JPRuskin
Last active December 7, 2021 17:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JPRuskin/6cdd5117d14ea02cd1c2104cd5456b45 to your computer and use it in GitHub Desktop.
Save JPRuskin/6cdd5117d14ea02cd1c2104cd5456b45 to your computer and use it in GitHub Desktop.
Solutions to Advent of Code 2021, probably in PowerShell.

Advent of Code 2021

CodeTree thanks to obalunenko

This gist contains some Advent of Code solutions for the 2021 season.

param(
[int[]]$Reports = @(199,200,208,210,200,207,240,269,260,263)
)
$Increases = 0
foreach ($Depth in $Reports) {
if ($LastDepth -and $Depth -gt $LastDepth) {
$Increases++
}
$LastDepth = $Depth
}
Write-Host "There are $($Increases) measurements that are larger than the previous measurement."
$LargerSums = 0
for ($i=0; $i -le ($Reports.Count - 2); $i++) {
$Window = $Reports[$i] + $Reports[$i+1] + $Reports[$i+2]
if ($LastWindow -and $Window -gt $LastWindow) {
$LargerSums++
}
$LastWindow = $Window
}
Write-Host "There are $($LargerSums) sums that are larger than the previous sum."
param(
[string[]]$Instructions = @"
forward 5
down 5
forward 8
up 3
down 8
forward 2
"@.Split("`n")
)
# Part 1
$Horizontal = 0
$Depth = 0
switch -regex ($Instructions) {
"forward (\d+)" {$Horizontal += $Matches[1]}
"down (\d+)" {$Depth += $Matches[1]}
"up (\d+)" {$Depth -= $Matches[1]}
}
Write-Host "$Horizontal * $Depth = $($Horizontal * $Depth)"
# Part 2
$Horizontal = 0
$Depth = 0
$Aim = 0
switch -regex ($Instructions) {
"forward (\d+)" {
$Horizontal += $Matches[1]
$Depth += $Aim * $Matches[1]
}
"down (\d+)" {$Aim += $Matches[1]}
"up (\d+)" {$Aim -= $Matches[1]}
}
Write-Host "$Horizontal * $Depth = $($Horizontal * $Depth)"
param(
[string[]]$Report = @"
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
"@.Split("`n")
)
function Get-ModeBit {
param(
[Parameter(Mandatory)]
[string[]]$Data,
[int]$Bit = 0
)
end {
$Data.ForEach{$_[$Bit]} | Group-Object | Sort-Object Count -Descending | Select-Object -ExpandProperty Name -First 1
}
}
function ConvertFromBinaryString {
# https://gist.github.com/JPRuskin/2e0f5315f5960d34ff71743a4ade765a#file-aoc_day5-ps1
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline, Mandatory)]
[string]$String,
[Parameter()]
[char]$On = "1",
[Parameter()]
[char]$Off = "0"
)
[Convert]::ToInt32($String.Trim().Replace($On, "a").Replace($Off, "b").Replace("a", "1").Replace("b", "0"), 2)
}
# Part 1
[string]$ModeBinary = "$(for ($i=0; $i -lt $Report[0].Length; $i++) {
Get-ModeBit -Data $Report -Bit $i
})".TrimEnd().Replace(' ','')
Write-Host "G: $($ModeBinary)"
$GammaRate = ConvertFromBinaryString -String $ModeBinary.Replace(' ', '') -On "1" -Off "0"
$EpsilonRate = ConvertFromBinaryString -String $ModeBinary.Replace(' ', '') -On "0" -Off "1"
Write-Host "$GammaRate * $EpsilonRate = $($GammaRate * $EpsilonRate)"
# Part 2
function Get-Rating {
param(
[string[]]$Data,
[switch]$Least # CO2 -> Least
)
end {
$MatchData = $Data
$Bit = 0
while ($MatchData.Count -gt 1) {
$BitCount = $MatchData.ForEach{$_[$Bit]} | Group-Object | Sort-Object Count -Descending
$ModeBit = if ($BitCount[0].Count -eq $BitCount[1].Count) {
Write-Verbose "Tie between $($MatchData)!"
[int](-not [bool]$Least) # Default in ties
} else {
$BitCount[[bool]$Least].Name
}
$MatchData = $MatchData.Where{
$_[$Bit] -eq "$($ModeBit)"
}
$Bit++
}
$MatchData
}
}
Write-Host "O2: $(($O2 = Get-Rating $Report | ConvertFromBinaryString))"
Write-Host "CO2: $(($CO2 = Get-Rating $Report -Least | ConvertFromBinaryString))"
Write-Host "Life Support = $($O2 * $CO2)"
param(
[int[]]$Numbers = @(7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1),
$Boards = (Get-Content -Path $PSScriptRoot\Day4Input.txt -Delimiter "
")
)
Class BingoBoard {
[int[]]$Values = @()
[int[]]$Marked = @()
[int]$Width = 5
[int]$Height = 5
[bool]$Bingo
[void]Mark([int[]]$Number) {
$this.Marked += $Number
}
[bool]CheckRow($Number) {
$Start = $Number * $this.Width
return $false -notin $this.Values[$Start..($Start + $this.Width - 1)].ForEach{$this.Marked -contains $_}
}
[bool]CheckColumn($Number) {
$Column = @($Number) + @(1..$this.Height | ForEach-Object {$Number + ($_ * $this.Width)})
return $false -notin $this.Values[$Column].ForEach{$this.Marked -contains $_}
}
[bool]CheckWin() {
$this.Bingo = $true -in @(
0..($this.Width-1) | ForEach-Object {$this.CheckColumn($_)}
0..($this.Height-1) | ForEach-Object {$this.CheckRow($_)}
)
return $this.Bingo
}
[int]CalculateScore() {
return ($this.Values.Where{$_ -notin $this.Marked} | Measure-Object -Sum).Sum
}
BingoBoard ([string]$Values) {
$this.Values = $Values.Split("`n").Split(" ").Trim(" ").Where{$_}
}
}
if ($Boards.Count -gt 1) {
[BingoBoard[]]$Boards = $Boards
} else {
Write-Error "Failed to split the boards." -ErrorAction Stop
}
# Part 1: Play the game(s)
$i = 0
while ($true -notin $Boards.CheckWin()) {
$Boards.Mark($Numbers[$i++])
}
Write-Host "First Winner Score: $($Boards.Where{$_.Bingo}.CalculateScore() * $Numbers[$i-1])"
# Part 2: Continue, to find the last winner
while ($Boards.CheckWin().Where{$_ -eq $false}.Count -gt 1) {
$Boards.Mark($Numbers[$i++])
}
$LastBoard = $Boards.Where{-not $_.Bingo}
while (-not $LastBoard.CheckWin()) {
$LastBoard.Mark($Numbers[$i++])
}
Write-Host "Final Winner Score: $($LastBoard.CalculateScore() * $Numbers[$i-1])"
param(
[string[]]$Vents = (Get-Content $PSScriptRoot\Day5.input)
)
class Coordinate {
[int]$X
[int]$Y
Coordinate ([string]$Position) {
$this.X, $this.Y = $Position.Split(',')
}
[string] ToString () {
return "$($this.X),$($this.Y)"
}
}
class Vent {
[Coordinate]$Begin
[Coordinate]$End
[bool]$StraightLine
[Coordinate[]]$Positions = @()
[void] GetAllCoordinates () {
if ($this.Begin.X -eq $this.End.X -or $this.Begin.Y -eq $this.End.Y) {
$this.StraightLine = $true
foreach ($X in $this.Begin.X..$this.End.X) {
foreach ($Y in $this.Begin.Y..$this.End.Y) {
$this.Positions += "$X,$Y"
}
}
} else {
$this.StraightLine = $false # $this.Begin.X -eq $this.End.X -or $this.Begin.Y -eq $this.End.Y
$Xs = @($this.Begin.X..$this.End.X)
$Ys = @($this.Begin.Y..$this.End.Y)
$i = 0
$Xs.ForEach{$this.Positions += "$($_),$($Ys[$i++])"}
}
}
Vent ([string]$Definition) {
if ($Definition -match "^(?<Begin>\d+,\d+) -> (?<End>\d+,\d+)$") {
$this.Begin = $Matches.Begin
$this.End = $Matches.End
$this.GetAllCoordinates()
} else {
Write-Warning "'$($Definition)' does not match the expected pattern."
}
}
}
$All = [Vent[]]$Vents
# Part 1
$IntersectingPoints = $All.Where{$_.StraightLine}.Positions | Group-Object | Where-Object Count -gt 1
Write-Host "There are $($IntersectingPoints.Count) intersections for straight lines."
# Part 2
$IntersectingPoints = $All.Positions | Group-Object | Where-Object Count -gt 1
Write-Host "There are $($IntersectingPoints.Count) intersections."
param(
$InitialState = @(3,4,3,1,2),
$Days = 80 # 256
)
<# Part 1
foreach ($Day in 1..$Days) {
$State = switch ($State ? $State : $InitialState) {
0 {6, 8}
default {$_-1}
}
}
Write-Host "There are $($State.Count) lanternfish after $($Days) days."
#>
# Part 2
$FishState = @{
0 = $InitialState.Where{$_ -eq 0}.Count
1 = $InitialState.Where{$_ -eq 1}.Count
2 = $InitialState.Where{$_ -eq 2}.Count
3 = $InitialState.Where{$_ -eq 3}.Count
4 = $InitialState.Where{$_ -eq 4}.Count
5 = $InitialState.Where{$_ -eq 5}.Count
6 = $InitialState.Where{$_ -eq 6}.Count
7 = $InitialState.Where{$_ -eq 7}.Count
8 = $InitialState.Where{$_ -eq 8}.Count
}
foreach ($Day in 1..$Days) {
$NewState = @{}
switch ($FishState.Keys) {
0 {
$NewState[6] += $FishState[0]
$NewState[8] += $FishState[0]
}
default {
$NewState[$_ - 1] += $FishState[$_]
}
}
$FishState = $NewState
Write-Progress -Activity "Generating Lanternfish" -CurrentOperation "Day $Day" -PercentComplete ($Day/$Days*100)
}
Write-Host "There are $(($FishState.Values | Measure-Object -Sum).Sum) lanternfish after $($Days) days."
param(
[int[]]$CrabLocation = @(16, 1, 2, 0, 4, 2, 7, 1, 2, 14)
)
function Get-TotalCost {
param(
[Parameter(Mandatory, ValueFromPipeline)]
[int[]]$Position,
[Parameter(Mandatory)]
[int]$Target,
[switch]$LinearFuelCost
)
begin {
$Cost = 0
if (-not $script:Map) {
$script:Map = @{}
}
}
process {
foreach ($Single in $Position) {
[int[]]$Objects = $Single, $Target | Sort-Object
$Steps = $Objects[1] - $Objects[0]
$Cost += if ($LinearFuelCost) {
$Steps
} else {
if (-not $script:Map[$Steps]) {
$script:Map[$Steps] = $Steps * ($Steps + 1) / 2 # ($Steps..1 | Measure-Object -Sum).Sum # this worked in all examples but failed in Day2
}
$script:Map[$Steps]
}
}
}
end {
$Cost
}
}
function Get-SecondsRemaining {
param(
$Percent,
[switch]$Reset
)
if ($Reset -or -not $script:Stopwatch) {
$script:Stopwatch = [system.diagnostics.stopwatch]::StartNew()
}
$script:Stopwatch.Elapsed.TotalSeconds / ($Percent / 100) * (100 - $Percent) / 100
if ($Percent -ge 100) {
$script:Stopwatch = $null
}
}
$script:Stopwatch = $null
# Part 1 -LinearFuelCost, 2
$SortedList = $CrabLocation | Sort-Object
if ($script:LastRun -ne "$($SortedList[0]), $($SortedList[-1]))") {
$Range = @{}
$script:LastRun = "$($SortedList[0]), $($SortedList[-1]))"
}
foreach ($Position in $SortedList[0]..$SortedList[-1]) {
try {
$Percent = $Position / $SortedList[-1] * 100
$Seconds = Get-SecondsRemaining -Percent $Percent
Write-Progress -Activity "Contemplating Crab Movement" -Status "Calculating cost for '$Position' (of $($SortedList[-1]))" -PercentComplete $Percent -SecondsRemaining $Seconds
} catch {} # If it takes long enough for me to play with this, that's probably a bad sign
if (-not $Range[$Position]) {
$Range[$Position] = Get-TotalCost -Position $CrabLocation -Target $Position
}
}
$Range = $Range.GetEnumerator
Write-Host "The cheapest possible outcome is position $($Range[0].Position) with a cost of $($Range[0].Cost)."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment