Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ SHELL := env APP_NAME=$(APP_NAME) $(SHELL)

SHELL := env GOTOOLS_IMAGE_TAG=$(GOTOOLS_IMAGE_TAG) $(SHELL)

AOC_PUZZLE_URL=
SHELL := env AOC_PUZZLE_URL=$(AOC_PUZZLE_URL) $(SHELL)

COMPOSE_TOOLS_FILE=deployments/docker-compose/go-tools-docker-compose.yml
COMPOSE_TOOLS_CMD_BASE=docker compose -f $(COMPOSE_TOOLS_FILE)
COMPOSE_TOOLS_CMD_UP=$(COMPOSE_TOOLS_CMD_BASE) up --exit-code-from
Expand Down
1 change: 1 addition & 0 deletions internal/puzzles/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const (
Year2021 // 2021
Year2022 // 2022
Year2023 // 2023
Year2024 // 2024

yearSentinel
)
Expand Down
14 changes: 7 additions & 7 deletions internal/puzzles/solutions/2017/day02/solution.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (s solution) Year() string {

func (s solution) Part1(input io.Reader) (string, error) {
var f checksumFunc = func(row []string) (int, error) {
var min, max int
var minVal, maxVal int

for i, number := range row {
d, err := strconv.Atoi(number)
Expand All @@ -37,19 +37,19 @@ func (s solution) Part1(input io.Reader) (string, error) {
}

if i == 0 {
min, max = d, d
minVal, maxVal = d, d
}

if d < min {
min = d
if d < minVal {
minVal = d
}

if d > max {
max = d
if d > maxVal {
maxVal = d
}
}

return max - min, nil
return maxVal - minVal, nil
}

return findChecksum(input, f)
Expand Down
126 changes: 126 additions & 0 deletions internal/puzzles/solutions/2024/day01/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Package day01 contains solution for https://adventofcode.com/2024/day/1 puzzle.
package day01

import (
"bufio"
"fmt"
"io"
"slices"
"strconv"
"strings"

"github.com/obalunenko/advent-of-code/internal/puzzles"
)

func init() {
puzzles.Register(solution{})
}

type solution struct{}

func (s solution) Year() string {
return puzzles.Year2024.String()
}

func (s solution) Day() string {
return puzzles.Day01.String()
}

func (s solution) Part1(input io.Reader) (string, error) {
l, err := parseInput(input)
if err != nil {
return "", fmt.Errorf("failed to parse input: %w", err)
}

slices.Sort(l.itemsA)
slices.Sort(l.itemsB)

var sum int

for i := 0; i < len(l.itemsA); i++ {
d := l.itemsA[i] - l.itemsB[i]
if d < 0 {
d = -d
}

sum += d
}

return strconv.Itoa(sum), nil
}

func (s solution) Part2(input io.Reader) (string, error) {
l, err := parseInput(input)
if err != nil {
return "", fmt.Errorf("failed to parse input: %w", err)
}

seenA := make(map[int]int)

for _, a := range l.itemsA {
seenA[a] = 0

for _, b := range l.itemsB {
if a == b {
seenA[a]++
}
}
}

var sum int

for _, a := range l.itemsA {
sum += a * seenA[a]
}

return strconv.Itoa(sum), nil
}

type lists struct {
itemsA []int
itemsB []int
}

func parseInput(input io.Reader) (lists, error) {
const (
listsNum = 2
listAIdx = 0
listBIdx = 1
)

l := lists{
itemsA: make([]int, 0),
itemsB: make([]int, 0),
}

scanner := bufio.NewScanner(input)
for scanner.Scan() {
line := scanner.Text()

parts := strings.Split(line, " ")
if len(parts) != listsNum {
return lists{}, fmt.Errorf("invalid input line: %s", line)
}

// Parse parts[0] and parts[1] to integers and append them to l.itemsA and l.itemsB respectively.
a, err := strconv.Atoi(parts[listAIdx])
if err != nil {
return lists{}, fmt.Errorf("failed to parse int: %w", err)
}

b, err := strconv.Atoi(parts[listBIdx])
if err != nil {
return lists{}, fmt.Errorf("failed to parse int: %w", err)
}

l.itemsA = append(l.itemsA, a)

l.itemsB = append(l.itemsB, b)
}

if scanner.Err() != nil {
return lists{}, fmt.Errorf("scanner error: %w", scanner.Err())
}

return l, nil
}
117 changes: 117 additions & 0 deletions internal/puzzles/solutions/2024/day01/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package day01

import (
"errors"
"io"
"path/filepath"
"testing"
"testing/iotest"

"github.com/stretchr/testify/assert"

"github.com/obalunenko/advent-of-code/internal/puzzles/common/utils"
)

func Test_solution_Year(t *testing.T) {
var s solution

want := "2024"
got := s.Year()

assert.Equal(t, want, got)
}

func Test_solution_Day(t *testing.T) {
var s solution

want := "1"
got := s.Day()

assert.Equal(t, want, got)
}

func Test_solution_Part1(t *testing.T) {
var s solution

type args struct {
input io.Reader
}

tests := []struct {
name string
args args
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "test example from description",
args: args{
input: utils.ReaderFromFile(t, filepath.Join("testdata", "input.txt")),
},
want: "11",
wantErr: assert.NoError,
},
{
name: "",
args: args{
input: iotest.ErrReader(errors.New("custom error")),
},
want: "",
wantErr: assert.Error,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := s.Part1(tt.args.input)
if !tt.wantErr(t, err) {
return
}

assert.Equal(t, tt.want, got)
})
}
}

func Test_solution_Part2(t *testing.T) {
var s solution

type args struct {
input io.Reader
}

tests := []struct {
name string
args args
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "test example from description",
args: args{
input: utils.ReaderFromFile(t, filepath.Join("testdata", "input.txt")),
},
want: "31",
wantErr: assert.NoError,
},
{
name: "",
args: args{
input: iotest.ErrReader(errors.New("custom error")),
},
want: "",
wantErr: assert.Error,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := s.Part2(tt.args.input)
if !tt.wantErr(t, err) {
return
}

assert.Equal(t, tt.want, got)
})
}
}
Loading
Loading