Solved: Anyone doing Advent of Code in powershell?
Source: Dev.to
Executive Summary
TL;DR: Tackling Advent of Code (AoC) in PowerShell presents challenges such as verbose input parsing and performance bottlenecks for complex algorithms.
Solutions involve:
- Leveraging idiomatic PowerShell’s pipeline and .NET integration.
- Boosting speed with C# interop for critical sections.
- Orchestrating external, highly‑optimized utilities.
Why Use Idiomatic PowerShell?
- Object‑oriented pipeline – chain cmdlets, pass objects, keep code readable.
- Built‑in cmdlets – powerful string manipulation, regex, and file handling.
- Direct .NET calls – access any .NET type when a cmdlet isn’t enough.
For many AoC puzzles this approach is natural, readable, and sufficient.
When PowerShell Hits a Performance Wall
- Large data sets, deep recursion, or intensive simulations can make PowerShell scripts run minutes instead of seconds.
- Advanced data structures (priority queues, custom graphs, immutable collections) are cumbersome to implement efficiently in pure PowerShell.
- Missing algorithmic primitives – PowerShell lacks the rich standard‑library helpers found in Python or C#.
Solution: Use C# interop (Add-Type) for the hot‑path code, then call the compiled classes from PowerShell.
Orchestrating External Tools
PowerShell shines as the “glue” that:
- Prepares inputs.
- Executes external, highly‑optimized binaries (e.g.,
grep, custom C/C++ tools). - Processes the outputs back into PowerShell objects.
Practical PowerShell Patterns
1. Summing Numbers from a Delimited Input File
input.txt
10,20,30
15,25,35
# Read each line, split by comma, convert to integer, and sum
$totalSum = Get-Content -Path 'input.txt' |
ForEach-Object { $_ -split ',' } |
ForEach-Object { [int]$_ } |
Measure-Object -Sum |
Select-Object -ExpandProperty Sum
Write-Host "Total Sum: $totalSum"
2. Working with a Grid / Matrix
grid.txt (example)
#.##
.#.#
##.#
# Load the grid as an array of character arrays
$grid = Get-Content -Path 'grid.txt' | ForEach-Object { $_.ToCharArray() }
# Access an element (row 1, column 2)
Write-Host "Element at (1,2): $($grid[1][2])"
# Iterate through the grid
for ($row = 0; $row -lt $grid.Length; $row++) {
for ($col = 0; $col -lt $grid[$row].Length; $col++) {
Write-Host "($row,$col) = $($grid[$row][$col])"
}
}
3. Using .NET Collections for Performance & Flexibility
# Mutable generic List[int]
$myList = [System.Collections.Generic.List[int]]::new()
$myList.Add(10)
$myList.Add(20)
$myList.Add(30)
Write-Host "List count: $($myList.Count)"
$myList.Remove(20)
Write-Host "List after removal: $($myList -join ', ')"
# Dictionary (hashtable in PowerShell)
$myDictionary = @{}
$myDictionary["apple"] = 1
$myDictionary["banana"] = 2
Write-Host "Value for apple: $($myDictionary["apple"])"
C# Interop for Hot‑Path Code
When “idiomatic PowerShell” isn’t fast enough, embed C# directly:
Add-Type @"
using System;
using System.Collections.Generic;
public static class AoCHelper {
// Example: fast sum of an int array
public static long FastSum(int[] numbers) {
long sum = 0;
foreach (int n in numbers) sum += n;
return sum;
}
// Add more performance‑critical methods here
}
"@
# Use the compiled class from PowerShell
$numbers = 1..1_000_000
$sum = [AoCHelper]::FastSum($numbers)
Write-Host "Fast sum = $sum"
Write the performance‑critical algorithm in C#, compile it with Add-Type, then call it as a normal PowerShell method.
Putting It All Together
- Start with idiomatic PowerShell for parsing and orchestration.
- Identify bottlenecks (use
Measure-Commandor profiling). - Replace the hot‑path sections with C# interop or external tools.
- Keep the overall script readable and maintainable by limiting the interop surface.
Final Thoughts
- Advent of Code is an excellent playground to explore PowerShell’s strengths and limits.
- By combining pipeline‑centric scripting, .NET power, C# interop, and external utilities, you can solve even the toughest AoC puzzles efficiently while preserving the clarity that makes PowerShell a great automation language.
Fast Fibonacci Sequence Calculation in C#
We’ll define a C# class with a static method to calculate the Nth Fibonacci number quickly.
$cSharpCode = @'
using System;
public static class FibonacciCalculator
{
public static long GetNthFibonacci(int n)
{
if (n left.Equals(right);
public static bool operator !=(Point left, Point right) => !(left == right);
}
'@
Add-Type -TypeDefinition $cSharpCode -Language CSharp
# Create and use Point structs
$p1 = New-Object Point(10, 20)
$p2 = New-Object Point(10, 20)
$p3 = New-Object Point(5, 5)
Write-Host "Point 1: $p1"
Write-Host "Point 2: $p2"
Write-Host "Point 3: $p3"
if ($p1 -eq $p2) { Write-Host "P1 and P2 are equal." }
if ($p1 -ne $p3) { Write-Host "P1 and P3 are not equal." }
Leveraging External Tools
Sometimes the most efficient solution for a specific sub‑problem isn’t to write it in PowerShell or C#, but to call an existing, highly optimized external tool. PowerShell excels at orchestrating these tools, passing data between them, and integrating their output.
Example: Using WSL grep for Advanced Pattern Matching
# Assume input.txt contains:
# This is a test line.
# Another line with the word test.
# No match here.
# Find all lines containing "test"
$matchedLines = wsl.exe grep "test" "input.txt"
Write-Host "Lines containing 'test':"
$matchedLines | ForEach-Object { Write-Host $_ }
Example: Invoking a Custom Compiled Executable
# Create a dummy input file for the external tool
Set-Content -Path 'puzzle_map.txt' -Value @'
###########
#S........#
###.......#
#.........#
#.......E.#
###########
'@
# Run the external pathfinder.exe (takes a file path and returns the shortest path length)
$pathResult = & ".\pathfinder.exe" "puzzle_map.txt"
Write-Host "Pathfinder result: $pathResult"
# If the external tool outputs JSON, you can parse it:
# $jsonResult = & ".\myparser.exe" "data.json" | ConvertFrom-Json
# $value = $jsonResult.SomeProperty
Example: Piping Data to/from External Tools
PowerShell’s pipeline can interact with external processes, feeding data to their standard input and capturing their standard output.
# Simulate an external tool that counts characters (e.g., `wc -c` on Linux)
# For Windows we’ll use a simple Python script (counter.py):
# import sys
# print(sum(len(line) for line in sys.stdin))
$dataToSend = @(
"Line 1"
"Another Line"
"Last One"
)
# Pipe data to the Python script and capture its output
# Ensure python.exe is in your PATH or specify its full path
$charCount = $dataToSend | python.exe - ".\counter.py"
Write-Host "Total characters (excluding newlines): $charCount"
Choosing the Right Approach
| Feature / Approach | Pure PowerShell (Idiomatic) | C# Interop (Add-Type) | External Tools Orchestration |
|---|---|---|---|
| Readability & Maintainability | High (for PowerShell users) | Medium‑Low (mix of PowerShell & C#) | Medium (PowerShell orchestrates; external logic opaque) |
| Performance | Medium‑Low (interpreted, object overhead) | High (compiled C# runs at native speed) | Very High (leverages highly optimized external binaries) |
Selecting the appropriate method depends on the specific Advent of Code puzzle, your comfort level with the languages/tools, and the performance requirements. Use PowerShell as the glue, C# for hot‑path calculations, and external utilities when they provide a clear advantage.
Development Effort
- Low to Medium – familiar language, rapid prototyping.
- Medium to High – requires C# knowledge, debugging can be split.
- Medium – requires understanding external tool APIs, input/output.
Complexity Handled
- Good for most text processing, data manipulation, simpler algorithms.
- Excellent for complex algorithms, custom data structures, performance‑critical logic.
- Excellent for specific sub‑problems where an existing tool is a perfect fit.
Suitability for AoC
- Primary choice for majority of puzzles, especially Part 1.
- Ideal for Part 2 of puzzles where Part 1 solution is too slow.
- Niche for specific problems (e.g., heavy regex, specific graph algorithms if a tool exists).
Debugging Experience
- Excellent within PowerShell ISE/VS Code.
- Mixed – PowerShell debugger for script, C# logic often opaque within PowerShell.
- Mixed – PowerShell debugger for orchestration, external tool debugging separate.
👉 Read the original article on TechResolve.blog