feat: completed day 7 for advent of code 2025
This commit is contained in:
parent
9909eaf70f
commit
3399702096
4 changed files with 172 additions and 0 deletions
|
|
@ -15,6 +15,7 @@ import (
|
|||
"cpatino.com/advent-of-code/2025/day04"
|
||||
"cpatino.com/advent-of-code/2025/day05"
|
||||
"cpatino.com/advent-of-code/2025/day06"
|
||||
"cpatino.com/advent-of-code/2025/day07"
|
||||
)
|
||||
|
||||
var days = map[int]func(string) (any, any){
|
||||
|
|
@ -24,6 +25,7 @@ var days = map[int]func(string) (any, any){
|
|||
4: day04.Run,
|
||||
5: day05.Run,
|
||||
6: day06.Run,
|
||||
7: day07.Run,
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
|
|
|
|||
120
2025/day07/day07.go
Executable file
120
2025/day07/day07.go
Executable file
|
|
@ -0,0 +1,120 @@
|
|||
package day07
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Beam struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
type Grid struct {
|
||||
cells [][]rune
|
||||
}
|
||||
|
||||
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
|
||||
startX, startY := -1, -1
|
||||
row := 0
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
rowRunes := []rune(line)
|
||||
if startX == -1 {
|
||||
for col, ch := range rowRunes {
|
||||
if ch == 'S' {
|
||||
startX, startY = row, col
|
||||
}
|
||||
}
|
||||
}
|
||||
grid = append(grid, rowRunes)
|
||||
row++
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g := Grid{cells: grid}
|
||||
part1 := Part1(&g, startX, startY)
|
||||
part2 := Part2(&g, startX, startY)
|
||||
return part1, part2
|
||||
}
|
||||
|
||||
func Part1(grid *Grid, startX, startY int) int {
|
||||
visited := make(map[Beam]bool)
|
||||
splits := 0
|
||||
|
||||
queue := []Beam{{startX, startY}}
|
||||
for len(queue) > 0 {
|
||||
pos := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
nx, ny := pos.x+1, pos.y
|
||||
if nx < 0 || ny < 0 || nx >= len(grid.cells) || ny >= len(grid.cells[0]) {
|
||||
continue
|
||||
}
|
||||
|
||||
state := Beam{nx, ny}
|
||||
if visited[state] {
|
||||
continue
|
||||
}
|
||||
|
||||
visited[state] = true
|
||||
cell := grid.cells[nx][ny]
|
||||
if cell == '^' {
|
||||
splits++
|
||||
if ny-1 >= 0 {
|
||||
queue = append(queue, Beam{nx, ny - 1})
|
||||
}
|
||||
if ny+1 < len(grid.cells[0]) {
|
||||
queue = append(queue, Beam{nx, ny + 1})
|
||||
}
|
||||
} else {
|
||||
queue = append(queue, Beam{nx, ny})
|
||||
}
|
||||
}
|
||||
|
||||
return splits
|
||||
}
|
||||
|
||||
func Part2(grid *Grid, startX, startY int) int {
|
||||
memo := make(map[Beam]int)
|
||||
|
||||
var dfs func(x, y int) int
|
||||
dfs = func(x, y int) int {
|
||||
if x < 0 || y < 0 || x >= len(grid.cells) || y >= len(grid.cells[0]) {
|
||||
return 1
|
||||
}
|
||||
|
||||
state := Beam{x, y}
|
||||
if v, ok := memo[state]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
cell := grid.cells[x][y]
|
||||
if cell == '^' {
|
||||
left, right := 0, 0
|
||||
if y-1 >= 0 {
|
||||
left = dfs(x+1, y-1)
|
||||
}
|
||||
if y+1 < len(grid.cells[0]) {
|
||||
right = dfs(x+1, y+1)
|
||||
}
|
||||
res := left + right
|
||||
memo[state] = res
|
||||
return res
|
||||
}
|
||||
|
||||
res := dfs(x+1, y)
|
||||
memo[state] = res
|
||||
return res
|
||||
}
|
||||
|
||||
return dfs(startX+1, startY)
|
||||
}
|
||||
34
2025/day07/day07_test.go
Executable file
34
2025/day07/day07_test.go
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
package day07
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
FileName string
|
||||
Part1 any
|
||||
Part2 any
|
||||
}
|
||||
|
||||
func TestDay07(t *testing.T) {
|
||||
tests := []TestCase{
|
||||
{"test.txt", 21, 40},
|
||||
{"input.txt", 1573, 15093663987272},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
16
2025/day07/test.txt
Executable file
16
2025/day07/test.txt
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
.......S.......
|
||||
...............
|
||||
.......^.......
|
||||
...............
|
||||
......^.^......
|
||||
...............
|
||||
.....^.^.^.....
|
||||
...............
|
||||
....^.^...^....
|
||||
...............
|
||||
...^.^...^.^...
|
||||
...............
|
||||
..^...^.....^..
|
||||
...............
|
||||
.^.^.^.^.^...^.
|
||||
...............
|
||||
Loading…
Add table
Add a link
Reference in a new issue