Skip to content
This repository was archived by the owner on Dec 28, 2024. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4dbdb1f

Browse files
committedDec 27, 2024··
Make all services output proper JSON
1 parent 4797aa0 commit 4dbdb1f

File tree

32 files changed

+386
-273
lines changed

32 files changed

+386
-273
lines changed
 

‎client/run.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package main
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"flag"
67
"fmt"
8+
"github.com/terminalnode/adventofcode2024/common/util"
79
"io"
810
"net/http"
911
"os"
@@ -64,17 +66,23 @@ func runSolution(
6466
url string,
6567
day int,
6668
part int,
67-
input string,
69+
rawInput string,
6870
) (string, error) {
6971
url = fmt.Sprintf("http://%s/day%02d/%d", url, day, part)
7072
fmt.Printf("Running day %d, part %d with URL '%s'\n", day, part, url)
7173
client := &http.Client{}
7274

73-
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(input)))
75+
input := util.AocInput{Input: rawInput}
76+
jsonData, err := json.Marshal(input)
77+
if err != nil {
78+
return "", fmt.Errorf("failed to marshal JSON: %v", err)
79+
}
80+
81+
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
7482
if err != nil {
7583
return "", err
7684
}
77-
req.Header.Set("Content-Type", "text/plain")
85+
req.Header.Set("Content-Type", "application/json")
7886

7987
resp, err := client.Do(req)
8088
if err != nil {

‎common/proto/grpc.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,30 @@ func CreateGRPCServer(
4141
return grpcServer
4242
}
4343

44+
// This part of the architecture is a bit #YOLO
45+
// But at least I got to play around a little with gRPC
46+
// Throughout the entire process I've only used the Kubernetes solution over HTTP
47+
4448
func (s *server) SolvePart1(
4549
ctx context.Context,
4650
req *InputData,
4751
) (*InputResponse, error) {
48-
result := s.solvePart1(req.Input)
49-
return &InputResponse{Result: result}, nil
52+
result, err := s.solvePart1(util.AocInput{Input: req.Input})
53+
if s := result.Solution; s != "" {
54+
return &InputResponse{Result: s}, nil
55+
} else {
56+
return &InputResponse{Result: err.Error()}, nil
57+
}
5058
}
5159

5260
func (s *server) SolvePart2(
5361
ctx context.Context,
5462
req *InputData,
5563
) (*InputResponse, error) {
56-
result := s.solvePart2(req.Input)
57-
return &InputResponse{Result: result}, nil
64+
result, err := s.solvePart2(util.AocInput{Input: req.Input})
65+
if s := result.Solution; s != "" {
66+
return &InputResponse{Result: s}, nil
67+
} else {
68+
return &InputResponse{Result: err.Error()}, nil
69+
}
5870
}

‎common/util/aoc_error.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package util
2+
3+
type ErrorType int
4+
5+
const (
6+
NotImplemented ErrorType = iota
7+
InputParsingError
8+
ParsingError
9+
StringToNumber
10+
ProcessingError
11+
)
12+
13+
func (et ErrorType) String() string {
14+
switch et {
15+
case NotImplemented:
16+
return "NotImplemented"
17+
case ParsingError:
18+
return "ParsingError"
19+
case StringToNumber:
20+
return "StringToNumber"
21+
default:
22+
return "UnknownError"
23+
}
24+
}
25+
26+
type AocError struct {
27+
Message string `json:"message"`
28+
Type string `json:"type"`
29+
IsError bool `json:"-"`
30+
}
31+
32+
func (
33+
e AocError,
34+
) Error() string {
35+
return e.Message
36+
}

‎common/util/solution.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
11
package util
22

3-
type Solution = func(string) string
3+
import "fmt"
4+
5+
type AocInput struct {
6+
Input string `json:"input"`
7+
}
8+
9+
type AocSolution struct {
10+
Solution string `json:"solution"`
11+
}
12+
13+
type Solution = func(AocInput) (AocSolution, AocError)
14+
15+
func NewAocError(
16+
m string,
17+
t ErrorType,
18+
) (AocSolution, AocError) {
19+
return AocSolution{}, AocError{Message: m, Type: t.String()}
20+
}
21+
22+
func NewAocSolution(
23+
solution string,
24+
) (AocSolution, AocError) {
25+
return AocSolution{Solution: solution}, AocError{}
26+
}
27+
28+
func FormatAocSolution(
29+
format string,
30+
a ...any,
31+
) (AocSolution, AocError) {
32+
return NewAocSolution(fmt.Sprintf(format, a...))
33+
}

‎common/web/http_util.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package web
22

33
import (
4+
"encoding/json"
45
"fmt"
5-
"io"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"net/http"
78
)
89

@@ -13,12 +14,11 @@ func addPrefix(prefix string, url string) string {
1314
return fmt.Sprintf("/%s%s", prefix, url)
1415
}
1516

16-
func readInput(r *http.Request) (string, error) {
17-
body, err := io.ReadAll(r.Body)
18-
if err != nil {
19-
return "", err
17+
func readInput(r *http.Request) (util.AocInput, error) {
18+
var input util.AocInput
19+
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
20+
return util.AocInput{}, err
2021
}
21-
2222
defer r.Body.Close()
23-
return string(body), nil
23+
return input, nil
2424
}

‎common/web/solution_handler.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package web
22

33
import (
4+
"encoding/json"
5+
"errors"
46
"fmt"
57
"github.com/terminalnode/adventofcode2024/common/util"
68
"net/http"
@@ -9,7 +11,7 @@ import (
911
func createSolutionHandler(
1012
day int,
1113
part int,
12-
solution func(string) string,
14+
solution util.Solution,
1315
) func(http.ResponseWriter, *http.Request) {
1416
if solution == nil {
1517
solution = defaultSolutionHandler(day, part)
@@ -27,10 +29,13 @@ func createSolutionHandler(
2729
return
2830
}
2931

30-
result := solution(input)
31-
if _, err = w.Write([]byte(result)); err != nil {
32-
http.Error(w, "Error", http.StatusInternalServerError)
33-
return
32+
aocSolution, aocErr := solution(input)
33+
w.Header().Set("Content-Type", "application/json")
34+
encoder := json.NewEncoder(w)
35+
if errors.Is(err, util.AocError{}) {
36+
encoder.Encode(aocErr)
37+
} else {
38+
encoder.Encode(aocSolution)
3439
}
3540
}
3641
}
@@ -39,7 +44,10 @@ func defaultSolutionHandler(
3944
day int,
4045
part int,
4146
) util.Solution {
42-
return func(input string) string {
43-
return fmt.Sprintf("Solution for day %d part %d not implemented yet", day, part)
47+
return func(input util.AocInput) (util.AocSolution, util.AocError) {
48+
return util.NewAocError(
49+
fmt.Sprintf("Solution for day %d part %d not implemented yet", day, part),
50+
util.NotImplemented,
51+
)
4452
}
4553
}

‎solutions/day01/main.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"slices"
78
"strconv"
89
"strings"
@@ -40,10 +41,12 @@ func createLists(input string) ([]int, []int, error) {
4041
return left, right, nil
4142
}
4243

43-
func part1(input string) string {
44-
left, right, err := createLists(input)
44+
func part1(
45+
input util.AocInput,
46+
) (util.AocSolution, util.AocError) {
47+
left, right, err := createLists(input.Input)
4548
if err != nil {
46-
return err.Error()
49+
return util.NewAocError(err.Error(), util.InputParsingError)
4750
}
4851

4952
// Sort the lists
@@ -60,13 +63,15 @@ func part1(input string) string {
6063
sum += diff
6164
}
6265

63-
return fmt.Sprintf("Result for part 1: %d", sum)
66+
return util.FormatAocSolution("Result for part 1: %d", sum)
6467
}
6568

66-
func part2(input string) string {
67-
left, right, err := createLists(input)
69+
func part2(
70+
input util.AocInput,
71+
) (util.AocSolution, util.AocError) {
72+
left, right, err := createLists(input.Input)
6873
if err != nil {
69-
return err.Error()
74+
return util.NewAocError(err.Error(), util.InputParsingError)
7075
}
7176

7277
rightMap := make(map[int]int)
@@ -79,5 +84,5 @@ func part2(input string) string {
7984
sum += l * rightMap[l]
8085
}
8186

82-
return fmt.Sprintf("Result for part 2: %d", sum)
87+
return util.FormatAocSolution("Result for part 2: %d", sum)
8388
}

‎solutions/day02/main.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
5+
"github.com/terminalnode/adventofcode2024/common/util"
66
"strconv"
77
"strings"
88
)
@@ -119,23 +119,23 @@ func countSafe(
119119
}
120120

121121
func part1(
122-
input string,
123-
) string {
124-
reports, err := parseAllReports(input, false)
122+
input util.AocInput,
123+
) (util.AocSolution, util.AocError) {
124+
reports, err := parseAllReports(input.Input, false)
125125
if err != nil {
126-
return fmt.Sprintf("Failed to parse reports: %v", err)
126+
return util.NewAocError(err.Error(), util.InputParsingError)
127127
}
128128

129-
return fmt.Sprintf("Number of safe reports: %d", countSafe(reports))
129+
return util.FormatAocSolution("Number of safe reports: %d", countSafe(reports))
130130
}
131131

132132
func part2(
133-
input string,
134-
) string {
135-
reports, err := parseAllReports(input, true)
133+
input util.AocInput,
134+
) (util.AocSolution, util.AocError) {
135+
reports, err := parseAllReports(input.Input, true)
136136
if err != nil {
137-
return fmt.Sprintf("Failed to parse reports: %v", err)
137+
return util.NewAocError(err.Error(), util.InputParsingError)
138138
}
139139

140-
return fmt.Sprintf("Number of safe reports: %d", countSafe(reports))
140+
return util.FormatAocSolution("Number of safe reports: %d", countSafe(reports))
141141
}

‎solutions/day03/main.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"regexp"
78
"strconv"
89
)
@@ -14,9 +15,9 @@ func main() {
1415
}
1516

1617
func part1(
17-
input string,
18-
) string {
19-
finds := r.FindAllSubmatch([]byte(input), -1)
18+
input util.AocInput,
19+
) (util.AocSolution, util.AocError) {
20+
finds := r.FindAllSubmatch([]byte(input.Input), -1)
2021
sum := 0
2122
for _, match := range finds {
2223
verb := string(match[1])
@@ -26,17 +27,17 @@ func part1(
2627

2728
multiplied, err := mul(string(match[3]), string(match[4]))
2829
if err != nil {
29-
return fmt.Sprintf("Failed to parse multiplication of %q:\n%v\n", match, err)
30+
return util.NewAocError(fmt.Sprintf("Failed to parse multiplication of %q:\n%v\n", match, err), util.ParsingError)
3031
}
3132
sum += multiplied
3233
}
33-
return fmt.Sprintf("Result: %d", sum)
34+
return util.FormatAocSolution("Result: %d", sum)
3435
}
3536

3637
func part2(
37-
input string,
38-
) string {
39-
finds := r.FindAllSubmatch([]byte(input), -1)
38+
input util.AocInput,
39+
) (util.AocSolution, util.AocError) {
40+
finds := r.FindAllSubmatch([]byte(input.Input), -1)
4041
sum := 0
4142

4243
enabled := true
@@ -47,7 +48,7 @@ func part2(
4748
if enabled {
4849
multiplied, err := mul(string(match[3]), string(match[4]))
4950
if err != nil {
50-
return fmt.Sprintf("Failed to parse multiplication of %q:\n%v\n", match, err)
51+
return util.NewAocError(fmt.Sprintf("Failed to parse multiplication of %q:\n%v\n", match, err), util.ParsingError)
5152
}
5253
sum += multiplied
5354
}
@@ -58,7 +59,7 @@ func part2(
5859
}
5960
}
6061

61-
return fmt.Sprintf("Result: %d", sum)
62+
return util.FormatAocSolution("Result: %d", sum)
6263
}
6364

6465
func mul(sub1 string, sub2 string) (int, error) {

‎solutions/day04/main.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
65
"github.com/terminalnode/adventofcode2024/common/util"
76
)
@@ -14,11 +13,11 @@ func main() {
1413
}
1514

1615
func part1(
17-
input string,
18-
) string {
19-
m, err := util.NewCharMatrix(input)
16+
input util.AocInput,
17+
) (util.AocSolution, util.AocError) {
18+
m, err := util.NewCharMatrix(input.Input)
2019
if err != nil {
21-
return fmt.Sprintf("Failed to build matrix: %v", err)
20+
return util.NewAocError(err.Error(), util.InputParsingError)
2221
}
2322

2423
count := 0
@@ -40,15 +39,15 @@ func part1(
4039
}
4140
}
4241

43-
return fmt.Sprintf("Number of XMAS: %d", count)
42+
return util.FormatAocSolution("Number of XMAS: %d", count)
4443
}
4544

4645
func part2(
47-
input string,
48-
) string {
49-
m, err := util.NewCharMatrix(input)
46+
input util.AocInput,
47+
) (util.AocSolution, util.AocError) {
48+
m, err := util.NewCharMatrix(input.Input)
5049
if err != nil {
51-
return fmt.Sprintf("Failed to build matrix: %v", err)
50+
return util.NewAocError(err.Error(), util.InputParsingError)
5251
}
5352
count := 0
5453
for x := 1; x < m.MaxX; x++ {
@@ -96,7 +95,7 @@ func part2(
9695
}
9796
}
9897

99-
return fmt.Sprintf("Number of X-shaped MAS: %d", count)
98+
return util.FormatAocSolution("Number of X-shaped MAS: %d", count)
10099
}
101100

102101
func searchXmas(

‎solutions/day05/main.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"github.com/terminalnode/adventofcode2024/common"
7+
"github.com/terminalnode/adventofcode2024/common/util"
78
"strconv"
89
"strings"
910
)
@@ -21,11 +22,11 @@ func main() {
2122
}
2223

2324
func part1(
24-
input string,
25-
) string {
26-
parsed, err := parseInput(input)
25+
input util.AocInput,
26+
) (util.AocSolution, util.AocError) {
27+
parsed, err := parseInput(input.Input)
2728
if err != nil {
28-
return fmt.Sprintf("Failed to parse input: %v", err)
29+
return util.NewAocError(err.Error(), util.InputParsingError)
2930
}
3031

3132
sum := 0
@@ -34,15 +35,15 @@ func part1(
3435
sum += manual[len(manual)/2]
3536
}
3637

37-
return fmt.Sprintf("Sum of middle numbers: %d", sum)
38+
return util.FormatAocSolution("Sum of middle numbers: %d", sum)
3839
}
3940

4041
func part2(
41-
input string,
42-
) string {
43-
parsed, err := parseInput(input)
42+
input util.AocInput,
43+
) (util.AocSolution, util.AocError) {
44+
parsed, err := parseInput(input.Input)
4445
if err != nil {
45-
return fmt.Sprintf("Failed to parse input: %v", err)
46+
return util.NewAocError(err.Error(), util.InputParsingError)
4647
}
4748

4849
sum := 0
@@ -51,12 +52,12 @@ func part2(
5152
stopAt := len(manual) / 2
5253
corrected, err := correctManual(parsed.rules, manual, PageList{}, stopAt)
5354
if err != nil {
54-
return fmt.Sprintf("Failed to correct manual %v:\n%v", manual, err)
55+
return util.NewAocError(fmt.Sprintf("Failed to correct manual %v:\n%v", manual, err), util.ProcessingError)
5556
}
5657
sum += corrected[stopAt]
5758
}
5859

59-
return fmt.Sprintf("Sum of middle numbers (corrected manuals): %d", sum)
60+
return util.FormatAocSolution("Sum of middle numbers (corrected manuals): %d", sum)
6061
}
6162

6263
func divideCorrectManuals(

‎solutions/day06/main.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ func main() {
3636
}
3737

3838
func part1(
39-
input string,
40-
) string {
41-
parsed, err := parseInput(input)
39+
input util.AocInput,
40+
) (util.AocSolution, util.AocError) {
41+
parsed, err := parseInput(input.Input)
4242
if err != nil {
43-
return fmt.Sprintf("Failed to parse input: %v", err)
43+
return util.NewAocError(err.Error(), util.InputParsingError)
4444
}
4545

4646
for parsed.move() {
@@ -52,16 +52,16 @@ func part1(
5252
count += len(xMap)
5353
}
5454

55-
return fmt.Sprintf("Visited spots in the Matrix: %d", count)
55+
return util.FormatAocSolution("Visited spots in the Matrix: %d", count)
5656
}
5757

5858
func part2(
59-
input string,
60-
) string {
59+
input util.AocInput,
60+
) (util.AocSolution, util.AocError) {
6161
// Solve part 1 first to know where to place obstacles
62-
original, err := parseInput(input)
62+
original, err := parseInput(input.Input)
6363
if err != nil {
64-
return fmt.Sprintf("Failed to parse input: %v", err)
64+
return util.NewAocError(err.Error(), util.InputParsingError)
6565
}
6666

6767
originalX := original.Guard.X
@@ -101,7 +101,7 @@ func part2(
101101
}
102102
}
103103

104-
return fmt.Sprintf("%d of the available %d positions make him loopy!", count, attempts)
104+
return util.FormatAocSolution("%d of the available %d positions make him loopy!", count, attempts)
105105
}
106106

107107
func parseInput(

‎solutions/day07/main.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"strconv"
78
"strings"
89
)
@@ -17,11 +18,11 @@ func main() {
1718
}
1819

1920
func part1(
20-
input string,
21-
) string {
22-
equations, err := parseEquations(input)
21+
input util.AocInput,
22+
) (util.AocSolution, util.AocError) {
23+
equations, err := parseEquations(input.Input)
2324
if err != nil {
24-
return fmt.Sprintf("Failed to parse input: %v", err)
25+
return util.NewAocError(err.Error(), util.InputParsingError)
2526
}
2627

2728
sum := 0
@@ -31,15 +32,15 @@ func part1(
3132
}
3233
}
3334

34-
return fmt.Sprintf("Sum of all OK tests: %d", sum)
35+
return util.FormatAocSolution("Sum of all OK tests: %d", sum)
3536
}
3637

3738
func part2(
38-
input string,
39-
) string {
40-
equations, err := parseEquations(input)
39+
input util.AocInput,
40+
) (util.AocSolution, util.AocError) {
41+
equations, err := parseEquations(input.Input)
4142
if err != nil {
42-
return fmt.Sprintf("Failed to parse input: %v", err)
43+
return util.NewAocError(err.Error(), util.InputParsingError)
4344
}
4445

4546
sum := 0
@@ -49,7 +50,7 @@ func part2(
4950
}
5051
}
5152

52-
return fmt.Sprintf("Sum of all OK tests: %d", sum)
53+
return util.FormatAocSolution("Sum of all OK tests: %d", sum)
5354
}
5455

5556
func parseEquations(

‎solutions/day08/main.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ func main() {
1111
}
1212

1313
func part1(
14-
input string,
15-
) string {
16-
m, err := util.NewCharMatrix(input)
14+
input util.AocInput,
15+
) (util.AocSolution, util.AocError) {
16+
m, err := util.NewCharMatrix(input.Input)
1717
if err != nil {
18-
return fmt.Sprintf("Failed to parse input: %v", err)
18+
return util.NewAocError(err.Error(), util.InputParsingError)
1919
}
2020

2121
coords := make(map[uint8][]util.Coordinate)
@@ -49,15 +49,15 @@ func part1(
4949
}
5050
}
5151

52-
return fmt.Sprintf("Unique anti nodes: %d", len(antiNodeSet))
52+
return util.FormatAocSolution("Unique anti nodes: %d", len(antiNodeSet))
5353
}
5454

5555
func part2(
56-
input string,
57-
) string {
58-
m, err := util.NewCharMatrix(input)
56+
input util.AocInput,
57+
) (util.AocSolution, util.AocError) {
58+
m, err := util.NewCharMatrix(input.Input)
5959
if err != nil {
60-
return fmt.Sprintf("Failed to parse input: %v", err)
60+
return util.NewAocError(err.Error(), util.InputParsingError)
6161
}
6262

6363
coords := make(map[uint8][]util.Coordinate)
@@ -106,7 +106,7 @@ func part2(
106106
}
107107
}
108108

109-
return fmt.Sprintf("Unique anti nodes (with resonance): %d", len(antiNodeSet))
109+
return util.FormatAocSolution("Unique anti nodes (with resonance): %d", len(antiNodeSet))
110110
}
111111

112112
func addCoordinateToSet(

‎solutions/day09/main.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
5+
"github.com/terminalnode/adventofcode2024/common/util"
66
)
77

88
func main() {
99
common.Setup(9, part1, part2)
1010
}
1111

1212
func part1(
13-
input string,
14-
) string {
13+
input util.AocInput,
14+
) (util.AocSolution, util.AocError) {
1515
sum := 0
16-
disk := parse(input)
16+
disk := parse(input.Input)
1717
backIndex := len(disk)
1818

1919
for i, id := range disk {
@@ -34,14 +34,14 @@ func part1(
3434
}
3535
}
3636

37-
return fmt.Sprintf("Sum: %d", sum)
37+
return util.FormatAocSolution("Sum: %d", sum)
3838
}
3939

4040
func part2(
41-
input string,
42-
) string {
41+
input util.AocInput,
42+
) (util.AocSolution, util.AocError) {
4343
sum := 0
44-
disk := parseFileList(input)
44+
disk := parseFileList(input.Input)
4545

4646
bkw := len(disk) - 1
4747
for bkw > 0 {
@@ -97,5 +97,5 @@ func part2(
9797
}
9898
}
9999

100-
return fmt.Sprintf("Sum: %d", sum)
100+
return util.FormatAocSolution("Sum: %d", sum)
101101
}

‎solutions/day10/main.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ func main() {
1212
}
1313

1414
func part1(
15-
input string,
16-
) string {
17-
topo := parseTopographicMap(input)
15+
input util.AocInput,
16+
) (util.AocSolution, util.AocError) {
17+
topo := parseTopographicMap(input.Input)
1818

1919
out := 0
2020
for y := 0; y < len(topo); y++ {
@@ -31,13 +31,13 @@ func part1(
3131
}
3232
}
3333

34-
return fmt.Sprintf("Number of trails: %d", out)
34+
return util.FormatAocSolution("Number of trails: %d", out)
3535
}
3636

3737
func part2(
38-
input string,
39-
) string {
40-
topo := parseTopographicMap(input)
38+
input util.AocInput,
39+
) (util.AocSolution, util.AocError) {
40+
topo := parseTopographicMap(input.Input)
4141

4242
out := 0
4343
for y := 0; y < len(topo); y++ {
@@ -52,7 +52,7 @@ func part2(
5252
}
5353
}
5454

55-
return fmt.Sprintf("Number of distinct trails: %d", out)
55+
return util.FormatAocSolution("Number of distinct trails: %d", out)
5656
}
5757

5858
func parseTopographicMap(

‎solutions/day11/main.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,41 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"strconv"
78
"strings"
89
)
910

1011
// Stone => blinks remaining => output
1112
type blinkCache = map[int]map[int]int
1213

13-
func main() {
14-
common.Setup(11, part1, part2)
15-
}
16-
17-
func part1(input string) string { return solve(input, 25) }
18-
19-
func part2(input string) string { return solve(input, 75) }
14+
func main() { common.Setup(11, part1, part2) }
15+
func part1(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input.Input, 25) }
16+
func part2(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input.Input, 75) }
2017

2118
func solve(
2219
input string,
2320
blinks int,
24-
) string {
21+
) (util.AocSolution, util.AocError) {
2522
stones, err := parseStones(input)
2623
cache := make(blinkCache)
2724
if err != nil {
28-
return fmt.Sprintf("Failed to parse stones: %v", err)
25+
return util.NewAocError(fmt.Sprintf("Failed to parse stones: %v", err), util.InputParsingError)
2926
}
3027
lenStart := len(stones)
3128

3229
out := 0
3330
for i, stone := range stones {
3431
result, err := blink(stone, blinks, cache)
3532
if err != nil {
36-
return fmt.Sprintf("Failed to blink stone #%d (%d): %v", i+1, stone, err)
33+
return util.NewAocError(fmt.Sprintf("Failed to blink stone #%d (%d): %v", i+1, stone, err), util.ProcessingError)
3734
}
3835

3936
out += result
4037
fmt.Printf("Stone with value %d resulted in %d (out = %d)\n", stone, result, out)
4138
}
4239

43-
return fmt.Sprintf("%d stones have turned into %d after %d blinks", lenStart, out, blinks)
40+
return util.NewAocSolution(fmt.Sprintf("%d stones have turned into %d after %d blinks", lenStart, out, blinks))
4441
}
4542

4643
func parseStones(

‎solutions/day12/main.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
65
"github.com/terminalnode/adventofcode2024/common/util"
76
"log"
@@ -19,11 +18,11 @@ func main() {
1918
}
2019

2120
func part1(
22-
input string,
23-
) string {
21+
input util.AocInput,
22+
) (util.AocSolution, util.AocError) {
2423
sum := 0
2524
fields := 0
26-
plots := parsePlots(input)
25+
plots := parsePlots(input.Input)
2726
visited := make(map[string]bool)
2827

2928
rows := len(plots)
@@ -42,15 +41,15 @@ func part1(
4241
}
4342
}
4443

45-
return fmt.Sprintf("Area * perimeter of %d fields: %d", fields, sum)
44+
return util.FormatAocSolution("Area * perimeter of %d fields: %d", fields, sum)
4645
}
4746

4847
func part2(
49-
input string,
50-
) string {
48+
input util.AocInput,
49+
) (util.AocSolution, util.AocError) {
5150
sum := 0
5251
fields := 0
53-
plots := parsePlots(input)
52+
plots := parsePlots(input.Input)
5453
visited := make(map[string]bool)
5554

5655
rows := len(plots)
@@ -69,7 +68,7 @@ func part2(
6968
}
7069
}
7170

72-
return fmt.Sprintf("Area * sides of %d fields: %d", fields, sum)
71+
return util.FormatAocSolution("Area * sides of %d fields: %d", fields, sum)
7372
}
7473

7574
func parsePlots(

‎solutions/day13/main.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
5+
"github.com/terminalnode/adventofcode2024/common/util"
66
)
77

8-
func main() { common.Setup(13, part1, part2) }
9-
func part1(input string) string { return solve(input, false) }
10-
func part2(input string) string { return solve(input, true) }
8+
func main() { common.Setup(13, part1, part2) }
9+
func part1(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, false) }
10+
func part2(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, true) }
1111

1212
func solve(
13-
input string,
13+
input util.AocInput,
1414
part2 bool,
15-
) string {
16-
problems, err := parseProblems(input, part2)
15+
) (util.AocSolution, util.AocError) {
16+
problems, err := parseProblems(input.Input, part2)
1717
if err != nil {
18-
return fmt.Sprintf("Failed to parse input: %v", err)
18+
return util.NewAocError(err.Error(), util.InputParsingError)
1919
}
2020

2121
sum := int64(0)
@@ -32,5 +32,5 @@ func solve(
3232
}
3333
}
3434

35-
return fmt.Sprintf("Cost is %d tokens to solve these %d claw machines", sum, len(problems))
35+
return util.FormatAocSolution("Cost is %d tokens to solve these %d claw machines", sum, len(problems))
3636
}

‎solutions/day14/main.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"bytes"
5-
"fmt"
65
"github.com/terminalnode/adventofcode2024/common"
76
"github.com/terminalnode/adventofcode2024/common/util"
87
"regexp"
@@ -18,11 +17,11 @@ func main() {
1817
}
1918

2019
func part1(
21-
input string,
22-
) string {
23-
robots, err := parseRobots(input)
20+
input util.AocInput,
21+
) (util.AocSolution, util.AocError) {
22+
robots, err := parseRobots(input.Input)
2423
if err != nil {
25-
return fmt.Sprintf("Failed to parse robots: %v", err)
24+
return util.NewAocError(err.Error(), util.InputParsingError)
2625
}
2726

2827
q1, q2, q3, q4 := 0, 0, 0, 0
@@ -42,15 +41,15 @@ func part1(
4241
}
4342
}
4443

45-
return fmt.Sprintf("After 100 seconds, area has a safety factor of %d", q1*q2*q3*q4)
44+
return util.FormatAocSolution("After 100 seconds, area has a safety factor of %d", q1*q2*q3*q4)
4645
}
4746

4847
func part2(
49-
input string,
50-
) string {
51-
robots, err := parseRobots(input)
48+
input util.AocInput,
49+
) (util.AocSolution, util.AocError) {
50+
robots, err := parseRobots(input.Input)
5251
if err != nil {
53-
return fmt.Sprintf("Failed to parse robots: %v", err)
52+
return util.NewAocError(err.Error(), util.InputParsingError)
5453
}
5554

5655
// The image we're looking for has a frame, and all non-image parts seem highly irregular.
@@ -84,7 +83,7 @@ func part2(
8483
}
8584
}
8685

87-
return fmt.Sprintf("Answer is probably %d", step)
86+
return util.FormatAocSolution("Answer is probably %d", step)
8887
}
8988

9089
func getNewPositions(

‎solutions/day15/main.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,23 @@ package main
22

33
import (
44
"errors"
5-
"fmt"
65
"github.com/terminalnode/adventofcode2024/common"
76
"github.com/terminalnode/adventofcode2024/common/util"
87
)
98

10-
func main() { common.Setup(15, part1, part2) }
11-
func part1(input string) string { return solve(input, false) }
12-
func part2(input string) string { return solve(input, true) }
9+
func main() { common.Setup(15, part1, part2) }
10+
func part1(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, false) }
11+
func part2(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, true) }
1312

1413
type visitedSet = map[int]map[int]bool
1514

1615
func solve(
17-
input string,
16+
input util.AocInput,
1817
makeWide bool,
19-
) string {
20-
p, err := parse(input, makeWide)
18+
) (util.AocSolution, util.AocError) {
19+
p, err := parse(input.Input, makeWide)
2120
if err != nil {
22-
return fmt.Sprintf("Failed to parse input: %v", err)
21+
return util.NewAocError(err.Error(), util.InputParsingError)
2322
}
2423

2524
for _, move := range p.moves {
@@ -45,9 +44,9 @@ func solve(
4544
}
4645

4746
if makeWide {
48-
return fmt.Sprintf("Sum of all GPS coordinates in the wide area: %d", score(p.warehouse))
47+
return util.FormatAocSolution("Sum of all GPS coordinates in the wide area: %d", score(p.warehouse))
4948
}
50-
return fmt.Sprintf("Sum of all GPS coordinates: %d", score(p.warehouse))
49+
return util.FormatAocSolution("Sum of all GPS coordinates: %d", score(p.warehouse))
5150
}
5251

5352
type boxMove struct {

‎solutions/day16/main.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
5+
"github.com/terminalnode/adventofcode2024/common/util"
66
"math"
77
)
88

@@ -11,26 +11,26 @@ func main() {
1111
}
1212

1313
func part1(
14-
input string,
15-
) string {
16-
i, err := parse(input)
14+
input util.AocInput,
15+
) (util.AocSolution, util.AocError) {
16+
i, err := parse(input.Input)
1717
if err != nil {
18-
return fmt.Sprintf("Failed to parse input: %v", err)
18+
return util.NewAocError(err.Error(), util.InputParsingError)
1919
}
2020

2121
// Initialize visited set with end point
2222
set := initializeVisitedSet(i)
2323
loop(initialReindeer(i.s), i, set, initializeWinningSet(i), -1)
2424

25-
return fmt.Sprintf("Cheapest path: %v", lowestSoFar(i, set))
25+
return util.FormatAocSolution("Cheapest path: %v", lowestSoFar(i, set))
2626
}
2727

2828
func part2(
29-
input string,
30-
) string {
31-
i, err := parse(input)
29+
input util.AocInput,
30+
) (util.AocSolution, util.AocError) {
31+
i, err := parse(input.Input)
3232
if err != nil {
33-
return fmt.Sprintf("Failed to parse input: %v", err)
33+
return util.NewAocError(err.Error(), util.InputParsingError)
3434
}
3535

3636
// Initialize visited set with end point
@@ -49,7 +49,7 @@ func part2(
4949
count += len(ys)
5050
}
5151

52-
return fmt.Sprintf("Best seats: %d", count)
52+
return util.FormatAocSolution("Best seats: %d", count)
5353
}
5454

5555
func loop(

‎solutions/day17/main.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"strconv"
78
"strings"
89
)
@@ -12,22 +13,22 @@ func main() {
1213
}
1314

1415
func part1(
15-
input string,
16-
) string {
17-
m, err := parseMachine(input)
16+
input util.AocInput,
17+
) (util.AocSolution, util.AocError) {
18+
m, err := parseMachine(input.Input)
1819
if err != nil {
19-
return fmt.Sprintf("Failed to parse machine: %v", err)
20+
return util.NewAocError(err.Error(), util.InputParsingError)
2021
}
2122
m.run(-1)
22-
return m.strOut()
23+
return util.NewAocSolution(m.strOut())
2324
}
2425

2526
func part2(
26-
input string,
27-
) string {
28-
m, err := parseMachine(input)
27+
input util.AocInput,
28+
) (util.AocSolution, util.AocError) {
29+
m, err := parseMachine(input.Input)
2930
if err != nil {
30-
return fmt.Sprintf("Failed to parse machine: %v", err)
31+
return util.NewAocError(err.Error(), util.InputParsingError)
3132
}
3233

3334
maxIdx := len(m.seq) - 1
@@ -47,7 +48,8 @@ func part2(
4748

4849
m.a, err = arrayToOct(octArr)
4950
if err != nil {
50-
return fmt.Sprintf("Failed to read %v as octal string: %v", octArr, err)
51+
msg := fmt.Sprintf("Solved it, but failed to extract number: %v", err)
52+
return util.NewAocError(msg, util.ParsingError)
5153
}
5254

5355
// Run the program and verify output
@@ -69,9 +71,10 @@ func part2(
6971

7072
final, err := arrayToOct(octArr)
7173
if err != nil {
72-
return fmt.Sprintf("Solved it, but failed to extract number: %v", err)
74+
msg := fmt.Sprintf("Solved it, but failed to extract number: %v", err)
75+
return util.NewAocError(msg, util.ParsingError)
7376
}
74-
return fmt.Sprintf("Registry A should be %d", final)
77+
return util.FormatAocSolution("Registry A should be %d", final)
7578
}
7679

7780
func arrayToOct(

‎solutions/day17/main_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"github.com/terminalnode/adventofcode2024/common/util"
45
"testing"
56
)
67

@@ -50,8 +51,8 @@ Register C: 0
5051
Program: 0,1,5,4,3,0`
5152
const exOut = "4,6,3,5,6,3,5,2,1,0"
5253

53-
out := part1(ex)
54-
if out != exOut {
54+
out, _ := part1(util.AocInput{Input: ex})
55+
if out.Solution != exOut {
5556
t.Errorf("expected '%s' but got '%s'", exOut, out)
5657
}
5758
}
@@ -64,8 +65,8 @@ Register C: 0
6465
Program: 0,3,5,4,3,0`
6566
exOut := "Registry A should be 117440"
6667

67-
out := part2(ex)
68-
if out != exOut {
68+
out, _ := part2(util.AocInput{Input: ex})
69+
if out.Solution != exOut {
6970
t.Errorf("expected '%s' but got '%s'", exOut, out)
7071
}
7172
}

‎solutions/day18/main.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
65
"github.com/terminalnode/adventofcode2024/common/util"
76
)
@@ -11,12 +10,12 @@ func main() {
1110
}
1211

1312
func part1(
14-
input string,
15-
) string {
13+
input util.AocInput,
14+
) (util.AocSolution, util.AocError) {
1615
m := buildMatrix()
17-
cs, err := parse(input)
16+
cs, err := parse(input.Input)
1817
if err != nil {
19-
return fmt.Sprintf("Failed to parse input: %v", err)
18+
return util.NewAocError(err.Error(), util.InputParsingError)
2019
}
2120

2221
for _, c := range cs[:1024] {
@@ -29,16 +28,16 @@ func part1(
2928
shortestPath(m, start, end, 0, visitedSet)
3029

3130
shortest := visitedSet[70][70]
32-
return fmt.Sprintf("Shortest path is %d steps", shortest)
31+
return util.FormatAocSolution("Shortest path is %d steps", shortest)
3332
}
3433

3534
func part2(
36-
input string,
37-
) string {
35+
input util.AocInput,
36+
) (util.AocSolution, util.AocError) {
3837
m := buildMatrix()
39-
cs, err := parse(input)
38+
cs, err := parse(input.Input)
4039
if err != nil {
41-
return fmt.Sprintf("Failed to parse input: %v", err)
40+
return util.NewAocError(err.Error(), util.InputParsingError)
4241
}
4342

4443
// Initialize everything
@@ -63,7 +62,7 @@ func part2(
6362
success = anyPath(m, start, end, buildVisitedSet[bool](), winningSet)
6463
}
6564

66-
return fmt.Sprintf("The byte that broke the camel's back was %s", latest)
65+
return util.FormatAocSolution("The byte that broke the camel's back was %s", latest)
6766
}
6867

6968
func buildMatrix() [][]bool {

‎solutions/day19/main.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"regexp"
78
"strings"
89
)
@@ -12,11 +13,11 @@ func main() {
1213
}
1314

1415
func part1(
15-
input string,
16-
) string {
17-
p, err := parse(input)
16+
input util.AocInput,
17+
) (util.AocSolution, util.AocError) {
18+
p, err := parse(input.Input)
1819
if err != nil {
19-
return fmt.Sprintf("Failed to parse input: %v", err)
20+
return util.NewAocError(err.Error(), util.InputParsingError)
2021
}
2122

2223
join := strings.Join(p.available, "|")
@@ -29,15 +30,15 @@ func part1(
2930
}
3031
}
3132

32-
return fmt.Sprintf("%d of the %d desired designs are possible", count, len(p.desired))
33+
return util.FormatAocSolution("%d of the %d desired designs are possible", count, len(p.desired))
3334
}
3435

3536
func part2(
36-
input string,
37-
) string {
38-
p, err := parse(input)
37+
input util.AocInput,
38+
) (util.AocSolution, util.AocError) {
39+
p, err := parse(input.Input)
3940
if err != nil {
40-
return fmt.Sprintf("Failed to parse input: %v", err)
41+
return util.NewAocError(err.Error(), util.InputParsingError)
4142
}
4243

4344
cache := make(map[string]int)
@@ -47,7 +48,7 @@ func part2(
4748
count += n
4849
}
4950

50-
return fmt.Sprintf("Number of available combinations: %d", count)
51+
return util.FormatAocSolution("Number of available combinations: %d", count)
5152
}
5253

5354
func loop(

‎solutions/day20/main.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,23 @@ func main() {
1111
common.Setup(20, part1, part2)
1212
}
1313

14-
func part1(input string) string { return solve(input, 2, 100) }
15-
func part2(input string) string { return solve(input, 20, 100) }
14+
func part1(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, 2, 100) }
15+
func part2(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, 20, 100) }
1616

1717
func solve(
18-
input string,
18+
input util.AocInput,
1919
steps int,
2020
limit int,
21-
) string {
22-
p, err := parse(input)
21+
) (util.AocSolution, util.AocError) {
22+
p, err := parse(input.Input)
2323
if err != nil {
24-
return fmt.Sprintf("Failed to parse input: %v", err)
24+
return util.NewAocError(err.Error(), util.InputParsingError)
2525
}
2626

2727
dm, path, err := p.createDistanceMap()
2828
if err != nil {
29-
return fmt.Sprintf("Failed to create distance map: %v", err)
29+
msg := fmt.Sprintf("Failed to create distance map: %v", err)
30+
return util.NewAocError(msg, util.ProcessingError)
3031
}
3132

3233
cheatCounts := make(map[int]int)
@@ -43,7 +44,7 @@ func solve(
4344
}
4445
}
4546

46-
return fmt.Sprintf("Number of cheats saving at least %d ps: %d", limit, count)
47+
return util.FormatAocSolution("Number of cheats saving at least %d ps: %d", limit, count)
4748
}
4849

4950
func findAllCheats(

‎solutions/day21/main.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,29 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"strconv"
78
"strings"
89
)
910

1011
func main() { common.Setup(21, part1, part2) }
1112

12-
func part1(input string) string { return solve(input, 2) }
13-
func part2(input string) string { return solve(input, 25) }
13+
func part1(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, 2) }
14+
func part2(input util.AocInput) (util.AocSolution, util.AocError) { return solve(input, 25) }
1415

1516
func solve(
16-
input string,
17+
input util.AocInput,
1718
robots int,
18-
) string {
19+
) (util.AocSolution, util.AocError) {
1920
cache := make(cacheMap)
2021

21-
sequences := strings.Split(input, "\n")
22+
sequences := strings.Split(input.Input, "\n")
2223
sum := 0
2324
for _, code := range sequences {
2425
codeNumeric, err := strconv.Atoi(code[:len(code)-1])
2526
if err != nil {
26-
return fmt.Sprintf("Failed to parse code %s as int: %v", code, err)
27+
msg := fmt.Sprintf("Failed to parse code %s as int: %v", code, err)
28+
return util.NewAocError(msg, util.StringToNumber)
2729
}
2830

2931
// Five is the longest path between two keys on numeric pad
@@ -43,5 +45,5 @@ func solve(
4345
sum += pathLen * codeNumeric
4446
}
4547

46-
return fmt.Sprintf("Sum: %d", sum)
48+
return util.FormatAocSolution("Sum: %d", sum)
4749
}

‎solutions/day22/main.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"strconv"
78
"strings"
89
)
@@ -12,11 +13,11 @@ func main() {
1213
}
1314

1415
func part1(
15-
input string,
16-
) string {
17-
secrets, err := parse(input)
16+
input util.AocInput,
17+
) (util.AocSolution, util.AocError) {
18+
secrets, err := parse(input.Input)
1819
if err != nil {
19-
return fmt.Sprintf("Failed to parse input: %v", err)
20+
return util.NewAocError(err.Error(), util.InputParsingError)
2021
}
2122

2223
sum := 0
@@ -27,7 +28,7 @@ func part1(
2728
sum += secret
2829
}
2930

30-
return fmt.Sprintf("Sum of all secret numbers after 2k rounds: %d", sum)
31+
return util.FormatAocSolution("Sum of all secret numbers after 2k rounds: %d", sum)
3132
}
3233

3334
type priceDiff struct {
@@ -36,11 +37,11 @@ type priceDiff struct {
3637
}
3738

3839
func part2(
39-
input string,
40-
) string {
41-
secrets, err := parse(input)
40+
input util.AocInput,
41+
) (util.AocSolution, util.AocError) {
42+
secrets, err := parse(input.Input)
4243
if err != nil {
43-
return fmt.Sprintf("Failed to parse input: %v", err)
44+
return util.NewAocError(err.Error(), util.InputParsingError)
4445
}
4546

4647
allKeys := make(map[string]bool)
@@ -88,7 +89,7 @@ func part2(
8889
}
8990
}
9091

91-
return fmt.Sprintf("Max number of bananas %d (%s)", bestSum, bestKey)
92+
return util.FormatAocSolution("Max number of bananas %d (%s)", bestSum, bestKey)
9293
}
9394

9495
func priceOf(n int) int {

‎solutions/day23/main.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"slices"
78
"strings"
89
)
@@ -12,11 +13,11 @@ func main() {
1213
}
1314

1415
func part1(
15-
input string,
16-
) string {
17-
cm, err := parse(input)
16+
input util.AocInput,
17+
) (util.AocSolution, util.AocError) {
18+
cm, err := parse(input.Input)
1819
if err != nil {
19-
return fmt.Sprintf("Failed to parse input: %v", err)
20+
return util.NewAocError(err.Error(), util.InputParsingError)
2021
}
2122

2223
visited := make(map[string]bool)
@@ -34,15 +35,16 @@ func part1(
3435
}
3536
}
3637

37-
return fmt.Sprintf("Clusters of 3 with computers starting with t: %d", len(visited))
38+
return util.FormatAocSolution("Clusters of 3 with computers starting with t: %d", len(visited))
3839
}
3940

4041
func part2(
41-
input string,
42-
) string {
43-
cliques, err := getCliques(input)
42+
input util.AocInput,
43+
) (util.AocSolution, util.AocError) {
44+
cliques, err := getCliques(input.Input)
4445
if err != nil {
45-
return fmt.Sprintf("Failed to get cliques: %v", err)
46+
msg := fmt.Sprintf("Failed to get cliques: %v", err)
47+
return util.NewAocError(msg, util.InputParsingError)
4648
}
4749

4850
var biggest []string
@@ -53,7 +55,7 @@ func part2(
5355
}
5456
slices.Sort(biggest)
5557

56-
return fmt.Sprintf("Password: %s", strings.Join(biggest, ","))
58+
return util.FormatAocSolution("Password: %s", strings.Join(biggest, ","))
5759
}
5860

5961
func getCliques(

‎solutions/day24/main.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
6+
"github.com/terminalnode/adventofcode2024/common/util"
67
"log"
78
"math/bits"
89
"slices"
@@ -15,28 +16,29 @@ func main() {
1516
}
1617

1718
func part1(
18-
input string,
19-
) string {
20-
r, wm, err := parse(input)
19+
input util.AocInput,
20+
) (util.AocSolution, util.AocError) {
21+
r, wm, err := parse(input.Input)
2122
if err != nil {
22-
return fmt.Sprintf("Failed to parse input: %v", err)
23+
return util.NewAocError(err.Error(), util.InputParsingError)
2324
}
2425
zNames := findIndexes('z', r, wm)
2526
resolveNames(r, wm, zNames)
2627
out, strOut, err := toInt(r, zNames)
2728
if err != nil {
28-
return fmt.Sprintf("Failed to read %s as binary: %v", strOut, err)
29+
msg := fmt.Sprintf("Failed to read %s as binary: %v", strOut, err)
30+
return util.NewAocError(msg, util.InputParsingError)
2931
}
3032

31-
return fmt.Sprintf("Decimal output is %d (binary %s)", out, strOut)
33+
return util.FormatAocSolution("Decimal output is %d (binary %s)", out, strOut)
3234
}
3335

3436
func part2(
35-
input string,
36-
) string {
37-
r, wm, err := parse(input)
37+
input util.AocInput,
38+
) (util.AocSolution, util.AocError) {
39+
r, wm, err := parse(input.Input)
3840
if err != nil {
39-
return fmt.Sprintf("Failed to parse input: %v", err)
41+
return util.NewAocError(err.Error(), util.InputParsingError)
4042
}
4143

4244
zWrong := make([]name, 0)
@@ -61,8 +63,8 @@ func part2(
6163
pairs := make([][2]name, 0, 3)
6264
for _, carry := range carryWrong {
6365
zOutput := findFirstZ(carry, wm)
64-
zNum, _ := strconv.Atoi(string(zOutput[1:]))
65-
pairs = append(pairs, [2]name{carry, name(fmt.Sprintf("z%02d", zNum-1))})
66+
zNum, _ := strconv.Atoi(zOutput[1:])
67+
pairs = append(pairs, [2]name{carry, fmt.Sprintf("z%02d", zNum-1)})
6668
}
6769

6870
xNames := findIndexes('x', r, wm)
@@ -93,7 +95,7 @@ func part2(
9395
final = append(final, lastPair...)
9496
slices.Sort(final)
9597

96-
return strings.Join(final, ",")
98+
return util.NewAocSolution(strings.Join(final, ","))
9799
}
98100

99101
func findFirstZ(
@@ -224,7 +226,7 @@ func findIndexes(
224226
) []name {
225227
out := make([]name, 0, 30)
226228
for curr := 0; ; curr++ {
227-
key := name(fmt.Sprintf("%c%02d", prefix, curr))
229+
key := fmt.Sprintf("%c%02d", prefix, curr)
228230
_, inR := r[key]
229231
_, inWM := wm[key]
230232
if !inR && !inWM {

‎solutions/day25/main.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package main
22

33
import (
4-
"fmt"
54
"github.com/terminalnode/adventofcode2024/common"
5+
"github.com/terminalnode/adventofcode2024/common/util"
66
)
77

88
func main() {
9-
common.Setup(25, part1, nil)
9+
common.Setup(25, part1, part2)
1010
}
1111

1212
func part1(
13-
input string,
14-
) string {
15-
keys, locks := parse(input)
13+
input util.AocInput,
14+
) (util.AocSolution, util.AocError) {
15+
keys, locks := parse(input.Input)
1616
count := 0
1717
for _, key := range keys {
1818
for _, lock := range locks {
@@ -30,5 +30,11 @@ func part1(
3030
}
3131
}
3232

33-
return fmt.Sprintf("Number of ok key-lock combos: %d", count)
33+
return util.FormatAocSolution("Number of ok key-lock combos: %d", count)
34+
}
35+
36+
func part2(
37+
_ util.AocInput,
38+
) (util.AocSolution, util.AocError) {
39+
return util.NewAocSolution("Maybe the true day 25 part 2 were the friends we made along the way?")
3440
}

0 commit comments

Comments
 (0)
This repository has been archived.