refactor: massive refactor to have only one binary to call
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day01
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day02
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day03
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day04
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day05
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2020/day06
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2021/day01
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2021/day02
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module 2021/day03
|
|
||||||
|
|
||||||
go 1.25.4
|
|
||||||
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
GO = go
|
||||||
|
BIN = bin/aoc
|
||||||
|
|
||||||
|
.PHONY: build test clean
|
||||||
|
|
||||||
|
build:
|
||||||
|
$(GO) build -o $(BIN) ./cmd/aoc
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(GO) test ./...
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN)
|
||||||
72
README.md
72
README.md
@@ -16,26 +16,61 @@ Also, it's a fresh start from 2025. I do some exercises from other years along t
|
|||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
yyyy/
|
├── cmd/
|
||||||
├── dayXX/
|
│ └── aoc/
|
||||||
│ ├── main.go # The main code to run to print solutions.
|
│ └── main.go # CLI entry point that runs solutions
|
||||||
│ ├── main_test.go # The test file that validates the logic.
|
└── internal/
|
||||||
│ └── input.txt # The day's puzzle input.
|
├── 2020/
|
||||||
└── ...
|
│ ├── DayOne/
|
||||||
|
│ │ ├── code.go # Go solution for Day 1 (2020)
|
||||||
|
│ │ └── code_test.go # Unit tests for Day 1
|
||||||
|
│ └── ...
|
||||||
|
├── 2021/
|
||||||
|
│ └── ... # Additional years and days
|
||||||
|
├── registry/
|
||||||
|
│ └── registry.go # Central registry for day runners
|
||||||
|
└── data/
|
||||||
|
├── 2020/
|
||||||
|
│ ├── DayOne/
|
||||||
|
│ │ └── input.txt # Puzzle input for Day 1 (2020)
|
||||||
|
│ └── ...
|
||||||
|
└── ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Each day's code can be run with:
|
Each day's solution is organized into its own folder, named according to the day number (e.g., `DayOne`, `DayTwo`). Inside each folder, you'll find a `code.go` file with the Go implementation of the solution and a `code_test.go` file containing corresponding tests. The input data for each puzzle is located in the `internal/data` directory, mirroring the code structure for easy access.
|
||||||
|
|
||||||
|
To connect each solution to the CLI, the repository uses a central registry located in `internal/registry/registry.go`. This registry is essentially a map linking a day key (combining year and day number) to assign a "day runner" which is a struct that specifies the `ParseInput`, `PartOne` and `PartTwo` functions of the day's problem.
|
||||||
|
|
||||||
|
When running a solution, the CLI (`cmd/aoc/main.go`) looks up the appropriate runner from the registry based on your command-line input, uses the parsing function to load the input data, and then runs the desired part (or both parts) using the registered solution functions.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Build the CLI tool:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd yyyy/dayXX
|
make
|
||||||
go run main.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected output:
|
Run a day's solution:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
Part 1: <answer>
|
bin/aoc 2020D1 # Run both parts
|
||||||
Part 2: <answer>
|
bin/aoc 2020D1P1 # Run only part one
|
||||||
|
bin/aoc 2020D1P2 # Run only part two
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ bin/aoc 2020D1
|
||||||
|
197451
|
||||||
|
138233720
|
||||||
|
|
||||||
|
$ bin/aoc 2020D1P1
|
||||||
|
197451
|
||||||
|
|
||||||
|
$ bin/aoc 2020D1P2
|
||||||
|
138233720
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
@@ -55,13 +90,18 @@ In this example, the calibration values of these four lines are 12, 38, 15, and
|
|||||||
Adding these together produces 142.
|
Adding these together produces 142.
|
||||||
```
|
```
|
||||||
|
|
||||||
I'm using these examples to validate my logic.
|
I'm using these examples each day to validate my logic.
|
||||||
|
|
||||||
If you want to run those, you can use:
|
Run all tests:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd dayXX
|
make test
|
||||||
go test
|
```
|
||||||
|
|
||||||
|
Or run tests for a specific day:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test ./internal/2020/DayOne/...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|||||||
56
cmd/aoc/main.go
Normal file
56
cmd/aoc/main.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"advent-of-code/internal/registry"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
_ "advent-of-code/internal/2020/DayFour"
|
||||||
|
_ "advent-of-code/internal/2020/DayOne"
|
||||||
|
_ "advent-of-code/internal/2020/DaySix"
|
||||||
|
_ "advent-of-code/internal/2020/DayThree"
|
||||||
|
_ "advent-of-code/internal/2020/DayTwo"
|
||||||
|
_ "advent-of-code/internal/2021/DayOne"
|
||||||
|
_ "advent-of-code/internal/2021/DayThree"
|
||||||
|
_ "advent-of-code/internal/2021/DayTwo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func capitalize(day string) string {
|
||||||
|
dayNames := map[string]string{
|
||||||
|
"1": "One", "2": "Two", "3": "Three", "4": "Four", "5": "Five",
|
||||||
|
"6": "Six", "7": "Seven", "8": "Eight", "9": "Nine", "10": "Ten",
|
||||||
|
"11": "Eleven", "12": "Twelve", "13": "Thirteen", "14": "Fourteen", "15": "Fifteen",
|
||||||
|
"16": "Sixteen", "17": "Seventeen", "18": "Eighteen", "19": "Nineteen", "20": "Twenty",
|
||||||
|
"21": "TwentyOne", "22": "TwentyTwo", "23": "TwentyThree", "24": "TwentyFour", "25": "TwentyFive",
|
||||||
|
}
|
||||||
|
return dayNames[day]
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage: %s <YEAR>D<DAY>[P<PART>]\n", os.Args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`^(\d{4})D(\d+)(?:P(\d+))?$`)
|
||||||
|
matches := re.FindStringSubmatch(os.Args[1])
|
||||||
|
if matches == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Invalid format: %s\n", os.Args[1])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
year, dayNum, part := matches[1], matches[2], matches[3]
|
||||||
|
dayKey := fmt.Sprintf("%sD%s", year, dayNum)
|
||||||
|
dayName := fmt.Sprintf("Day%s", capitalize(dayNum))
|
||||||
|
input := filepath.Join("internal", "data", year, dayName, "input.txt")
|
||||||
|
|
||||||
|
runner, ok := registry.Days[dayKey].(registry.Runner)
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("Day not found: %s\n", dayKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
runner.Run(input, part)
|
||||||
|
}
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
package main
|
package dayfive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D5", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
|
||||||
return strings.Split(string(content), "\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func calculateSeatID(pass string) int {
|
func calculateSeatID(pass string) int {
|
||||||
@@ -39,6 +34,11 @@ func calculateSeatID(pass string) int {
|
|||||||
return row*8 + column
|
return row*8 + column
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
|
return strings.Split(string(content), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
func PartOne(input []string) int {
|
func PartOne(input []string) int {
|
||||||
maxSeatID := 0
|
maxSeatID := 0
|
||||||
for _, pass := range input {
|
for _, pass := range input {
|
||||||
@@ -77,9 +77,3 @@ func PartTwo(input []string) int {
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
input := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(input))
|
|
||||||
fmt.Println("Part 2:", PartTwo(input))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package dayfive
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -32,3 +32,4 @@ func TestPartTwo(t *testing.T) {
|
|||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package main
|
package dayfour
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D4", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
|
|
||||||
text := string(content)
|
text := string(content)
|
||||||
passports := strings.Split(text, "\n\n")
|
passports := strings.Split(text, "\n\n")
|
||||||
@@ -152,8 +152,3 @@ func PartTwo(data []string) int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package dayfour
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ func TestPartOne(t *testing.T) {
|
|||||||
expected := 2
|
expected := 2
|
||||||
got := PartOne(testInput)
|
got := PartOne(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartOne(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartOne() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +21,7 @@ func TestPartTwo(t *testing.T) {
|
|||||||
expected := 2
|
expected := 2
|
||||||
got := PartTwo(testInput)
|
got := PartTwo(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartTwo(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,25 +1,22 @@
|
|||||||
package main
|
package dayone
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []int {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D1", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []int {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
lines := strings.Fields(string(content))
|
lines := strings.Fields(string(content))
|
||||||
var data []int
|
var data []int
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
num, err := strconv.Atoi(line)
|
num, _ := strconv.Atoi(line)
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to convert string to int: %v", err)
|
|
||||||
}
|
|
||||||
data = append(data, num)
|
data = append(data, num)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
@@ -51,8 +48,3 @@ func PartTwo(data []int) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package dayone
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ func TestPartOne(t *testing.T) {
|
|||||||
expected := 514579
|
expected := 514579
|
||||||
got := PartOne(testInput)
|
got := PartOne(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartOne(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartOne() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ func TestPartTwo(t *testing.T) {
|
|||||||
expected := 241861950
|
expected := 241861950
|
||||||
got := PartTwo(testInput)
|
got := PartTwo(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartTwo(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package main
|
package daysix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D6", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
return strings.Split(strings.TrimSpace(string(content)), "\n")
|
return strings.Split(strings.TrimSpace(string(content)), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +68,3 @@ func PartTwo(input []string) int {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
input := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(input))
|
|
||||||
fmt.Println("Part 2:", PartTwo(input))
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package daysix
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
var input = []string{
|
var testInput = []string{
|
||||||
"abc",
|
"abc",
|
||||||
"",
|
"",
|
||||||
"a",
|
"a",
|
||||||
@@ -22,7 +22,7 @@ var input = []string{
|
|||||||
|
|
||||||
func TestPartOne(t *testing.T) {
|
func TestPartOne(t *testing.T) {
|
||||||
expected := 11
|
expected := 11
|
||||||
got := PartOne(input)
|
got := PartOne(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartOne() = %d, want %d", got, expected)
|
t.Errorf("PartOne() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
@@ -30,8 +30,9 @@ func TestPartOne(t *testing.T) {
|
|||||||
|
|
||||||
func TestPartTwo(t *testing.T) {
|
func TestPartTwo(t *testing.T) {
|
||||||
expected := 6
|
expected := 6
|
||||||
got := PartTwo(input)
|
got := PartTwo(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package main
|
package daythree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D3", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
return strings.Split(string(content), "\n")
|
return strings.Split(string(content), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +50,3 @@ func PartTwo(input []string) int {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package daythree
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -31,3 +31,4 @@ func TestPartTwo(t *testing.T) {
|
|||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package main
|
package daytwo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2020D2", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
lines := strings.Split(string(content), "\n")
|
lines := strings.Split(string(content), "\n")
|
||||||
var data []string
|
var data []string
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
@@ -75,8 +75,3 @@ func PartTwo(data []string) int {
|
|||||||
return valid
|
return valid
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package daytwo
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ func TestPartOne(t *testing.T) {
|
|||||||
expected := 2
|
expected := 2
|
||||||
got := PartOne(testInput)
|
got := PartOne(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartOne(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartOne() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ func TestPartTwo(t *testing.T) {
|
|||||||
expected := 1
|
expected := 1
|
||||||
got := PartTwo(testInput)
|
got := PartTwo(testInput)
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Errorf("PartTwo(%v) = %d, want %d", testInput, got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,24 +1,21 @@
|
|||||||
package main
|
package dayone
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []int {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2021D1", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []int {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
var data []int
|
var data []int
|
||||||
for line := range strings.SplitSeq(string(content), "\n") {
|
for line := range strings.SplitSeq(string(content), "\n") {
|
||||||
num, err := strconv.Atoi(line)
|
num, _ := strconv.Atoi(line)
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to convert string to int: %v", err)
|
|
||||||
}
|
|
||||||
data = append(data, num)
|
data = append(data, num)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
@@ -44,8 +41,3 @@ func PartTwo(data []int) int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package dayone
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -19,3 +19,4 @@ func TestPartTwo(t *testing.T) {
|
|||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package main
|
package daythree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2021D3", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
return strings.Split(strings.TrimSpace(string(content)), "\n")
|
return strings.Split(strings.TrimSpace(string(content)), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,8 +115,3 @@ func PartTwo(data []string) int {
|
|||||||
return oxygenRating * co2Rating
|
return oxygenRating * co2Rating
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package daythree
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -32,3 +32,4 @@ func TestPartTwo(t *testing.T) {
|
|||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package main
|
package daytwo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"advent-of-code/internal/registry"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseInput(file string) []string {
|
func init() {
|
||||||
content, err := os.ReadFile(file)
|
registry.Register("2021D2", ParseInput, PartOne, PartTwo)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatalf("Failed to read input file: %v", err)
|
|
||||||
}
|
func ParseInput(filepath string) []string {
|
||||||
|
content, _ := os.ReadFile(filepath)
|
||||||
return strings.Split(string(content), "\n")
|
return strings.Split(string(content), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +58,3 @@ func PartTwo(data []string) int {
|
|||||||
return horizontal * depth
|
return horizontal * depth
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
data := parseInput("input.txt")
|
|
||||||
fmt.Println("Part 1:", PartOne(data))
|
|
||||||
fmt.Println("Part 2:", PartTwo(data))
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package daytwo
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
@@ -26,3 +26,4 @@ func TestPartTwo(t *testing.T) {
|
|||||||
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
t.Errorf("PartTwo() = %d, want %d", got, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
42
internal/registry/registry.go
Normal file
42
internal/registry/registry.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Runner interface {
|
||||||
|
Run(input string, part string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DayRunner[T any] struct {
|
||||||
|
ParseInput func(string) T
|
||||||
|
PartOne func(T) int
|
||||||
|
PartTwo func(T) int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DayRunner[T]) Run(input string, part string) {
|
||||||
|
data := r.ParseInput(input)
|
||||||
|
switch part {
|
||||||
|
case "":
|
||||||
|
fmt.Println(r.PartOne(data))
|
||||||
|
fmt.Println(r.PartTwo(data))
|
||||||
|
case "1":
|
||||||
|
fmt.Println(r.PartOne(data))
|
||||||
|
case "2":
|
||||||
|
fmt.Println(r.PartTwo(data))
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "Invalid part: %s\n", part)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Days = make(map[string]any)
|
||||||
|
|
||||||
|
func Register[T any](key string, parseInput func(string) T, partOne func(T) int, partTwo func(T) int) {
|
||||||
|
Days[key] = &DayRunner[T]{
|
||||||
|
ParseInput: parseInput,
|
||||||
|
PartOne: partOne,
|
||||||
|
PartTwo: partTwo,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user