feat: completed day 4 for advent of code 2025
Some checks are pending
gofmt / format (push) Waiting to run

This commit is contained in:
Ceferino Patino 2025-12-03 23:09:17 -06:00
commit 02fe79f702
Signed by: c4patino
SSH key fingerprint: SHA256:Wu+cU1t+7zVT9wzew/4meNmeulo66NzMqc22MdDBgXI
4 changed files with 164 additions and 0 deletions

View file

@ -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{

118
2025/day04/day04.go Executable file
View file

@ -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
}

34
2025/day04/day04_test.go Executable file
View file

@ -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)
}
}
}

10
2025/day04/test.txt Executable file
View file

@ -0,0 +1,10 @@
..@@.@@@@.
@@@.@.@.@@
@@@@@.@.@@
@.@@@@..@.
@@.@@@@.@@
.@@@@@@@.@
.@.@.@.@@@
@.@@@.@@@@
.@@@@@@@@.
@.@.@@@.@.