From 02fe79f702bbede053b1f27afba27c5726fc3fa0 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Wed, 3 Dec 2025 23:09:17 -0600 Subject: [PATCH] feat: completed day 4 for advent of code 2025 --- 2025/cmd/root.go | 2 + 2025/day04/day04.go | 118 +++++++++++++++++++++++++++++++++++++++ 2025/day04/day04_test.go | 34 +++++++++++ 2025/day04/test.txt | 10 ++++ 4 files changed, 164 insertions(+) create mode 100755 2025/day04/day04.go create mode 100755 2025/day04/day04_test.go create mode 100755 2025/day04/test.txt diff --git a/2025/cmd/root.go b/2025/cmd/root.go index f919404..301897b 100644 --- a/2025/cmd/root.go +++ b/2025/cmd/root.go @@ -12,12 +12,14 @@ import ( "cpatino.com/advent-of-code/2025/day01" "cpatino.com/advent-of-code/2025/day02" "cpatino.com/advent-of-code/2025/day03" + "cpatino.com/advent-of-code/2025/day04" ) var days = map[int]func(string) (any, any){ 1: day01.Run, 2: day02.Run, 3: day03.Run, + 4: day04.Run, } var rootCmd = &cobra.Command{ diff --git a/2025/day04/day04.go b/2025/day04/day04.go new file mode 100755 index 0000000..f50c4f8 --- /dev/null +++ b/2025/day04/day04.go @@ -0,0 +1,118 @@ +package day04 + +import ( + "bufio" + "os" +) + +var dirs = [8][2]int{ + {-1, -1}, {-1, 0}, {-1, 1}, + {0, -1}, {0, 1}, + {1, -1}, {1, 0}, {1, 1}, +} + +func copyGrid(src [][]rune) [][]rune { + res := make([][]rune, len(src)) + for i := range src { + res[i] = make([]rune, len(src[i])) + copy(res[i], src[i]) + } + return res +} + +func Part1(grid [][]rune) int { + rows := len(grid) + if rows == 0 { + return 0 + } + + cols := len(grid[0]) + accessible := 0 + + for r := range rows { + for c := range cols { + if grid[r][c] != '@' { + continue + } + + adj := 0 + for _, d := range dirs { + nr, nc := r+d[0], c+d[1] + if nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] == '@' { + adj++ + } + } + + if adj < 4 { + accessible++ + } + } + } + + return accessible +} + +func Part2(grid [][]rune) int { + rows, cols := len(grid), len(grid[0]) + totalRemoved := 0 + for { + toRemove := make([][2]int, 0) + for r := range rows { + for c := range cols { + if grid[r][c] != '@' { + continue + } + + adj := 0 + for _, d := range dirs { + nr, nc := r+d[0], c+d[1] + if nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] == '@' { + adj++ + } + } + + if adj < 4 { + toRemove = append(toRemove, [2]int{r, c}) + } + } + } + + if len(toRemove) == 0 { + break + } + + for _, pos := range toRemove { + r, c := pos[0], pos[1] + grid[r][c] = '.' + } + + totalRemoved += len(toRemove) + } + + return totalRemoved +} + +func Run(filename string) (any, any) { + file, err := os.Open(filename) + if err != nil { + panic(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var grid [][]rune + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 { + continue + } + grid = append(grid, []rune(line)) + } + if err := scanner.Err(); err != nil { + panic(err) + } + + part1 := Part1(copyGrid(grid)) + part2 := Part2(copyGrid(grid)) + return part1, part2 +} diff --git a/2025/day04/day04_test.go b/2025/day04/day04_test.go new file mode 100755 index 0000000..c40d49a --- /dev/null +++ b/2025/day04/day04_test.go @@ -0,0 +1,34 @@ +package day04 + +import ( + "os" + "testing" +) + +type TestCase struct { + FileName string + Part1 any + Part2 any +} + +func TestDay04(t *testing.T) { + tests := []TestCase{ + {"test.txt", 13, 43}, + {"input.txt", 1523, 9290}, + } + + for _, test := range tests { + if _, err := os.Stat(test.FileName); os.IsNotExist(err) { + t.Fatalf("test file does not exist: %v", test.FileName) + } + + part1, part2 := Run(test.FileName) + if test.Part1 != nil && part1 != test.Part1 { + t.Fatalf("%s: unexpected part1:\nwant:\t%v\ngot:\t%v", test.FileName, test.Part1, part1) + } + + if test.Part2 != nil && part2 != test.Part2 { + t.Fatalf("%s: unexpected part2:\nwant:\t%v\ngot:\t%v", test.FileName, test.Part2, part2) + } + } +} diff --git a/2025/day04/test.txt b/2025/day04/test.txt new file mode 100755 index 0000000..8209399 --- /dev/null +++ b/2025/day04/test.txt @@ -0,0 +1,10 @@ +..@@.@@@@. +@@@.@.@.@@ +@@@@@.@.@@ +@.@@@@..@. +@@.@@@@.@@ +.@@@@@@@.@ +.@.@.@.@@@ +@.@@@.@@@@ +.@@@@@@@@. +@.@.@@@.@.