day 10 part 2

This commit is contained in:
alexchao26
2024-07-30 12:52:48 -04:00
parent 68b2419b13
commit dab6f914da
2 changed files with 161 additions and 50 deletions
+155 -44
View File
@@ -71,46 +71,30 @@ func pipeMaze(input string, part int) int {
}
}
// need to find which directions are connected to the initial cell
// 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
fillGridLocation(grid, r, c)
// note this soultion was overkill for part 1
// inputs are nice and exactly two adjacent cells that connect to S
var loopCoords map[[2]int]bool
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},
}
didLoop := false
for len(toAnalyze) > 0 {
coords := toAnalyze[0]
if seen[coords] {
didLoop = true
break
}
seen[coords] = true
toAnalyze = toAnalyze[1:]
if diffs, ok := pipes[grid[coords[0]][coords[1]]]; ok {
for _, diff := range diffs {
nextRow, nextCol := coords[0]+diff[0], coords[1]+diff[1]
if isInRange(grid, nextRow, nextCol) && !seen[[2]int{nextRow, nextCol}] {
toAnalyze = append(toAnalyze, [2]int{nextRow, nextCol})
}
}
}
}
if didLoop {
loopCoords = seen
// traverse entire loop to determine length
loopCoords := map[[2]int]bool{}
toVisit := [][2]int{
{r, c},
}
for len(toVisit) > 0 {
coords := toVisit[0]
if loopCoords[coords] {
break
}
loopCoords[coords] = true
toVisit = toVisit[1:]
// assumes loop is well formed, will cause a panic if not
diffs := pipes[grid[coords[0]][coords[1]]]
for _, diff := range diffs {
nextRow, nextCol := coords[0]+diff[0], coords[1]+diff[1]
if isInRange(grid, nextRow, nextCol) && !loopCoords[[2]int{nextRow, nextCol}] {
toVisit = append(toVisit, [2]int{nextRow, nextCol})
}
}
}
if part == 1 {
@@ -119,26 +103,153 @@ func pipeMaze(input string, part int) int {
// 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 j := 0; j < len(grid[0]); j++ {
if loopCoords[[2]int{i, j}] {
newGrid[i] = append(newGrid[i], grid[i][j])
reducedGrid[i] = append(reducedGrid[i], grid[i][j])
} else {
newGrid[i] = append(newGrid[i], ".")
reducedGrid[i] = append(reducedGrid[i], ".")
}
}
}
for _, r := range newGrid {
fmt.Println(r)
// expand grid to double plus 2 in both dimensions to account for squeezing between pipes
// 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 {
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) {
+6 -6
View File
@@ -106,12 +106,12 @@ func Test_pipeMaze(t *testing.T) {
part: 2,
want: 10,
},
// {
// name: "actual part 2",
// input: input,
// part: 2,
// want: 0,
// },
{
name: "actual part 2",
input: input,
part: 2,
want: 493,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {