diff --git a/day24/common/blizzard.go b/day24/common/blizzard.go index ab5af2c..0fdb551 100644 --- a/day24/common/blizzard.go +++ b/day24/common/blizzard.go @@ -22,6 +22,7 @@ type Map struct { height int width int cache [][][]int + bestDistance int } func (tileMap *Map) InitCache() { @@ -35,6 +36,7 @@ func (tileMap *Map) InitCache() { } } } + tileMap.bestDistance = math.MaxInt32 } func (tileMap *Map) GetDistanceToEnd(currentSteps int) int { @@ -48,8 +50,6 @@ func (tileMap *Map) GetDistanceToEnd(currentSteps int) int { break } } - tileMap.cache[startSteps][0][startCol] = currentSteps - tileMap.PropagateDistanceFromTile(startSteps, startCol, 0, currentSteps) endCol := 0 for i := 0; i < tileMap.width; i++ { @@ -59,13 +59,10 @@ func (tileMap *Map) GetDistanceToEnd(currentSteps int) int { } } - minDistance := math.MaxInt32 - for i := 0; i < tileMap.steps; i++ { - if tileMap.cache[i][len(tileMap.tiles[0])-1][endCol] < minDistance { - minDistance = tileMap.cache[i][len(tileMap.tiles[0])-1][endCol] - } - } - return minDistance + tileMap.cache[startSteps][0][startCol] = currentSteps + tileMap.PropagateDistanceFromTile(startSteps, startCol, 0, currentSteps, endCol, len(tileMap.tiles[startSteps])-1) + + return tileMap.bestDistance } func (tileMap *Map) GetDistanceToStart(currentSteps int) int { @@ -79,8 +76,6 @@ func (tileMap *Map) GetDistanceToStart(currentSteps int) int { break } } - tileMap.cache[startSteps][len(tileMap.tiles[startSteps])-1][endCol] = currentSteps - tileMap.PropagateDistanceFromTile(startSteps, endCol, len(tileMap.tiles[startSteps])-1, currentSteps) startCol := 0 for i := 0; i < tileMap.width; i++ { @@ -90,37 +85,61 @@ func (tileMap *Map) GetDistanceToStart(currentSteps int) int { } } - minDistance := math.MaxInt32 - for i := 0; i < tileMap.steps; i++ { - if tileMap.cache[i][0][startCol] < minDistance { - minDistance = tileMap.cache[i][0][startCol] - } - } - return minDistance + tileMap.cache[startSteps][len(tileMap.tiles[startSteps])-1][endCol] = currentSteps + tileMap.PropagateDistanceFromTile(startSteps, endCol, len(tileMap.tiles[startSteps])-1, currentSteps, startCol, 0) + + return tileMap.bestDistance } -func (tileMap *Map) PropagateDistanceFromTile(step, x, y, currentDistance int) { +func (tileMap *Map) PropagateDistanceFromTile(step, x, y, currentDistance, targetX, targetY int) { nextStep := (step + 1) % tileMap.steps + orders := []byte{0, 1, 2, 3, 4} + distances := []int{(x-targetX)*(x-targetX)+(y+1-targetY)*(y+1-targetY), + (x+1-targetX)*(x+1-targetX)+(y-targetY)*(y-targetY), + (x-targetX)*(x-targetX)+(y-targetY)*(y-targetY), + (x-1-targetX)*(x-1-targetX)+(y-targetY)*(y-targetY), + (x-targetX)*(x-targetX)+(y-1-targetY)*(y-1-targetY)} - if x > 0 && tileMap.tiles[nextStep][y][x-1] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x-1] { - tileMap.cache[nextStep][y][x-1] = currentDistance + 1 - tileMap.PropagateDistanceFromTile(nextStep, x-1, y, currentDistance+1) + if currentDistance >= tileMap.bestDistance { + return } - if x < tileMap.width - 1 && tileMap.tiles[nextStep][y][x+1] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x+1] { - tileMap.cache[nextStep][y][x+1] = currentDistance + 1 - tileMap.PropagateDistanceFromTile(nextStep, x+1, y, currentDistance+1) + + if x == targetX && y == targetY { + tileMap.bestDistance = currentDistance } - if y > 0 && tileMap.tiles[nextStep][y-1][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y-1][x] { - tileMap.cache[nextStep][y-1][x] = currentDistance + 1 - tileMap.PropagateDistanceFromTile(nextStep, x, y-1, currentDistance+1) + + sorted := false + for !sorted { + sorted = true + for i := 0; i < 4; i++ { + if distances[orders[i]] > distances[orders[i+1]] { + orders[i], orders[i+1] = orders[i+1], orders[i] + sorted = false + } + } } - if y < tileMap.height - 1 && tileMap.tiles[nextStep][y+1][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y+1][x] { - tileMap.cache[nextStep][y+1][x] = currentDistance + 1 - tileMap.PropagateDistanceFromTile(nextStep, x, y+1, currentDistance+1) - } - if tileMap.tiles[nextStep][y][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x] { - tileMap.cache[nextStep][y][x] = currentDistance + 1 - tileMap.PropagateDistanceFromTile(nextStep, x, y, currentDistance+1) + + for _, order := range orders { + if order == 0 && y < tileMap.height - 1 && tileMap.tiles[nextStep][y+1][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y+1][x] { + tileMap.cache[nextStep][y+1][x] = currentDistance + 1 + tileMap.PropagateDistanceFromTile(nextStep, x, y+1, currentDistance+1, targetX, targetY) + } + if order == 1 && x < tileMap.width - 1 && tileMap.tiles[nextStep][y][x+1] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x+1] { + tileMap.cache[nextStep][y][x+1] = currentDistance + 1 + tileMap.PropagateDistanceFromTile(nextStep, x+1, y, currentDistance+1, targetX, targetY) + } + if order == 2 && tileMap.tiles[nextStep][y][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x] { + tileMap.cache[nextStep][y][x] = currentDistance + 1 + tileMap.PropagateDistanceFromTile(nextStep, x, y, currentDistance+1, targetX, targetY) + } + if order == 3 && x > 0 && tileMap.tiles[nextStep][y][x-1] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y][x-1] { + tileMap.cache[nextStep][y][x-1] = currentDistance + 1 + tileMap.PropagateDistanceFromTile(nextStep, x-1, y, currentDistance+1, targetX, targetY) + } + if order == 4 && y > 0 && tileMap.tiles[nextStep][y-1][x] == Empty && currentDistance + 1 < tileMap.cache[nextStep][y-1][x] { + tileMap.cache[nextStep][y-1][x] = currentDistance + 1 + tileMap.PropagateDistanceFromTile(nextStep, x, y-1, currentDistance+1, targetX, targetY) + } } }