From 0dc1aeebedd56a09f1bb0318267d357ae827aef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Mon, 16 Dec 2024 18:27:54 +0100 Subject: [PATCH] Day 15. part 2. --- day_15/solution.go | 207 +++++++++++++++++++++++++++++++++++++++- day_15/solution_test.go | 2 +- 2 files changed, 203 insertions(+), 6 deletions(-) diff --git a/day_15/solution.go b/day_15/solution.go index 0f201e3..2f76393 100644 --- a/day_15/solution.go +++ b/day_15/solution.go @@ -1,15 +1,20 @@ package day_15 import ( + "fmt" + "slices" "strings" ) const ( - Wall = '#' - Player = '@' - Box = 'O' - Empty = '.' + Wall = '#' + Player = '@' + Box = 'O' + Empty = '.' + WideBoxL = '[' + WideBoxR = ']' ) + const ( InstUp = '^' InstDown = 'v' @@ -19,6 +24,12 @@ const ( type Warehouse [][]rune +func (w Warehouse) Print() { + for _, line := range w { + fmt.Println(string(line)) + } +} + func (w Warehouse) At(x, y int) rune { if x < 0 || y < 0 || x >= len(w[0]) || y >= len(w) { return Wall @@ -57,7 +68,31 @@ func SolveBasic(input string) int { // task:https://adventofcode.com/2024/day/12#part2 func SolveComplex(input string) int { - return 0 + warehouse, instructions, rX, rY := loadWide(input) + + for _, instr := range instructions { + switch instr { + case InstUp: + rX, rY = moveWideUp(warehouse, rX, rY) + case InstDown: + rX, rY = moveWideDown(warehouse, rX, rY) + case InstLeft: + rX, rY = moveWideLeft(warehouse, rX, rY) + case InstRight: + rX, rY = moveWideRight(warehouse, rX, rY) + default: + panic("unknown instruction " + string(instr)) + } + } + sum := 0 + for y, line := range warehouse { + for x, val := range line { + if val == WideBoxL { + sum += y*100 + x + } + } + } + return sum } func load(input string) (Warehouse, []rune, int, int) { @@ -77,6 +112,32 @@ func load(input string) (Warehouse, []rune, int, int) { return warehouse, instructions, rX, rY } +func loadWide(input string) (Warehouse, []rune, int, int) { + substrings := strings.Split(input, "\n\n") + warehouse := Warehouse{} + rX := 0 + rY := 0 + for y, line := range strings.Split(substrings[0], "\n") { + line = expandLine(line) + if strings.ContainsRune(line, Player) { + rY = y + rX = strings.IndexRune(line, Player) + } + warehouse = append(warehouse, []rune(line)) + } + instructions := []rune(strings.ReplaceAll(substrings[1], "\n", "")) + + return warehouse, instructions, rX, rY +} + +func expandLine(line string) string { + line = strings.ReplaceAll(line, "#", "##") + line = strings.ReplaceAll(line, ".", "..") + line = strings.ReplaceAll(line, "@", "@.") + line = strings.ReplaceAll(line, "O", "[]") + return line +} + func moveUp(warehouse Warehouse, x int, y int) (int, int) { if warehouse.At(x, y-1) == Wall { return x, y @@ -160,3 +221,139 @@ func moveRight(warehouse Warehouse, x int, y int) (int, int) { } return x, y } + +func moveWideUp(warehouse Warehouse, x int, y int) (int, int) { + if warehouse.At(x, y-1) == Wall { + return x, y + } else if warehouse.At(x, y-1) == Empty { + warehouse[y][x] = Empty + warehouse[y-1][x] = Player + return x, y - 1 + } else { + type Point struct { + x, y int + } + checkable := []Point{{x, y}} + + for i := 0; i < len(checkable); i++ { + p := checkable[i] + l := warehouse.At(p.x, p.y-1) + if l == Wall { + return x, y + } + if l == WideBoxL { + if !slices.Contains(checkable, Point{p.x, p.y - 1}) { + checkable = append(checkable, Point{p.x, p.y - 1}) + } + if !slices.Contains(checkable, Point{p.x + 1, p.y - 1}) { + checkable = append(checkable, Point{p.x + 1, p.y - 1}) + } + } + if l == WideBoxR { + if !slices.Contains(checkable, Point{p.x, p.y - 1}) { + checkable = append(checkable, Point{p.x, p.y - 1}) + } + if !slices.Contains(checkable, Point{p.x - 1, p.y - 1}) { + checkable = append(checkable, Point{p.x - 1, p.y - 1}) + } + } + } + for i := len(checkable) - 1; i >= 0; i-- { + p := checkable[i] + warehouse[p.y-1][p.x] = warehouse[p.y][p.x] + warehouse[p.y][p.x] = Empty + } + return x, y - 1 + } +} + +func moveWideDown(warehouse Warehouse, x int, y int) (int, int) { + if warehouse.At(x, y+1) == Wall { + return x, y + } else if warehouse.At(x, y+1) == Empty { + warehouse[y][x] = Empty + warehouse[y+1][x] = Player + return x, y + 1 + } else { + type Point struct { + x, y int + } + checkable := []Point{{x, y}} + + for i := 0; i < len(checkable); i++ { + p := checkable[i] + l := warehouse.At(p.x, p.y+1) + if l == Wall { + return x, y + } + if l == WideBoxL { + if !slices.Contains(checkable, Point{p.x, p.y + 1}) { + checkable = append(checkable, Point{p.x, p.y + 1}) + } + if !slices.Contains(checkable, Point{p.x + 1, p.y + 1}) { + checkable = append(checkable, Point{p.x + 1, p.y + 1}) + } + } + if l == WideBoxR { + if !slices.Contains(checkable, Point{p.x, p.y + 1}) { + checkable = append(checkable, Point{p.x, p.y + 1}) + } + if !slices.Contains(checkable, Point{p.x - 1, p.y + 1}) { + checkable = append(checkable, Point{p.x - 1, p.y + 1}) + } + } + } + for i := len(checkable) - 1; i >= 0; i-- { + p := checkable[i] + warehouse[p.y+1][p.x] = warehouse[p.y][p.x] + warehouse[p.y][p.x] = Empty + } + return x, y + 1 + } +} + +func moveWideLeft(warehouse Warehouse, x int, y int) (int, int) { + if warehouse.At(x-1, y) == Wall { + return x, y + } else if warehouse.At(x-1, y) == Empty { + warehouse[y][x] = Empty + warehouse[y][x-1] = Player + return x - 1, y + } else { + newX := x - 1 + for ; warehouse.At(newX, y) == WideBoxL || warehouse.At(newX, y) == WideBoxR; newX-- { + } + if warehouse.At(newX, y) == Empty { + for tx := newX; tx < x-1; tx++ { + warehouse[y][tx] = warehouse[y][tx+1] + } + warehouse[y][x-1] = Player + warehouse[y][x] = Empty + return x - 1, y + } + } + return x, y +} + +func moveWideRight(warehouse Warehouse, x int, y int) (int, int) { + if warehouse.At(x+1, y) == Wall { + return x, y + } else if warehouse.At(x+1, y) == Empty { + warehouse[y][x] = Empty + warehouse[y][x+1] = Player + return x + 1, y + } else { + newX := x + 1 + for ; warehouse.At(newX, y) == WideBoxL || warehouse.At(newX, y) == WideBoxR; newX++ { + } + if warehouse.At(newX, y) == Empty { + for tx := newX; tx > x+1; tx-- { + warehouse[y][tx] = warehouse[y][tx-1] + } + warehouse[y][x+1] = Player + warehouse[y][x] = Empty + return x + 1, y + } + } + return x, y +} diff --git a/day_15/solution_test.go b/day_15/solution_test.go index a96bc76..23e6ec7 100644 --- a/day_15/solution_test.go +++ b/day_15/solution_test.go @@ -22,5 +22,5 @@ func TestBasicSolutionExample01(t *testing.T) { } func TestComplexSolutionExample(t *testing.T) { - helpers.Check(t, day_15.SolveComplex, helpers.Format(ExampleData), 0) + helpers.Check(t, day_15.SolveComplex, helpers.Format(ExampleData01), 9021) }