diff --git a/README.md b/README.md index 55ae363..15150ae 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ go test ./cmd/01 | 01 | [Problem](https://adventofcode.com/2025/day/1) | [Solution](./cmd/01/) | Part 1 seemed straight forward enough. Part 2 completely stumped me. The trickiest part was not counting zero's twice when you ended and then started from there. | | 02 | [Problem](https://adventofcode.com/2025/day/2) | [Solution](./cmd/02/) | Part 1 should have been super straight-forward, but some whitespace screwed up my parsing of the final range. I some how was able to stumble over a solution to part 2 rather blindly. | | 03 | [Problem](https://adventofcode.com/2025/day/3) | [Solution](./cmd/03/) | Part 1 intuitively makes you think you only care about highest nums, but then you need to consider placement. I once again tripped over the solution using a stack. However chat morally supported me the whole time. | -| 04 | [Problem](https://adventofcode.com/2025/day/4) | [Solution](./cmd/04/) | Part 1 was by far the most straight-forward challenge so far. | +| 04 | [Problem](https://adventofcode.com/2025/day/4) | [Solution](./cmd/04/) | Part 1 was by far the most straight-forward challenge so far. This was easiest day of AoC this year by far. | | 05 | [Problem](https://adventofcode.com/2025/day/5) | [Solution](./cmd/05/) | | | 06 | [Problem](https://adventofcode.com/2025/day/6) | [Solution](./cmd/06/) | | | 07 | [Problem](https://adventofcode.com/2025/day/7) | [Solution](./cmd/07/) | | diff --git a/cmd/04/main.go b/cmd/04/main.go index c2803d6..cd18b0b 100644 --- a/cmd/04/main.go +++ b/cmd/04/main.go @@ -4,9 +4,11 @@ import ( "github.com/StevanFreeborn/advent-of-code-2025/internal/file" "github.com/StevanFreeborn/advent-of-code-2025/internal/grid" "github.com/StevanFreeborn/advent-of-code-2025/internal/move" + "github.com/StevanFreeborn/advent-of-code-2025/internal/position" ) const PaperRollCharacter = "@" +const EmptySpaceCharacter = "." func SolvePartOne(filePath string) int { input := file.ReadAllLines(filePath) @@ -27,5 +29,40 @@ func SolvePartOne(filePath string) int { total++ } } + + return total +} + +func SolvePartTwo(filePath string) int { + input := file.ReadAllLines(filePath) + g := grid.From(input) + + total := 0 + + for { + positionsToRemove := []position.Position{} + + for position := range g.Positions() { + value := g.GetValueAt(position) + + if value != PaperRollCharacter { + continue + } + + sameNeighbors := g.GetSameNeighborsOf(position, move.AllDirections) + + if len(sameNeighbors) < 4 { + positionsToRemove = append(positionsToRemove, position) + total++ + } + } + + if len(positionsToRemove) == 0 { + break + } + + g.SetValuesAt(positionsToRemove, EmptySpaceCharacter) + } + return total } diff --git a/cmd/04/main_test.go b/cmd/04/main_test.go index cb0ee68..5b58261 100644 --- a/cmd/04/main_test.go +++ b/cmd/04/main_test.go @@ -25,3 +25,23 @@ func TestSolvePartOneWithInput(t *testing.T) { t.Errorf("got %d but wanted %d", result, expected) } } + +func TestSolvePartTwoWithExampleInput(t *testing.T) { + expected := 43 + + result := solution.SolvePartTwo("EXAMPLE.txt") + + if result != expected { + t.Errorf("got %d but wanted %d", result, expected) + } +} + +func TestSolvePartTwoWithInput(t *testing.T) { + expected := 8451 + + result := solution.SolvePartTwo("INPUT.txt") + + if result != expected { + t.Errorf("got %d but wanted %d", result, expected) + } +} diff --git a/internal/grid/grid.go b/internal/grid/grid.go index 8b91625..347dc7d 100644 --- a/internal/grid/grid.go +++ b/internal/grid/grid.go @@ -1,6 +1,8 @@ package grid import ( + "strings" + "github.com/StevanFreeborn/advent-of-code-2025/internal/move" "github.com/StevanFreeborn/advent-of-code-2025/internal/position" ) @@ -12,6 +14,7 @@ type Grid interface { GetValueAt(position.Position) string GetSameNeighborsOf(position.Position, []move.Move) []position.Position Positions() map[position.Position]string + SetValuesAt(positions []position.Position, value string) } type grid struct { @@ -20,6 +23,10 @@ type grid struct { positions map[position.Position]string } +func New(positions map[position.Position]string) Grid { + return grid{positions: positions} +} + func From(input []string) Grid { numberOfRows := len(input) numberOfColumns := len(input[0]) @@ -95,3 +102,27 @@ func (g grid) Positions() map[position.Position]string { return positions } + +func (g grid) SetValuesAt(positions []position.Position, value string) { + for _, pos := range positions { + g.positions[pos] = value + } +} + +func (g grid) String() string { + var rowString strings.Builder + + for row := range g.numberOfRows { + var colString strings.Builder + + for col := range g.numberOfColumns { + pos := position.From(row, col) + value := g.positions[pos] + colString.WriteString(value) + } + + rowString.WriteString(colString.String() + "\n") + } + + return rowString.String() +}