patternshellMinor
Advent of Code Day 6: toggling lights in a grid with Powershell
Viewed 0 times
adventgridwithtogglingpowershelllightscodeday
Problem
I am using the "Advent of Code" series to help with my PowerShell education. The Day 6 puzzle has a 1000 × 1000 grid of lights. After processing instructions to turn on, turn off, or toggle rectangles of lights in the grid, how many lights are on at the end?
I am confident that this script will produce the right answer. However, it is going way too slow. I am interested in optimizing this script for performance. I am not against coming up with an alternative way to solve this problem with PowerShell.
``
}
if ($string -like "turn off*"){
write-host "turn off"
while ($x -le $maxX){
while ($y -le $maxY){
$light = "$x,$y"
if ($light -in $lightson){
[void]$lightson.Remove("$x,$y")
#write-host $lightson.Count
}
$y +=1
}
$x += 1
$y = $miny
}
write-host $lightson.Count "
I am confident that this script will produce the right answer. However, it is going way too slow. I am interested in optimizing this script for performance. I am not against coming up with an alternative way to solve this problem with PowerShell.
``
$lightson = New-Object Collections.Generic.HashSet[string]
$strings = Get-Content C:\test\lights.txt
foreach ($string in $strings){
$numbers = [regex]::matches($string,"\d+")
$minX = [convert]::ToInt32($numbers[0],10)
$minY = [convert]::ToInt32($numbers[1],10)
$maxX = [convert]::ToInt32($numbers[2],10)
$maxY = [convert]::ToInt32($numbers[3],10)
$x = $minX
$y = $miny
write-host $string
write-host $x $y
if ($string -like "turn on*"){
write-host "turn on"
while ($x -le $maxX){
while ($y -le $maxY){
$light = "$x,$y"
if ($light -notin $lightson){
[void]$lightson.Add("$x,$y")
#write-host $lightson.Count
}
$y +=1
}
$x += 1
$y = $miny
}
write-host $lightson.Count "n"}
if ($string -like "turn off*"){
write-host "turn off"
while ($x -le $maxX){
while ($y -le $maxY){
$light = "$x,$y"
if ($light -in $lightson){
[void]$lightson.Remove("$x,$y")
#write-host $lightson.Count
}
$y +=1
}
$x += 1
$y = $miny
}
write-host $lightson.Count "
n"
}
if ($string -like "toggle*"){
write-host "togglen"Solution
I assume the
When you add a light to the list, you don't need to check if it's already in the list.
You will also no longer need
When toggling a light, you can again use the return value of
Every loop of
For slightly less verbose loops, you could change
I entered the number into the website you linked, and your algorithm did give the correct answer.
Write-Host commands are to view progress/status of the script? I would remove these if you are confident the script is reliable and accurate. Maybe one status (write-host $lightson.Count) after every instruction line.When you add a light to the list, you don't need to check if it's already in the list.
Add will return True/False for its success. Either way, you won't need to check before or after. Just know that if it was on the list already, it will simply return False and carry on. Likewise when removing it from the list.while ($x -le $maxX){
while ($y -le $maxY){
$light = "$x,$y"
[void]$lightson.Add("$x,$y")
$y +=1
}
$x += 1
$y = $miny
}You will also no longer need
$light.When toggling a light, you can again use the return value of
Add or Remove:while ($x -le $maxX){
while ($y -le $maxY){
If ($lightson.Remove("$x,$y")) { }
Else {[void]$lightson.Add("$x,$y")}
$y +=1
}
$x += 1
$y = $miny
}Every loop of
ForEach is evaluating all three If conditions. You can combine these into an If/ElseIf/ElseIf so subsequent conditions are not evaluated when the first has already succeeded.For slightly less verbose loops, you could change
While loops to For loops. This didn't make a large difference in times though.I entered the number into the website you linked, and your algorithm did give the correct answer.
$lightson = New-Object Collections.Generic.HashSet[string]
$strings = Get-Content C:\test\lights.txt
foreach ($string in $strings){
$numbers = [regex]::matches($string,"\d+")
$minX = [convert]::ToInt32($numbers[0],10)
$minY = [convert]::ToInt32($numbers[1],10)
$maxX = [convert]::ToInt32($numbers[2],10)
$maxY = [convert]::ToInt32($numbers[3],10)
if ($string -like "turn on*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
[void]$lightson.Add("$x,$y")
}
}
} ElseIf ($string -like "turn off*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
[void]$lightson.Remove("$x,$y")
}
}
} ElseIf ($string -like "toggle*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
If ($lightson.Remove("$x,$y")) { }
Else {[void]$lightson.Add("$x,$y")}
}
}
}
write-host $lightson.Count
}Code Snippets
while ($x -le $maxX){
while ($y -le $maxY){
$light = "$x,$y"
[void]$lightson.Add("$x,$y")
$y +=1
}
$x += 1
$y = $miny
}while ($x -le $maxX){
while ($y -le $maxY){
If ($lightson.Remove("$x,$y")) { }
Else {[void]$lightson.Add("$x,$y")}
$y +=1
}
$x += 1
$y = $miny
}$lightson = New-Object Collections.Generic.HashSet[string]
$strings = Get-Content C:\test\lights.txt
foreach ($string in $strings){
$numbers = [regex]::matches($string,"\d+")
$minX = [convert]::ToInt32($numbers[0],10)
$minY = [convert]::ToInt32($numbers[1],10)
$maxX = [convert]::ToInt32($numbers[2],10)
$maxY = [convert]::ToInt32($numbers[3],10)
if ($string -like "turn on*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
[void]$lightson.Add("$x,$y")
}
}
} ElseIf ($string -like "turn off*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
[void]$lightson.Remove("$x,$y")
}
}
} ElseIf ($string -like "toggle*"){
For ($x = $minX; $x -le $maxX; $x++) {
For ($y = $minY; $y -le $maxY; $y++) {
If ($lightson.Remove("$x,$y")) { }
Else {[void]$lightson.Add("$x,$y")}
}
}
}
write-host $lightson.Count
}Context
StackExchange Code Review Q#126796, answer score: 3
Revisions (0)
No revisions yet.