feat: completed day 11 for advent of code
This commit is contained in:
parent
b29cef3adc
commit
9cf9674e7f
5 changed files with 179 additions and 0 deletions
|
|
@ -19,6 +19,7 @@ import (
|
|||
"cpatino.com/advent-of-code/2025/day08"
|
||||
"cpatino.com/advent-of-code/2025/day09"
|
||||
"cpatino.com/advent-of-code/2025/day10"
|
||||
"cpatino.com/advent-of-code/2025/day11"
|
||||
)
|
||||
|
||||
var days = map[int]func(string) (any, any){
|
||||
|
|
@ -32,6 +33,7 @@ var days = map[int]func(string) (any, any){
|
|||
8: day08.Run,
|
||||
9: day09.Run,
|
||||
10: day10.Run,
|
||||
11: day11.Run,
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
|
|
|
|||
119
2025/day11/day11.go
Executable file
119
2025/day11/day11.go
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
package day11
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
node string
|
||||
mask uint8
|
||||
}
|
||||
|
||||
func countPaths(graph map[string][]string, start, target string) int {
|
||||
memo := make(map[string]int)
|
||||
visiting := make(map[string]bool)
|
||||
var dfs func(string) int
|
||||
dfs = func(u string) int {
|
||||
if u == target {
|
||||
return 1
|
||||
}
|
||||
if visiting[u] {
|
||||
return 0
|
||||
}
|
||||
if v, ok := memo[u]; ok {
|
||||
return v
|
||||
}
|
||||
visiting[u] = true
|
||||
total := 0
|
||||
for _, v := range graph[u] {
|
||||
total += dfs(v)
|
||||
}
|
||||
visiting[u] = false
|
||||
memo[u] = total
|
||||
return total
|
||||
}
|
||||
return dfs(start)
|
||||
}
|
||||
|
||||
func Part1(graph map[string][]string) int {
|
||||
return countPaths(graph, "you", "out")
|
||||
}
|
||||
|
||||
func Part2(graph map[string][]string) int {
|
||||
start, target := "svr", "out"
|
||||
const need1, need2 = "dac", "fft"
|
||||
|
||||
memo := make(map[Key]int)
|
||||
visiting := make(map[string]bool)
|
||||
var dfs func(string, uint8) int
|
||||
dfs = func(u string, mask uint8) int {
|
||||
if u == need1 {
|
||||
mask |= 0b01
|
||||
}
|
||||
if u == need2 {
|
||||
mask |= 0b10
|
||||
}
|
||||
|
||||
if u == target {
|
||||
if mask == 0b11 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
if visiting[u] {
|
||||
return 0
|
||||
}
|
||||
|
||||
k := Key{u, mask}
|
||||
if v, ok := memo[k]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
visiting[u] = true
|
||||
total := 0
|
||||
for _, v := range graph[u] {
|
||||
total += dfs(v, mask)
|
||||
}
|
||||
|
||||
visiting[u] = false
|
||||
memo[k] = total
|
||||
return total
|
||||
}
|
||||
return dfs(start, 0)
|
||||
}
|
||||
|
||||
func Run(filename string) (any, any) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
graph := make(map[string][]string)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
src := strings.TrimSpace(parts[0])
|
||||
outs := strings.Fields(strings.TrimSpace(parts[1]))
|
||||
graph[src] = outs
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
part1 := Part1(graph)
|
||||
part2 := Part2(graph)
|
||||
|
||||
return part1, part2
|
||||
}
|
||||
35
2025/day11/day11_test.go
Executable file
35
2025/day11/day11_test.go
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
package day11
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
FileName string
|
||||
Part1 any
|
||||
Part2 any
|
||||
}
|
||||
|
||||
func TestDay11(t *testing.T) {
|
||||
tests := []TestCase{
|
||||
{"test.txt", 5, nil},
|
||||
{"test2.txt", nil, 2},
|
||||
{"input.txt", 634, 377452269415704},
|
||||
}
|
||||
|
||||
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/day11/test.txt
Executable file
10
2025/day11/test.txt
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
aaa: you hhh
|
||||
you: bbb ccc
|
||||
bbb: ddd eee
|
||||
ccc: ddd eee fff
|
||||
ddd: ggg
|
||||
eee: out
|
||||
fff: out
|
||||
ggg: out
|
||||
hhh: ccc fff iii
|
||||
iii: out
|
||||
13
2025/day11/test2.txt
Normal file
13
2025/day11/test2.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
svr: aaa bbb
|
||||
aaa: fft
|
||||
fft: ccc
|
||||
bbb: tty
|
||||
tty: ccc
|
||||
ccc: ddd eee
|
||||
ddd: hub
|
||||
hub: fff
|
||||
eee: dac
|
||||
dac: fff
|
||||
fff: ggg hhh
|
||||
ggg: out
|
||||
hhh: out
|
||||
Loading…
Add table
Add a link
Reference in a new issue