From 6e06bd5b16581f9794315d889c54c3ad9c5c8d19 Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Mon, 2 Dec 2024 19:28:55 +0000 Subject: [PATCH] add day-02 + benchmarks --- day-02/benchmark | 15 +++++ day-02/cmd/cli/main.go | 34 +++++++++++ day-02/go.mod | 11 ++++ day-02/go.sum | 10 ++++ day-02/internal/one/benchmark | 6 ++ day-02/internal/one/check.go | 16 +++++ day-02/internal/one/check_internal_test.go | 69 ++++++++++++++++++++++ day-02/internal/one/solve.go | 40 +++++++++++++ day-02/internal/one/solve_internal_test.go | 15 +++++ day-02/internal/two/benchmark | 6 ++ day-02/internal/two/check.go | 32 ++++++++++ day-02/internal/two/check_internal_test.go | 61 +++++++++++++++++++ day-02/internal/two/solve.go | 41 +++++++++++++ day-02/internal/two/solve_internal_test.go | 15 +++++ day-02/internal/util/util.go | 22 +++++++ day-02/makefile | 30 ++++++++++ day-02/solve.go | 20 +++++++ day-02/solve_internal_test.go | 15 +++++ 18 files changed, 458 insertions(+) create mode 100644 day-02/benchmark create mode 100644 day-02/cmd/cli/main.go create mode 100644 day-02/go.mod create mode 100644 day-02/go.sum create mode 100644 day-02/internal/one/benchmark create mode 100644 day-02/internal/one/check.go create mode 100644 day-02/internal/one/check_internal_test.go create mode 100644 day-02/internal/one/solve.go create mode 100644 day-02/internal/one/solve_internal_test.go create mode 100644 day-02/internal/two/benchmark create mode 100644 day-02/internal/two/check.go create mode 100644 day-02/internal/two/check_internal_test.go create mode 100644 day-02/internal/two/solve.go create mode 100644 day-02/internal/two/solve_internal_test.go create mode 100644 day-02/internal/util/util.go create mode 100644 day-02/makefile create mode 100644 day-02/solve.go create mode 100644 day-02/solve_internal_test.go diff --git a/day-02/benchmark b/day-02/benchmark new file mode 100644 index 0000000..fb314d4 --- /dev/null +++ b/day-02/benchmark @@ -0,0 +1,15 @@ +goos: linux +goarch: amd64 +pkg: github.com/onyx-and-iris/aoc2024/day-02 +cpu: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz +BenchmarkMain-12 1000000000 0.001121 ns/op +BenchmarkMain-12 1000000000 0.0009054 ns/op +BenchmarkMain-12 1000000000 0.0009948 ns/op +BenchmarkMain-12 1000000000 0.0008774 ns/op +BenchmarkMain-12 1000000000 0.0009065 ns/op +BenchmarkMain-12 1000000000 0.0008702 ns/op +BenchmarkMain-12 1000000000 0.0008654 ns/op +BenchmarkMain-12 1000000000 0.0008806 ns/op +BenchmarkMain-12 1000000000 0.0009256 ns/op +BenchmarkMain-12 1000000000 0.0009088 ns/op +ok github.com/onyx-and-iris/aoc2024/day-02 0.085s diff --git a/day-02/cmd/cli/main.go b/day-02/cmd/cli/main.go new file mode 100644 index 0000000..f11f5d5 --- /dev/null +++ b/day-02/cmd/cli/main.go @@ -0,0 +1,34 @@ +/******************************************************************************** + Advent of Code 2024 - day-02 +********************************************************************************/ + +package main + +import ( + "embed" + "flag" + "fmt" + "log" + + problems "github.com/onyx-and-iris/aoc2024/day-02" +) + +//go:embed testdata +var files embed.FS + +func main() { + filename := flag.String("f", "input.txt", "input file") + flag.Parse() + + data, err := files.ReadFile(fmt.Sprintf("testdata/%s", *filename)) + if err != nil { + log.Fatal(err) + } + + one, two, err := problems.Solve(data) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("solution one: %d\nsolution two: %d\n", one, two) +} diff --git a/day-02/go.mod b/day-02/go.mod new file mode 100644 index 0000000..71bd362 --- /dev/null +++ b/day-02/go.mod @@ -0,0 +1,11 @@ +module github.com/onyx-and-iris/aoc2024/day-02 + +go 1.23.3 + +require github.com/stretchr/testify v1.10.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/day-02/go.sum b/day-02/go.sum new file mode 100644 index 0000000..713a0b4 --- /dev/null +++ b/day-02/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/day-02/internal/one/benchmark b/day-02/internal/one/benchmark new file mode 100644 index 0000000..8e5709b --- /dev/null +++ b/day-02/internal/one/benchmark @@ -0,0 +1,6 @@ +goos: linux +goarch: amd64 +pkg: github.com/onyx-and-iris/aoc2024/day-02/internal/one +cpu: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz +BenchmarkMain-12 1000000000 0.0003352 ns/op +ok github.com/onyx-and-iris/aoc2024/day-02/internal/one 0.009s diff --git a/day-02/internal/one/check.go b/day-02/internal/one/check.go new file mode 100644 index 0000000..d645234 --- /dev/null +++ b/day-02/internal/one/check.go @@ -0,0 +1,16 @@ +package one + +import "math" + +func checkWithComparator(nums []int, comparator comparator) bool { + for i := 1; i < len(nums); i++ { + if comparator(nums, i) || !isSafe(nums[i-1], nums[i]) { + return false + } + } + return true +} + +func isSafe(m, n int) bool { + return int(math.Abs(float64(m-n))) <= 3 +} diff --git a/day-02/internal/one/check_internal_test.go b/day-02/internal/one/check_internal_test.go new file mode 100644 index 0000000..b4eb969 --- /dev/null +++ b/day-02/internal/one/check_internal_test.go @@ -0,0 +1,69 @@ +package one + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCheckIncreased(t *testing.T) { + tt := map[string]struct { + input []int + want bool + }{ + "nominal": { + input: []int{1, 3, 6, 7, 9}, + want: true, + }, + "unsafe": { + input: []int{1, 3, 2, 4, 8}, + want: false, + }, + "two numbers the same": { + input: []int{1, 3, 3, 4, 8}, + want: false, + }, + } + + cmp := func(nums []int, i int) bool { + return nums[i-1] >= nums[i] + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + got := checkWithComparator(tc.input, cmp) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestCheckDecreased(t *testing.T) { + tt := map[string]struct { + input []int + want bool + }{ + "nominal": { + input: []int{7, 6, 4, 2, 1}, + want: true, + }, + "unsafe": { + input: []int{9, 7, 6, 2, 1}, + want: false, + }, + "two numbers the same": { + input: []int{8, 6, 4, 4, 1}, + want: false, + }, + } + + cmp := func(nums []int, i int) bool { + return nums[i-1] <= nums[i] + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + got := checkWithComparator(tc.input, cmp) + assert.Equal(t, tc.want, got) + }) + } +} diff --git a/day-02/internal/one/solve.go b/day-02/internal/one/solve.go new file mode 100644 index 0000000..8de2461 --- /dev/null +++ b/day-02/internal/one/solve.go @@ -0,0 +1,40 @@ +package one + +import ( + "bufio" + "bytes" + "io" + + "github.com/onyx-and-iris/aoc2024/day-02/internal/util" +) + +type comparator func([]int, int) bool + +func Solve(data []byte) (int, error) { + r := bytes.NewReader(data) + sum := parseLines(r) + + return sum, nil +} + +func parseLines(r io.Reader) int { + var sum int + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + nums := util.IntsFromString(scanner.Text()) + if check(checkWithComparator, nums, func(nums []int, i int) bool { + return nums[i-1] >= nums[i] + }) || check(checkWithComparator, nums, func(nums []int, i int) bool { + return nums[i-1] <= nums[i] + }) { + sum++ + } + } + + return sum +} + +func check(fn func([]int, comparator) bool, nums []int, comparator comparator) bool { + return fn(nums, comparator) +} diff --git a/day-02/internal/one/solve_internal_test.go b/day-02/internal/one/solve_internal_test.go new file mode 100644 index 0000000..f9cc9af --- /dev/null +++ b/day-02/internal/one/solve_internal_test.go @@ -0,0 +1,15 @@ +package one + +import ( + _ "embed" + "os" + "testing" +) + +//go:embed testdata/input.txt +var data []byte + +func BenchmarkMain(b *testing.B) { + os.Stdout, _ = os.Open(os.DevNull) + Solve(data) +} diff --git a/day-02/internal/two/benchmark b/day-02/internal/two/benchmark new file mode 100644 index 0000000..bdc57f7 --- /dev/null +++ b/day-02/internal/two/benchmark @@ -0,0 +1,6 @@ +goos: linux +goarch: amd64 +pkg: github.com/onyx-and-iris/aoc2024/day-02/internal/two +cpu: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz +BenchmarkMain-12 1000000000 0.0005847 ns/op +ok github.com/onyx-and-iris/aoc2024/day-02/internal/two 0.011s diff --git a/day-02/internal/two/check.go b/day-02/internal/two/check.go new file mode 100644 index 0000000..1aced4e --- /dev/null +++ b/day-02/internal/two/check.go @@ -0,0 +1,32 @@ +package two + +import ( + "math" + "slices" +) + +func checkWithComparator(nums []int, comparator comparator, count int) bool { + if count > 1 { + return false + } + + for i := 1; i < len(nums); i++ { + if comparator(nums, i) || !isSafe(nums[i-1], nums[i]) { + count++ + removeFirst, removeSecond := nextLevels(nums, i) + return checkWithComparator(removeFirst, comparator, count) || + checkWithComparator(removeSecond, comparator, count) + } + } + + return true +} + +func isSafe(m, n int) bool { + return int(math.Abs(float64(m-n))) <= 3 +} + +func nextLevels(nums []int, i int) ([]int, []int) { + first, second := slices.Clone(nums), slices.Clone(nums) + return append(first[:i-1], first[i:]...), append(second[:i], second[i+1:]...) +} diff --git a/day-02/internal/two/check_internal_test.go b/day-02/internal/two/check_internal_test.go new file mode 100644 index 0000000..f32b8a2 --- /dev/null +++ b/day-02/internal/two/check_internal_test.go @@ -0,0 +1,61 @@ +package two + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIncreasedWithDampener(t *testing.T) { + tt := map[string]struct { + input []int + want bool + }{ + "one violation: two numbers the same": { + input: []int{72, 74, 74, 77, 78}, + want: true, + }, + "one violation: not in order": { + input: []int{72, 74, 75, 77, 63}, + want: true, + }, + + "two violations: three numbers the same": { + input: []int{74, 74, 74, 77, 78}, + want: false, + }, + "two violations: two numbers the same and not in order": { + input: []int{72, 74, 74, 72, 78}, + want: false, + }, + } + + cmp := func(nums []int, i int) bool { + return nums[i-1] >= nums[i] + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + got := checkWithComparator(tc.input, cmp, 0) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestDecreasedWithDampener(t *testing.T) { + tt := map[string]struct { + input []int + want bool + }{} + + cmp := func(nums []int, i int) bool { + return nums[i-1] <= nums[i] + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + got := checkWithComparator(tc.input, cmp, 0) + assert.Equal(t, tc.want, got) + }) + } +} diff --git a/day-02/internal/two/solve.go b/day-02/internal/two/solve.go new file mode 100644 index 0000000..72c06ef --- /dev/null +++ b/day-02/internal/two/solve.go @@ -0,0 +1,41 @@ +package two + +import ( + "bufio" + "bytes" + "io" + + "github.com/onyx-and-iris/aoc2024/day-02/internal/util" +) + +type comparator func([]int, int) bool + +func Solve(data []byte) (int, error) { + r := bytes.NewReader(data) + sum := parseLines(r) + + return sum, nil +} + +func parseLines(r io.Reader) int { + var sum int + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + nums := util.IntsFromString(scanner.Text()) + if check(checkWithComparator, nums, func(nums []int, i int) bool { + return nums[i-1] >= nums[i] + }) || check(checkWithComparator, nums, func(nums []int, i int) bool { + return nums[i-1] <= nums[i] + }) { + sum++ + } + } + + return sum +} + +func check(fn func([]int, comparator, int) bool, nums []int, comparator comparator) bool { + var count int + return fn(nums, comparator, count) +} diff --git a/day-02/internal/two/solve_internal_test.go b/day-02/internal/two/solve_internal_test.go new file mode 100644 index 0000000..e3efa34 --- /dev/null +++ b/day-02/internal/two/solve_internal_test.go @@ -0,0 +1,15 @@ +package two + +import ( + _ "embed" + "os" + "testing" +) + +//go:embed testdata/input.txt +var data []byte + +func BenchmarkMain(b *testing.B) { + os.Stdout, _ = os.Open(os.DevNull) + Solve(data) +} diff --git a/day-02/internal/util/util.go b/day-02/internal/util/util.go new file mode 100644 index 0000000..2bb9743 --- /dev/null +++ b/day-02/internal/util/util.go @@ -0,0 +1,22 @@ +package util + +import ( + "strconv" + "strings" +) + +func MustConv(s string) int { + n, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + return n +} + +func IntsFromString(s string) []int { + nums := []int{} + for _, r := range strings.Fields(s) { + nums = append(nums, MustConv(r)) + } + return nums +} diff --git a/day-02/makefile b/day-02/makefile new file mode 100644 index 0000000..1497ad1 --- /dev/null +++ b/day-02/makefile @@ -0,0 +1,30 @@ +program = day-02 + +GO = go +SRC_DIR := src +BIN_DIR := bin + +EXE := $(BIN_DIR)/$(program) + +.DEFAULT_GOAL := build + +.PHONY: fmt vet build bench clean +fmt: + $(GO) fmt ./... + +vet: fmt + $(GO) vet ./... + +build: vet | $(BIN_DIR) + $(GO) build -o $(EXE) ./$(SRC_DIR) + +bench: + $(GO) test ./internal/one/ -bench=. > internal/one/benchmark + $(GO) test ./internal/two/ -bench=. > internal/two/benchmark + $(GO) test . -count=10 -bench=. > benchmark + +$(BIN_DIR): + @mkdir -p $@ + +clean: + @rm -rv $(BIN_DIR) diff --git a/day-02/solve.go b/day-02/solve.go new file mode 100644 index 0000000..28dc4c4 --- /dev/null +++ b/day-02/solve.go @@ -0,0 +1,20 @@ +package daytwo + +import ( + "github.com/onyx-and-iris/aoc2024/day-02/internal/one" + "github.com/onyx-and-iris/aoc2024/day-02/internal/two" +) + +func Solve(data []byte) (int, int, error) { + answerOne, err := one.Solve(data) + if err != nil { + return 0, 0, err + } + + answerTwo, err := two.Solve(data) + if err != nil { + return 0, 0, err + } + + return answerOne, answerTwo, nil +} diff --git a/day-02/solve_internal_test.go b/day-02/solve_internal_test.go new file mode 100644 index 0000000..cb1c531 --- /dev/null +++ b/day-02/solve_internal_test.go @@ -0,0 +1,15 @@ +package daytwo + +import ( + _ "embed" + "os" + "testing" +) + +//go:embed testdata/input.txt +var data []byte + +func BenchmarkMain(b *testing.B) { + os.Stdout, _ = os.Open(os.DevNull) + Solve(data) +}