feat: completed day 4 for advent of code 2025
Some checks are pending
gofmt / format (push) Waiting to run
Some checks are pending
gofmt / format (push) Waiting to run
This commit is contained in:
parent
3b8b6d8636
commit
02fe79f702
4 changed files with 164 additions and 0 deletions
|
|
@ -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
118
2025/day04/day04.go
Executable 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
34
2025/day04/day04_test.go
Executable 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
10
2025/day04/test.txt
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
..@@.@@@@.
|
||||
@@@.@.@.@@
|
||||
@@@@@.@.@@
|
||||
@.@@@@..@.
|
||||
@@.@@@@.@@
|
||||
.@@@@@@@.@
|
||||
.@.@.@.@@@
|
||||
@.@@@.@@@@
|
||||
.@@@@@@@@.
|
||||
@.@.@@@.@.
|
||||
Loading…
Add table
Add a link
Reference in a new issue