해결: PowerShell로 Advent of Code 하는 사람?
Source: Dev.to
죄송합니다만, 해당 URL에 있는 전체 글 내용을 직접 가져올 수 없습니다. 번역이 필요한 텍스트를 여기 채팅창에 복사해 주시면, 요청하신 대로 한국어로 번역해 드리겠습니다.
Executive Summary
TL;DR: PowerShell에서 Advent of Code (AoC)를 해결하는 것은 입력 파싱이 장황하고 복잡한 알고리즘에서 성능 병목이 발생하는 등 여러 어려움이 있습니다.
해결 방안은:
- 관용적인 PowerShell 파이프라인 및 .NET 통합 활용.
- 핵심 부분에 C# 인터옵을 사용해 속도 향상.
- 외부 고성능 유틸리티를 오케스트레이션.
왜 관용적인 PowerShell을 사용해야 할까?
- 객체‑지향 파이프라인 – cmdlet을 연결하고, 객체를 전달하며, 코드를 읽기 쉽게 유지합니다.
- 내장 cmdlet – 강력한 문자열 조작, 정규식, 파일 처리 기능을 제공합니다.
- 직접 .NET 호출 – cmdlet만으로는 부족할 때 언제든지 .NET 타입에 접근할 수 있습니다.
많은 AoC 퍼즐에서 이 접근 방식은 자연스럽고, 읽기 쉬우며, 충분합니다.
PowerShell이 성능 장벽에 부딪힐 때
- 대용량 데이터 세트, 깊은 재귀, 혹은 집중적인 시뮬레이션은 PowerShell 스크립트가 초가 아니라 분 단위로 실행되게 만들 수 있습니다.
- 고급 데이터 구조(우선순위 큐, 사용자 정의 그래프, 불변 컬렉션)는 순수 PowerShell에서 효율적으로 구현하기 번거롭습니다.
- 알고리즘 기본 요소 부족 – PowerShell은 Python이나 C#에서 제공되는 풍부한 표준‑라이브러리 도구가 없습니다.
해결책: C# interop(Add-Type)을 사용해 핵심 경로 코드를 구현한 뒤, PowerShell에서 컴파일된 클래스를 호출합니다.
외부 도구 오케스트레이션
PowerShell는 “접착제” 역할을 하며:
- 입력을 준비합니다.
- 외부의 고성능 바이너리(e.g.,
grep, custom C/C++ tools)를 실행합니다. - 출력물을 PowerShell 객체로 다시 처리합니다.
실용적인 PowerShell 패턴
1. 구분된 입력 파일에서 숫자 합산
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. 그리드 / 매트릭스 작업
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. 성능 및 유연성을 위한 .NET 컬렉션 사용
# 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# 인터롭 for Hot‑Path 코드
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"
성능이 중요한 알고리즘을 C#로 작성하고 Add-Type으로 컴파일한 뒤, 일반 PowerShell 메서드처럼 호출합니다.
Source: …
모두 합쳐 보기
- 시작 – 구문 분석 및 오케스트레이션을 위해 관용적인 PowerShell을 사용합니다.
- 병목 현상 식별 –
Measure-Command또는 프로파일링을 활용합니다. - 핫‑패스 섹션 교체 – C# 인터옵 또는 외부 도구로 대체합니다.
- 스크립트 가독성 및 유지보수성 유지 – 인터옵 노출을 최소화합니다.
최종 생각
- Advent of Code는 PowerShell의 강점과 한계를 탐구하기에 훌륭한 놀이터입니다.
- 파이프라인 중심 스크립팅, .NET 파워, C# 인터옵, 그리고 외부 유틸리티를 결합하면 가장 까다로운 AoC 퍼즐도 효율적으로 해결하면서 PowerShell이 뛰어난 자동화 언어가 되는 명료성을 유지할 수 있습니다.
C#에서 빠른 피보나치 수열 계산
우리는 정적 메서드를 사용하여 N번째 피보나치 수를 빠르게 계산하는 C# 클래스를 정의할 것입니다.
$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." }
외부 도구 활용
특정 하위 문제에 가장 효율적인 해결책이 PowerShell이나 C#로 직접 구현하는 것이 아니라, 이미 존재하고 고도로 최적화된 외부 도구를 호출하는 경우가 있습니다. PowerShell은 이러한 도구들을 조정하고, 데이터 흐름을 연결하며, 결과를 통합하는 데 뛰어납니다.
예시: 고급 패턴 매칭을 위한 WSL grep 사용
# 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 $_ }
예시: 사용자 정의 컴파일 실행 파일 호출
# 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
예시: 외부 도구와 데이터 파이프라인 연결
PowerShell 파이프라인은 외부 프로세스와 상호 작용하여 데이터를 표준 입력으로 전달하고 표준 출력을 캡처할 수 있습니다.
# 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"
올바른 접근 방식 선택
| 기능 / 접근 방식 | 순수 PowerShell (관용적) | C# 인터옵 (Add-Type) | 외부 도구 오케스트레이션 |
|---|---|---|---|
| 가독성 및 유지보수성 | 높음 (PowerShell 사용자에게) | 중간‑낮음 (PowerShell과 C# 혼합) | 중간 (PowerShell이 오케스트레이션; 외부 로직은 불투명) |
| 성능 | 중간‑낮음 (인터프리터, 객체 오버헤드) | 높음 (컴파일된 C#가 네이티브 속도로 실행) | 매우 높음 (고도로 최적화된 외부 바이너리 활용) |
적절한 방법 선택은 특정 Advent of Code 퍼즐, 사용자의 편안함 수준, 그리고 성능 요구 사항에 따라 달라집니다. PowerShell을 접착제로 사용하고, C#를 핵심 경로 계산에 활용하며, 외부 유틸리티가 명확한 이점을 제공할 때 이를 이용하십시오.
개발 노력
- Low to Medium – 익숙한 언어, 빠른 프로토타이핑.
- Medium to High – C# 지식이 필요하고, 디버깅을 분할할 수 있음.
- Medium – 외부 도구 API와 입출력 이해가 필요함.
복잡도 처리
- 대부분의 텍스트 처리, 데이터 조작, 단순 알고리즘에 적합합니다.
- 복잡한 알고리즘, 맞춤형 데이터 구조, 성능이 중요한 로직에 탁월합니다.
- 기존 도구가 완벽히 맞는 특정 하위 문제에 탁월합니다.
AoC 적합성
- 대다수 퍼즐, 특히 Part 1에 대한 기본 선택.
- Part 1 솔루션이 너무 느린 경우 Part 2에 이상적.
- 특정 문제에 특화된 틈새(예: 복잡한 정규식, 도구가 존재한다면 특정 그래프 알고리즘).
디버깅 경험
- Excellent PowerShell ISE/VS Code 내에서 우수.
- Mixed – 스크립트용 PowerShell 디버거, PowerShell 내에서 C# 로직은 종종 불투명.
- Mixed – 오케스트레이션용 PowerShell 디버거, 외부 도구 디버깅은 별도.
👉 원문 기사를 읽어보세요 TechResolve.blog