-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement 2024 day01 solution (#334)
* feat: Add 2024 year to constants * feat: Add 2024/day01 initial code * feat: Implement solution for 2024 day 1 * fix: Linter warnings in 2017 day 02
- Loading branch information
1 parent
66bb133
commit 4f6b4a8
Showing
11 changed files
with
742 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ const ( | |
Year2021 // 2021 | ||
Year2022 // 2022 | ||
Year2023 // 2023 | ||
Year2024 // 2024 | ||
|
||
yearSentinel | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
}) | ||
} | ||
} |
Oops, something went wrong.