feat: completed day 5 for advent of code 2025
Some checks failed
gofmt / format (push) Has been cancelled
Some checks failed
gofmt / format (push) Has been cancelled
This commit is contained in:
parent
02fe79f702
commit
ed7885cb22
4 changed files with 179 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"cpatino.com/advent-of-code/2025/day02"
|
"cpatino.com/advent-of-code/2025/day02"
|
||||||
"cpatino.com/advent-of-code/2025/day03"
|
"cpatino.com/advent-of-code/2025/day03"
|
||||||
"cpatino.com/advent-of-code/2025/day04"
|
"cpatino.com/advent-of-code/2025/day04"
|
||||||
|
"cpatino.com/advent-of-code/2025/day05"
|
||||||
)
|
)
|
||||||
|
|
||||||
var days = map[int]func(string) (any, any){
|
var days = map[int]func(string) (any, any){
|
||||||
|
|
@ -20,6 +21,7 @@ var days = map[int]func(string) (any, any){
|
||||||
2: day02.Run,
|
2: day02.Run,
|
||||||
3: day03.Run,
|
3: day03.Run,
|
||||||
4: day04.Run,
|
4: day04.Run,
|
||||||
|
5: day05.Run,
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
|
|
||||||
132
2025/day05/day05.go
Executable file
132
2025/day05/day05.go
Executable file
|
|
@ -0,0 +1,132 @@
|
||||||
|
package day05
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Part1(ranges [][2]int, ids []int) int {
|
||||||
|
freshCount := 0
|
||||||
|
for _, id := range ids {
|
||||||
|
for _, r := range ranges {
|
||||||
|
if id >= r[0] && id <= r[1] {
|
||||||
|
freshCount++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return freshCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func Part2(ranges [][2]int) int {
|
||||||
|
if len(ranges) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted := make([][2]int, len(ranges))
|
||||||
|
copy(sorted, ranges)
|
||||||
|
for i := 0; i < len(sorted)-1; i++ {
|
||||||
|
for j := i + 1; j < len(sorted); j++ {
|
||||||
|
if sorted[j][0] < sorted[i][0] {
|
||||||
|
sorted[i], sorted[j] = sorted[j], sorted[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
merged := make([][2]int, 0)
|
||||||
|
current := sorted[0]
|
||||||
|
for i := 1; i < len(sorted); i++ {
|
||||||
|
next := sorted[i]
|
||||||
|
if next[0] <= current[1]+1 {
|
||||||
|
if next[1] > current[1] {
|
||||||
|
current[1] = next[1]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
merged = append(merged, current)
|
||||||
|
current = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged = append(merged, current)
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
for _, r := range merged {
|
||||||
|
total += r[1] - r[0] + 1
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(filename string) (any, any) {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
lines := make([]string, 0)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sep := 0
|
||||||
|
for i, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
sep = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rangeLines := lines[:sep]
|
||||||
|
idLines := lines[sep+1:]
|
||||||
|
|
||||||
|
ranges := parseRanges(rangeLines)
|
||||||
|
ids := parseIDs(idLines)
|
||||||
|
|
||||||
|
part1 := Part1(ranges, ids)
|
||||||
|
part2 := Part2(ranges)
|
||||||
|
|
||||||
|
return part1, part2
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRanges(lines []string) [][2]int {
|
||||||
|
ranges := make([][2]int, 0)
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(line, "-")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
start, err1 := strconv.Atoi(parts[0])
|
||||||
|
end, err2 := strconv.Atoi(parts[1])
|
||||||
|
if err1 == nil && err2 == nil {
|
||||||
|
ranges = append(ranges, [2]int{start, end})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ranges
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseIDs(lines []string) []int {
|
||||||
|
ids := make([]int, 0)
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(line)
|
||||||
|
if err == nil {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
34
2025/day05/day05_test.go
Executable file
34
2025/day05/day05_test.go
Executable file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package day05
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestCase struct {
|
||||||
|
FileName string
|
||||||
|
Part1 any
|
||||||
|
Part2 any
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDay05(t *testing.T) {
|
||||||
|
tests := []TestCase{
|
||||||
|
{"test.txt", 3, 14},
|
||||||
|
{"input.txt", 798, 366181852921027},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
2025/day05/test.txt
Executable file
11
2025/day05/test.txt
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
3-5
|
||||||
|
10-14
|
||||||
|
16-20
|
||||||
|
12-18
|
||||||
|
|
||||||
|
1
|
||||||
|
5
|
||||||
|
8
|
||||||
|
11
|
||||||
|
17
|
||||||
|
32
|
||||||
Loading…
Add table
Add a link
Reference in a new issue