Commit 75afdba

bryfry <bryon@fryer.io>
2024-12-01 21:05:10
init 2024
1 parent dc8a345
2024/go/01/main.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+	"advent/internal/aoc"
+	"log"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+func parse(line string) (left, right int) {
+	sl := strings.Split(line, "   ")
+	if len(sl) != 2 {
+		log.Fatal("failed to parse line")
+	}
+
+	l, err := strconv.Atoi(sl[0])
+	if err != nil {
+		log.Fatalf("failed to parse left=%q: %s\n", sl[0], err)
+	}
+
+	r, err := strconv.Atoi(sl[1])
+	if err != nil {
+		log.Fatalf("failed to parse left=%q: %s\n", sl[1], err)
+	}
+	return l, r
+}
+
+func solvePart1(input []string) (solution int) {
+	left, right := make([]int, len(input)), make([]int, len(input))
+	for i, line := range input {
+		left[i], right[i] = parse(line)
+	}
+
+	sort.Ints(left)
+	sort.Ints(right)
+
+	dist := 0
+	for i := range left {
+		diff := left[i] - right[i]
+		if diff < 0 {
+			diff = -diff
+		}
+		dist += diff
+	}
+	return dist
+}
+
+func solvePart2(input []string) (solution int) {
+
+	left := make([]int, len(input))
+	rightCount := make(map[int]int, len(input))
+
+	for i, line := range input {
+		l, r := parse(line)
+		left[i] = l
+		v, ok := rightCount[r]
+		if !ok {
+			rightCount[r] = 1
+			continue
+		}
+		rightCount[r] = v + 1
+	}
+
+	sim := 0
+	for _, l := range left {
+		rc, ok := rightCount[l]
+		if ok {
+			sim = sim + (l * rc)
+		}
+	}
+
+	return sim
+}
+
+func main() {
+	day := aoc.Day1
+	aoc.SolveExample(day, aoc.Part1, solvePart1, 11)
+	aoc.SolvePuzzle(day, aoc.Part1, solvePart1, 1388114)
+	aoc.SolveExample(day, aoc.Part2, solvePart2, 31)
+	aoc.SolvePuzzle(day, aoc.Part2, solvePart2, 23529853)
+}
2024/go/internal/aoc/aoc.go
@@ -0,0 +1,158 @@
+package aoc
+
+import (
+	"bufio"
+	"fmt"
+	"log"
+	"os"
+	"time"
+)
+
+const (
+	Example = InputType("e")
+	Puzzle  = InputType("p")
+
+	Part1 = Part(1)
+	Part2 = Part(2)
+
+	Day1  = Day(1)
+	Day2  = Day(2)
+	Day3  = Day(3)
+	Day4  = Day(4)
+	Day5  = Day(5)
+	Day6  = Day(6)
+	Day7  = Day(7)
+	Day8  = Day(8)
+	Day9  = Day(9)
+	Day10 = Day(10)
+	Day11 = Day(11)
+	Day12 = Day(12)
+	Day13 = Day(13)
+	Day14 = Day(14)
+	Day15 = Day(15)
+	Day16 = Day(16)
+	Day17 = Day(17)
+	Day18 = Day(18)
+	Day19 = Day(19)
+	Day20 = Day(20)
+	Day21 = Day(21)
+	Day22 = Day(22)
+	Day23 = Day(23)
+	Day24 = Day(24)
+	Day25 = Day(25)
+
+	UnknownExpected = -1
+)
+
+type InputType string
+type Day int
+type Part int
+
+type Solve func([]string) int
+
+type ProblemId struct {
+	Day  Day
+	Part Part
+}
+
+type Input struct {
+	ProblemId
+	Solve
+	Type     InputType
+	Expected int
+}
+
+func (i Input) String() string {
+	var t string = "Example"
+	if i.Type == Puzzle {
+		t = "Puzzle"
+	}
+	return fmt.Sprintf("Day %02d, Part %d %7s: ", i.Day, i.Part, t)
+
+}
+
+func (i Input) Calculate() (err error) {
+	inputFilename := fmt.Sprintf("../input/%02d-%s%d.txt", i.Day, i.Type, i.Part)
+	input := []string{}
+	file, err := os.Open(inputFilename)
+	if err != nil {
+		return fmt.Errorf("failed to open %s: %w", inputFilename, err)
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		input = append(input, scanner.Text())
+	}
+	if err := scanner.Err(); err != nil {
+		return fmt.Errorf("failed to scan by lines: %w", err)
+	}
+
+	solution := i.Solve(input)
+	if i.Expected == UnknownExpected {
+		fmt.Printf("%8d\n", solution)
+		return nil
+	}
+	if solution != i.Expected {
+		fmt.Printf("%8d ❌\n", solution)
+		return nil
+	}
+	fmt.Printf("%8d ✅\n", solution)
+	return nil
+}
+
+func EventDay(year int) (day int) {
+
+	start := time.Date(year, time.December, 1, 0, 0, 0, 0, time.UTC)
+	now := time.Now()
+	end := time.Date(year, time.December, 25, 0, 0, 0, 0, time.UTC)
+
+	if now.After(end) {
+		return 25
+	}
+	if now.Before(start) {
+		return 0
+	}
+	return now.Day()
+}
+
+func ReleasedDays(year int) (days []Day) {
+	today := EventDay(year)
+	days = []Day{}
+	for d := 1; d <= today; d++ {
+		days = append(days, Day(d))
+	}
+	return days
+}
+
+func SolveExample(day Day, part Part, fn Solve, expected int) {
+	i := Input{
+		ProblemId: ProblemId{
+			Day:  day,
+			Part: part,
+		},
+		Type:     Example,
+		Solve:    fn,
+		Expected: expected,
+	}
+	err := i.Calculate()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func SolvePuzzle(day Day, part Part, fn Solve, expected int) {
+	i := Input{
+		ProblemId: ProblemId{
+			Day:  day,
+			Part: part,
+		},
+		Type:     Puzzle,
+		Solve:    fn,
+		Expected: expected,
+	}
+	err := i.Calculate()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
2024/go/template/main.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"advent2024/internal/aoc"
+)
+
+func solvePart1(input []string) (solution int) {
+	return 0
+}
+
+func solvePart2(input []string) (solution int) {
+	return 0
+}
+
+func main() {
+	day := aoc.Day1
+	aoc.SolveExample(day, aoc.Part1, solvePart1, 0)
+	aoc.SolvePuzzle(day, aoc.Part1, solvePart1, aoc.UnknownExpected)
+	aoc.SolveExample(day, aoc.Part2, solvePart2, 0)
+	aoc.SolvePuzzle(day, aoc.Part2, solvePart2, aoc.UnknownExpected)
+}
2024/go/.gitignore
@@ -0,0 +1,1 @@
+bin/*
2024/go/go.mod
@@ -0,0 +1,3 @@
+module advent
+
+go 1.22
2024/go/go.sum
2024/go/Justfile
@@ -0,0 +1,24 @@
+default: run-all
+
+clean: 
+	@echo "cleaning up"
+	@rm -f bin/*
+
+build-all:
+	just build 01
+
+run-all: clean build-all 
+	bin/01
+
+template day:
+	cp -r template {{day}}
+
+build day: 
+	go build -o bin/{{day}} {{day}}/main.go
+
+run day: clean
+	just build {{day}}
+	bin/{{day}}
+
+
+# vim: set ft=make :
2024/go/README.md
@@ -0,0 +1,14 @@
+# 2024 Advent of Code - Golang 
+
+Run all:
+
+```bash
+just
+```
+
+Run a specific day:
+```bash
+just run 01
+```
+
+