mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-07 12:45:10 +02:00
day 10 part 2
This commit is contained in:
+147
-36
@@ -71,47 +71,31 @@ func pipeMaze(input string, part int) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to find which directions are connected to the initial cell
|
fillGridLocation(grid, r, c)
|
||||||
// could traverse along the four directions and see which two lead back to
|
|
||||||
// the start... all pipes only connect two coordinates so it's actually
|
|
||||||
// fairly easy to traverse without creating a huge search space
|
|
||||||
|
|
||||||
// note this soultion was overkill for part 1
|
// traverse entire loop to determine length
|
||||||
// inputs are nice and exactly two adjacent cells that connect to S
|
loopCoords := map[[2]int]bool{}
|
||||||
var loopCoords map[[2]int]bool
|
toVisit := [][2]int{
|
||||||
for pipeType := range pipes {
|
|
||||||
// assign the start square to a random pipeType, then see if it will loop
|
|
||||||
grid[r][c] = pipeType
|
|
||||||
|
|
||||||
seen := map[[2]int]bool{}
|
|
||||||
toAnalyze := [][2]int{
|
|
||||||
{r, c},
|
{r, c},
|
||||||
}
|
}
|
||||||
didLoop := false
|
for len(toVisit) > 0 {
|
||||||
for len(toAnalyze) > 0 {
|
coords := toVisit[0]
|
||||||
coords := toAnalyze[0]
|
if loopCoords[coords] {
|
||||||
if seen[coords] {
|
|
||||||
didLoop = true
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
seen[coords] = true
|
loopCoords[coords] = true
|
||||||
toAnalyze = toAnalyze[1:]
|
toVisit = toVisit[1:]
|
||||||
|
|
||||||
if diffs, ok := pipes[grid[coords[0]][coords[1]]]; ok {
|
// assumes loop is well formed, will cause a panic if not
|
||||||
|
diffs := pipes[grid[coords[0]][coords[1]]]
|
||||||
for _, diff := range diffs {
|
for _, diff := range diffs {
|
||||||
nextRow, nextCol := coords[0]+diff[0], coords[1]+diff[1]
|
nextRow, nextCol := coords[0]+diff[0], coords[1]+diff[1]
|
||||||
if isInRange(grid, nextRow, nextCol) && !seen[[2]int{nextRow, nextCol}] {
|
if isInRange(grid, nextRow, nextCol) && !loopCoords[[2]int{nextRow, nextCol}] {
|
||||||
toAnalyze = append(toAnalyze, [2]int{nextRow, nextCol})
|
toVisit = append(toVisit, [2]int{nextRow, nextCol})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if didLoop {
|
|
||||||
loopCoords = seen
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if part == 1 {
|
if part == 1 {
|
||||||
return len(loopCoords) / 2
|
return len(loopCoords) / 2
|
||||||
@@ -119,26 +103,153 @@ func pipeMaze(input string, part int) int {
|
|||||||
|
|
||||||
// part 2
|
// part 2
|
||||||
|
|
||||||
newGrid := make([][]string, len(grid))
|
// create copy of grid with all non-loop spots replaced with a period
|
||||||
|
reducedGrid := make([][]string, len(grid))
|
||||||
for i := 0; i < len(grid); i++ {
|
for i := 0; i < len(grid); i++ {
|
||||||
for j := 0; j < len(grid[0]); j++ {
|
for j := 0; j < len(grid[0]); j++ {
|
||||||
if loopCoords[[2]int{i, j}] {
|
if loopCoords[[2]int{i, j}] {
|
||||||
newGrid[i] = append(newGrid[i], grid[i][j])
|
reducedGrid[i] = append(reducedGrid[i], grid[i][j])
|
||||||
} else {
|
} else {
|
||||||
newGrid[i] = append(newGrid[i], ".")
|
reducedGrid[i] = append(reducedGrid[i], ".")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range newGrid {
|
// expand grid to double plus 2 in both dimensions to account for squeezing between pipes
|
||||||
fmt.Println(r)
|
// the plus two is to add an empty row/column on each side for easier traversing from the outside
|
||||||
|
expandedGrid := [][]string{}
|
||||||
|
expandedGrid = append(expandedGrid, make([]string, len(reducedGrid[0])*2+2))
|
||||||
|
|
||||||
|
for r, rows := range reducedGrid {
|
||||||
|
expandedGrid = append(expandedGrid, make([]string, len(reducedGrid[0])*2+2))
|
||||||
|
for c, val := range rows {
|
||||||
|
expandedGrid[r*2+1][c*2+1] = val
|
||||||
|
}
|
||||||
|
// empty row
|
||||||
|
expandedGrid = append(expandedGrid, make([]string, len(reducedGrid[0])*2+2))
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
// fill gaps between loop coords so we have an encased area again
|
||||||
|
// we can naively try to fill in every empty spot because only ones with two valid connecting
|
||||||
|
// pipes will be filled
|
||||||
|
for r, rows := range expandedGrid {
|
||||||
|
for c, val := range rows {
|
||||||
|
if val == "" {
|
||||||
|
fillGridLocation(expandedGrid, r, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replacing empty strings with spaces makes the printout human readable
|
||||||
|
for r, rows := range expandedGrid {
|
||||||
|
for c, val := range rows {
|
||||||
|
if val == "" {
|
||||||
|
expandedGrid[r][c] = " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toVisit = [][2]int{
|
||||||
|
{0, 0},
|
||||||
|
}
|
||||||
|
seen := map[[2]int]bool{}
|
||||||
|
for len(toVisit) > 0 {
|
||||||
|
coords := toVisit[0]
|
||||||
|
toVisit = toVisit[1:]
|
||||||
|
if seen[coords] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[coords] = true
|
||||||
|
|
||||||
|
// delete reachable dots
|
||||||
|
if expandedGrid[coords[0]][coords[1]] == "." {
|
||||||
|
expandedGrid[coords[0]][coords[1]] = " "
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, diff := range [][2]int{
|
||||||
|
{-1, 0},
|
||||||
|
{1, 0},
|
||||||
|
{0, -1},
|
||||||
|
{0, 1},
|
||||||
|
} {
|
||||||
|
nextRow := coords[0] + diff[0]
|
||||||
|
nextCol := coords[1] + diff[1]
|
||||||
|
if isInRange(expandedGrid, nextRow, nextCol) {
|
||||||
|
if expandedGrid[nextRow][nextCol] == "." || expandedGrid[nextRow][nextCol] == " " {
|
||||||
|
toVisit = append(toVisit, [2]int{nextRow, nextCol})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// count remaining dots
|
||||||
|
var ans int
|
||||||
|
for _, rows := range expandedGrid {
|
||||||
|
for _, val := range rows {
|
||||||
|
if val == "." {
|
||||||
|
ans++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for _, rows := range expandedGrid {
|
||||||
|
// fmt.Println(rows)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillGridLocation(grid [][]string, r, c int) {
|
||||||
|
// inputs are nice and exactly two adjacent cells that connect to S
|
||||||
|
// check four directions from start
|
||||||
|
leftCol := c - 1
|
||||||
|
rightCol := c + 1
|
||||||
|
upRow := r - 1
|
||||||
|
downRow := r + 1
|
||||||
|
|
||||||
|
var combinedString string
|
||||||
|
// check left for inRange and possible valid pipe types
|
||||||
|
if isInRange(grid, r, leftCol) &&
|
||||||
|
(grid[r][leftCol] == "-" || grid[r][leftCol] == "L" || grid[r][leftCol] == "F") {
|
||||||
|
combinedString += "left"
|
||||||
|
}
|
||||||
|
// right
|
||||||
|
if isInRange(grid, r, rightCol) &&
|
||||||
|
(grid[r][rightCol] == "-" || grid[r][rightCol] == "J" || grid[r][rightCol] == "7") {
|
||||||
|
combinedString += "right"
|
||||||
|
}
|
||||||
|
// up
|
||||||
|
if isInRange(grid, upRow, c) &&
|
||||||
|
(grid[upRow][c] == "|" || grid[upRow][c] == "7" || grid[upRow][c] == "F") {
|
||||||
|
combinedString += "up"
|
||||||
|
}
|
||||||
|
if isInRange(grid, downRow, c) &&
|
||||||
|
(grid[downRow][c] == "|" || grid[downRow][c] == "J" || grid[downRow][c] == "L") {
|
||||||
|
combinedString += "down"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch combinedString {
|
||||||
|
case "leftup":
|
||||||
|
grid[r][c] = "J"
|
||||||
|
case "leftdown":
|
||||||
|
grid[r][c] = "7"
|
||||||
|
case "rightup":
|
||||||
|
grid[r][c] = "L"
|
||||||
|
case "rightdown":
|
||||||
|
grid[r][c] = "F"
|
||||||
|
case "leftright":
|
||||||
|
grid[r][c] = "-"
|
||||||
|
case "updown":
|
||||||
|
grid[r][c] = "|"
|
||||||
|
// default:
|
||||||
|
// do not panic so we can use this function more naively for the expanded grid
|
||||||
|
// could return an error instead and choose to check it for part1 where we NEED it to find a result
|
||||||
|
// panic("ineligible configuration: " + combinedString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isInRange(grid [][]string, row, col int) bool {
|
func isInRange(grid [][]string, row, col int) bool {
|
||||||
return row >= 0 && row < len(grid) && col >= 0 && col <= len(grid)
|
return row >= 0 && row < len(grid) && col >= 0 && col < len(grid[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseInput(input string) (ans [][]string) {
|
func parseInput(input string) (ans [][]string) {
|
||||||
|
|||||||
@@ -106,12 +106,12 @@ func Test_pipeMaze(t *testing.T) {
|
|||||||
part: 2,
|
part: 2,
|
||||||
want: 10,
|
want: 10,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// name: "actual part 2",
|
name: "actual part 2",
|
||||||
// input: input,
|
input: input,
|
||||||
// part: 2,
|
part: 2,
|
||||||
// want: 0,
|
want: 493,
|
||||||
// },
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user