From 6d8fb621d1e93b83786890d6d9cb6f0d8defa8ae Mon Sep 17 00:00:00 2001 From: DJ O'Leary Date: Fri, 26 Jun 2026 18:04:09 +0200 Subject: refactor!: invert repo directory structure now is language first --- 2023/go/.envrc | 1 - 2023/go/.gitignore | 21 -- 2023/go/README.md | 21 -- 2023/go/Taskfile.yml | 23 -- 2023/go/flake.lock | 27 -- 2023/go/flake.nix | 28 -- 2023/go/go.mod | 11 - 2023/go/go.sum | 8 - 2023/go/internal/day_01/day_01.go | 114 ------- 2023/go/internal/day_01/day_01_test.go | 31 -- 2023/go/internal/day_02/part_01/part_01.go | 138 -------- 2023/go/internal/day_02/part_01/part_01_test.go | 102 ------ 2023/go/internal/day_02/part_02/part_02.go | 114 ------- 2023/go/internal/day_02/part_02/part_02_test.go | 84 ----- 2023/go/internal/day_03/part_01/part_01.go | 123 ------- 2023/go/internal/day_03/part_01/part_01_test.go | 78 ----- 2023/go/internal/day_04/part_01/part_01.go | 130 ------- 2023/go/internal/day_04/part_01/part_01_test.go | 48 --- 2023/go/internal/day_04/part_02/part_02.go | 142 -------- 2023/go/internal/day_04/part_02/part_02_test.go | 143 -------- 2023/go/internal/day_06/part_01/part_01.go | 85 ----- 2023/go/internal/day_06/part_01/part_01_test.go | 96 ------ 2023/go/internal/day_06/part_02/part_02.go | 81 ----- 2023/go/internal/day_06/part_02/part_02_test.go | 84 ----- 2023/go/internal/day_07/part_01/part_01.go | 273 --------------- 2023/go/internal/day_07/part_01/part_01_test.go | 432 ------------------------ 2023/go/main.go | 86 ----- 27 files changed, 2524 deletions(-) delete mode 100644 2023/go/.envrc delete mode 100644 2023/go/.gitignore delete mode 100644 2023/go/README.md delete mode 100644 2023/go/Taskfile.yml delete mode 100644 2023/go/flake.lock delete mode 100644 2023/go/flake.nix delete mode 100644 2023/go/go.mod delete mode 100644 2023/go/go.sum delete mode 100644 2023/go/internal/day_01/day_01.go delete mode 100644 2023/go/internal/day_01/day_01_test.go delete mode 100644 2023/go/internal/day_02/part_01/part_01.go delete mode 100644 2023/go/internal/day_02/part_01/part_01_test.go delete mode 100644 2023/go/internal/day_02/part_02/part_02.go delete mode 100644 2023/go/internal/day_02/part_02/part_02_test.go delete mode 100644 2023/go/internal/day_03/part_01/part_01.go delete mode 100644 2023/go/internal/day_03/part_01/part_01_test.go delete mode 100644 2023/go/internal/day_04/part_01/part_01.go delete mode 100644 2023/go/internal/day_04/part_01/part_01_test.go delete mode 100644 2023/go/internal/day_04/part_02/part_02.go delete mode 100644 2023/go/internal/day_04/part_02/part_02_test.go delete mode 100644 2023/go/internal/day_06/part_01/part_01.go delete mode 100644 2023/go/internal/day_06/part_01/part_01_test.go delete mode 100644 2023/go/internal/day_06/part_02/part_02.go delete mode 100644 2023/go/internal/day_06/part_02/part_02_test.go delete mode 100644 2023/go/internal/day_07/part_01/part_01.go delete mode 100644 2023/go/internal/day_07/part_01/part_01_test.go delete mode 100644 2023/go/main.go (limited to '2023') diff --git a/2023/go/.envrc b/2023/go/.envrc deleted file mode 100644 index 3550a30..0000000 --- a/2023/go/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/2023/go/.gitignore b/2023/go/.gitignore deleted file mode 100644 index 9f4cb5b..0000000 --- a/2023/go/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -out/ - -# Go workspace file -go.work -go.work.sum diff --git a/2023/go/README.md b/2023/go/README.md deleted file mode 100644 index 9cda93b..0000000 --- a/2023/go/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Go 2023 - -## Getting Started - -### How to Build - -```sh -task build -``` - -### How to Run - -```sh -task run -``` - -### How to Test - -```sh -task test -``` diff --git a/2023/go/Taskfile.yml b/2023/go/Taskfile.yml deleted file mode 100644 index a07c24c..0000000 --- a/2023/go/Taskfile.yml +++ /dev/null @@ -1,23 +0,0 @@ -# https://taskfile.dev - -version: "3" -tasks: - default: - desc: Prints this message - cmds: - - cmd: task --list-all - build: - cmds: - - cmd: go build -o=out/Advent_of_Code_2023 main.go - run: - cmds: - - cmd: go run main.go {{.CLI_ARGS}} - test: - cmds: - - cmd: go test ./... - test:coverage: - desc: Runs tests and produce coverage report - cmds: - - cmd: mkdir --parents out - - cmd: go test -coverprofile=out/coverage.out ./... - - cmd: go tool cover -html=out/coverage.out diff --git a/2023/go/flake.lock b/2023/go/flake.lock deleted file mode 100644 index b7695d9..0000000 --- a/2023/go/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1741010256, - "narHash": "sha256-WZNlK/KX7Sni0RyqLSqLPbK8k08Kq7H7RijPJbq9KHM=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "ba487dbc9d04e0634c64e3b1f0d25839a0a68246", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/2023/go/flake.nix b/2023/go/flake.nix deleted file mode 100644 index 39dda89..0000000 --- a/2023/go/flake.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - description = "Advent of Code 2023: Go"; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; - }; - - outputs = - { nixpkgs, ... }: - let - pkgs = nixpkgs.legacyPackages.x86_64-linux; - in - { - devShells.x86_64-linux.default = pkgs.mkShell { - # build tools - nativeBuildInputs = with pkgs; [ - go - ]; - # dependencies - buildInputs = with pkgs; [ - delve - gopls - gotools - golangci-lint - ]; - }; - }; -} diff --git a/2023/go/go.mod b/2023/go/go.mod deleted file mode 100644 index 9fba23c..0000000 --- a/2023/go/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/DJOLEARY/Advent_of_Code/2023/Go - -go 1.22.3 - -require github.com/outrigdev/outrig v0.8.2 - -require ( - github.com/google/uuid v1.6.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect -) diff --git a/2023/go/go.sum b/2023/go/go.sum deleted file mode 100644 index 3c60b26..0000000 --- a/2023/go/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/outrigdev/outrig v0.8.2 h1:+qR+N6BXvJmFXsHmksaAJk4sgItxHLbWXN+9K8W2UVM= -github.com/outrigdev/outrig v0.8.2/go.mod h1:8ULH17Fc55s9zkf6S2ndQ43UoiJ0j28t9A0lwjs7rQc= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= diff --git a/2023/go/internal/day_01/day_01.go b/2023/go/internal/day_01/day_01.go deleted file mode 100644 index 9cd0a49..0000000 --- a/2023/go/internal/day_01/day_01.go +++ /dev/null @@ -1,114 +0,0 @@ -package day_01 - -import ( - "errors" - "fmt" - "os" - "strconv" - "strings" -) - -func Solve() { - filename := "../_input/day_01.txt" - content := readFile(filename) - - numbers := []int{} - - lines := strings.Split(content, "\n") - for _, line := range lines { - first_num, last_num, err := findNumbers(line) - if err != nil { - continue - } - - num_str := first_num + last_num - num := strToInt(num_str) - numbers = append(numbers, num) - } - - acc := accumulate(numbers) - - fmt.Println(acc) -} - -func readFile(filename string) string { - content, err := os.ReadFile(filename) - if err != nil { - panic(err) - } - - return string(content) -} - -var num_map = map[string]string{ - "zero": "0", - "0": "0", - "one": "1", - "1": "1", - "two": "2", - "2": "2", - "three": "3", - "3": "3", - "four": "4", - "4": "4", - "five": "5", - "5": "5", - "six": "6", - "6": "6", - "seven": "7", - "7": "7", - "eight": "8", - "8": "8", - "nine": "9", - "9": "9", -} - -func findNumbers(line string) (string, string, error) { - if line == "" || line == "\n" { - return "", "", errors.New("Empty line") - } - - found_numbers := []string{} - window_size := 5 - for i := range line { - window_end := i + window_size - if window_end > len(line) { - window_end = len(line) - } - sub_str := line[i:window_end] - - for key, value := range num_map { - if strings.HasPrefix(sub_str, key) { - found_numbers = append(found_numbers, value) - } - } - } - - if len(found_numbers) == 0 { - return "", "", errors.New("No numbers found") - } - - first := found_numbers[0] - last := found_numbers[len(found_numbers)-1] - - return first, last, nil -} - -func accumulate(numbers []int) int { - acc := 0 - - for _, num := range numbers { - acc += num - } - - return acc -} - -func strToInt(str string) int { - num, err := strconv.ParseInt(str, 0, 0) - if err != nil { - panic(err) - } - - return int(num) -} diff --git a/2023/go/internal/day_01/day_01_test.go b/2023/go/internal/day_01/day_01_test.go deleted file mode 100644 index 8063619..0000000 --- a/2023/go/internal/day_01/day_01_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package day_01 - -import ( - "testing" -) - -type input string -type answer string - -func TestFindNumbers(t *testing.T) { - data := map[input]answer{ - "1abc2": "12", - "pqr3stu8vwx": "38", - "a1b2c3d4e5f": "15", - "treb7uchet": "77", - } - - for input, expected := range data { - actual_first, actual_last, err := findNumbers(string(input)) - - if err != nil { - t.Error("find_numbers returned an error") - } - - actual := actual_first + actual_last - - if actual != string(expected) { - t.Errorf("Expected %s, got %s", expected, actual) - } - } -} diff --git a/2023/go/internal/day_02/part_01/part_01.go b/2023/go/internal/day_02/part_01/part_01.go deleted file mode 100644 index 9efe20f..0000000 --- a/2023/go/internal/day_02/part_01/part_01.go +++ /dev/null @@ -1,138 +0,0 @@ -package part_01 - -import ( - "os" - "regexp" - "strconv" - "strings" -) - -type cubes struct { - red int - blue int - green int -} - -func Solve() { - contents, err := os.ReadFile("../_input/day_02.txt") - if err != nil { - panic(err) - } - - lines := strings.Split(string(contents), "\n") - possibleGameIds := processLines(lines) - - println(accumulate(possibleGameIds)) -} - -func processLines(lines []string) []int { - var possibleGames []int - - maxCubes := cubes{red: 12, blue: 14, green: 13} - - for _, line := range lines { - if line == "" || line == "\n" { - continue - } - - shownCubes := convertLineToCubes(line) - - isPossible := isPossibleGame(shownCubes, maxCubes) - if isPossible { - gameId := getGameId(line) - possibleGames = append(possibleGames, gameId) - } - } - - return possibleGames -} - -func convertLineToCubes(line string) []cubes { - var shownCubes []cubes - - redRegex := regexp.MustCompile(`(\d+) red`) - blueRegex := regexp.MustCompile(`(\d+) blue`) - greenRegex := regexp.MustCompile(`(\d+) green`) - - for _, round := range strings.Split(line, ";") { - var cubes cubes - - redMatches := redRegex.FindStringSubmatch(round) - if redMatches != nil { - red, err := strconv.Atoi(redMatches[1]) - if err != nil { - panic("Could not convert red to int: " + redMatches[1]) - } else { - cubes.red = red - } - } - - blueMatches := blueRegex.FindStringSubmatch(round) - if blueMatches != nil { - blue, err := strconv.Atoi(blueMatches[1]) - if err != nil { - panic("Could not convert green to int: " + blueMatches[1]) - } else { - cubes.blue = blue - } - } - - greenMatches := greenRegex.FindStringSubmatch(round) - if greenMatches != nil { - green, err := strconv.Atoi(greenMatches[1]) - if err != nil { - panic("Could not convert green to int: " + greenMatches[1]) - } else { - cubes.green = green - } - } - - shownCubes = append(shownCubes, cubes) - } - - return shownCubes -} - -func isPossibleGame(shownCubes []cubes, maxCubes cubes) bool { - for _, cubes := range shownCubes { - if cubes.red > maxCubes.red { - return false - } - - if cubes.blue > maxCubes.blue { - return false - } - - if cubes.green > maxCubes.green { - return false - } - } - - return true -} - -func getGameId(line string) int { - regex := regexp.MustCompile(`^Game (\d+):`) - matches := regex.FindStringSubmatch(line) - if matches == nil || len(matches) < 2 { - println(matches) - panic("No game id found in line: '" + line + "'") - } - - gameId, err := strconv.Atoi(matches[1]) - if err != nil { - panic("Could not convert game id to int: " + matches[1]) - } - - return gameId -} - -func accumulate(gameIds []int) int { - var acc int - - for _, gameId := range gameIds { - acc += gameId - } - - return acc -} diff --git a/2023/go/internal/day_02/part_01/part_01_test.go b/2023/go/internal/day_02/part_01/part_01_test.go deleted file mode 100644 index 33e5fbf..0000000 --- a/2023/go/internal/day_02/part_01/part_01_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package part_01 - -import ( - "testing" -) - -type data struct { - gameId int - isPossible bool - shownCubes []cubes - line string -} - -var testInput = []data{ - { - gameId: 1, - isPossible: true, - shownCubes: []cubes{ - {red: 4, blue: 3}, - {red: 1, blue: 6, green: 2}, - {green: 2}, - }, - line: "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green", - }, - { - gameId: 2, - isPossible: true, - shownCubes: []cubes{ - {blue: 1, green: 2}, - {red: 1, blue: 4, green: 3}, - {blue: 1, green: 1}, - }, - line: "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue", - }, - { - gameId: 3, - isPossible: false, - shownCubes: []cubes{ - {red: 20, blue: 6, green: 8}, - {red: 4, blue: 5, green: 13}, - {red: 1, green: 5}, - }, - line: "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red", - }, - { - gameId: 4, - isPossible: false, - shownCubes: []cubes{ - {red: 3, blue: 6, green: 1}, - {red: 6, green: 3}, - {red: 14, blue: 15, green: 3}, - }, - line: "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red", - }, - { - gameId: 5, - isPossible: true, - shownCubes: []cubes{ - {red: 6, blue: 1, green: 3}, - {red: 1, blue: 2, green: 2}, - }, - line: "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green", - }, -} - -func TestConvertLineToCubes(t *testing.T) { - for _, data := range testInput { - actualCubes := convertLineToCubes(data.line) - - if len(data.shownCubes) != len(actualCubes) { - t.Errorf("Expected length of shownCubes to be %d, got %d", len(data.shownCubes), len(actualCubes)) - } - - for i, cubes := range data.shownCubes { - if cubes != actualCubes[i] { - t.Errorf("Expected shownCubes to be %v, got %v", cubes, actualCubes[i]) - } - } - } -} - -func TestIsPossibleGame(t *testing.T) { - maxCubes := cubes{red: 12, blue: 13, green: 14} - - for _, data := range testInput { - actualIsPossible := isPossibleGame(data.shownCubes, maxCubes) - - if data.isPossible != actualIsPossible { - t.Errorf("Expected isPossibleGame to be %t, got %t for game id %d", data.isPossible, actualIsPossible, data.gameId) - } - } -} - -func TestGetGameId(t *testing.T) { - for _, data := range testInput { - actualGameId := getGameId(data.line) - - if data.gameId != actualGameId { - t.Errorf("Expected gameId to be %d, got %d", data.gameId, actualGameId) - } - } -} diff --git a/2023/go/internal/day_02/part_02/part_02.go b/2023/go/internal/day_02/part_02/part_02.go deleted file mode 100644 index ffb9691..0000000 --- a/2023/go/internal/day_02/part_02/part_02.go +++ /dev/null @@ -1,114 +0,0 @@ -package part_02 - -import ( - "os" - "regexp" - "strconv" - "strings" -) - -type cubes struct { - red int - blue int - green int -} - -func Solve() { - contents, err := os.ReadFile("../_input/day_02.txt") - if err != nil { - panic(err) - } - - lines := strings.Split(string(contents), "\n") - answer := processLines(lines) - - println(answer) -} - -func processLines(lines []string) int { - var answer int - - for _, line := range lines { - if line == "" || line == "\n" { - continue - } - - shownCubes := convertLineToCubes(line) - - maxCubes := getMaximumCubes(shownCubes) - power := getPower(maxCubes) - answer += power - } - - return answer -} - -func convertLineToCubes(line string) []cubes { - var shownCubes []cubes - - redRegex := regexp.MustCompile(`(\d+) red`) - blueRegex := regexp.MustCompile(`(\d+) blue`) - greenRegex := regexp.MustCompile(`(\d+) green`) - - for _, round := range strings.Split(line, ";") { - var cubes cubes - - redMatches := redRegex.FindStringSubmatch(round) - if redMatches != nil { - red, err := strconv.Atoi(redMatches[1]) - if err != nil { - panic("Could not convert red to int: " + redMatches[1]) - } else { - cubes.red = red - } - } - - blueMatches := blueRegex.FindStringSubmatch(round) - if blueMatches != nil { - blue, err := strconv.Atoi(blueMatches[1]) - if err != nil { - panic("Could not convert green to int: " + blueMatches[1]) - } else { - cubes.blue = blue - } - } - - greenMatches := greenRegex.FindStringSubmatch(round) - if greenMatches != nil { - green, err := strconv.Atoi(greenMatches[1]) - if err != nil { - panic("Could not convert green to int: " + greenMatches[1]) - } else { - cubes.green = green - } - } - - shownCubes = append(shownCubes, cubes) - } - - return shownCubes -} - -func getMaximumCubes(shownCubes []cubes) cubes { - var maxCubes cubes - - for _, cubes := range shownCubes { - if cubes.red > maxCubes.red { - maxCubes.red = cubes.red - } - - if cubes.blue > maxCubes.blue { - maxCubes.blue = cubes.blue - } - - if cubes.green > maxCubes.green { - maxCubes.green = cubes.green - } - } - - return maxCubes -} - -func getPower(maxCubes cubes) int { - return maxCubes.red * maxCubes.blue * maxCubes.green -} diff --git a/2023/go/internal/day_02/part_02/part_02_test.go b/2023/go/internal/day_02/part_02/part_02_test.go deleted file mode 100644 index 6952899..0000000 --- a/2023/go/internal/day_02/part_02/part_02_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package part_02 - -import ( - "testing" -) - -type data struct { - shownCubes []cubes - maxCubes cubes - line string -} - -var testInput = []data{ - { - shownCubes: []cubes{ - {red: 4, blue: 3}, - {red: 1, blue: 6, green: 2}, - {green: 2}, - }, - maxCubes: cubes{red: 4, blue: 6, green: 2}, - line: "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green", - }, - { - shownCubes: []cubes{ - {blue: 1, green: 2}, - {red: 1, blue: 4, green: 3}, - {blue: 1, green: 1}, - }, - maxCubes: cubes{red: 1, blue: 4, green: 3}, - line: "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue", - }, - { - shownCubes: []cubes{ - {red: 20, blue: 6, green: 8}, - {red: 4, blue: 5, green: 13}, - {red: 1, green: 5}, - }, - maxCubes: cubes{red: 20, blue: 6, green: 13}, - line: "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red", - }, - { - shownCubes: []cubes{ - {red: 3, blue: 6, green: 1}, - {red: 6, green: 3}, - {red: 14, blue: 15, green: 3}, - }, - maxCubes: cubes{red: 14, blue: 15, green: 3}, - line: "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red", - }, - { - shownCubes: []cubes{ - {red: 6, blue: 1, green: 3}, - {red: 1, blue: 2, green: 2}, - }, - maxCubes: cubes{red: 6, blue: 2, green: 3}, - line: "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green", - }, -} - -func TestConvertLineToCubes(t *testing.T) { - for _, data := range testInput { - actualCubes := convertLineToCubes(data.line) - - if len(data.shownCubes) != len(actualCubes) { - t.Errorf("Expected length of shownCubes to be %d, got %d", len(data.shownCubes), len(actualCubes)) - } - - for i, cubes := range data.shownCubes { - if cubes != actualCubes[i] { - t.Errorf("Expected shownCubes to be %v, got %v", cubes, actualCubes[i]) - } - } - } -} - -func TestGetMaximumCubes(t *testing.T) { - for _, data := range testInput { - actualMaxCubes := getMaximumCubes(data.shownCubes) - - if actualMaxCubes != data.maxCubes { - t.Errorf("Expected maxCubes to be %v, got %v", data.maxCubes, actualMaxCubes) - } - } -} diff --git a/2023/go/internal/day_03/part_01/part_01.go b/2023/go/internal/day_03/part_01/part_01.go deleted file mode 100644 index 49837b3..0000000 --- a/2023/go/internal/day_03/part_01/part_01.go +++ /dev/null @@ -1,123 +0,0 @@ -package part_01 - -/** - * TRIED: - * 530923 - */ - -import ( - "os" - "strconv" - "strings" -) - -const USE_SAMPLE = true - -func Solve() { - var content []byte - if USE_SAMPLE { - content, _ = os.ReadFile("../_input/day_03_part_01_sample.txt") - } else { - content, _ = os.ReadFile("../_input/day_03.txt") - } - lines := strings.Split(string(content), "\n") - - validNumbers := walkLines(lines) - - answer := 0 - for _, number := range validNumbers { - answer += number - } - - println(answer) -} - -func walkLines(lines []string) []int { - var validNumbers []int - - for y := 0; y < len(lines); y++ { - line := lines[y] - - if line == "" || line == "\n" { - continue - } - - // Counts as a symbol... - filteredLine := strings.ReplaceAll(line, "\r", "") - - previousWasNumber := false - number := "" - for x := 0; x < len(filteredLine); x++ { - char := filteredLine[x] - - _, err := strconv.Atoi(string(char)) - isNumeric := err == nil - - if isNumeric { - previousWasNumber = true - number += string(char) - continue - } - - if !previousWasNumber { - continue - } - - isValid := checkValidity(lines, x, y, len(number)) - if isValid { - num, _ := strconv.Atoi(number) - validNumbers = append(validNumbers, num) - } - - println(number) - - previousWasNumber = false - number = "" - } - } - - return validNumbers -} - -// N = number -// k = numOfDigits + 1 -// (x-k,y-1) (x-1,y-1) ( x ,y-1) -// (x-k, y ) N ( x , y ) -// (x-k,y+1) (x-1,y+1) ( x ,y+1) -func checkValidity(lines []string, x int, y int, numOfDigits int) bool { - - for i := max(y-1, 0); i <= y+1; i++ { - - var debugLine string - - for j := max(x-(numOfDigits+1), 0); j <= x; j++ { - - if lineExists := len(lines) > i; !lineExists { - continue - } - - if charExists := len(lines[i]) > j; !charExists { - continue - } - - char := rune(lines[i][j]) - debugLine += string(char) - - if char == '.' { - continue - } - - _, err := strconv.Atoi(string(char)) - isNumeric := err == nil - if isNumeric { - continue - } - - debugLine = "" //nolint:ineffassign // Only used for debugging and needs to be reset - - return true - } - } - - return false -} diff --git a/2023/go/internal/day_03/part_01/part_01_test.go b/2023/go/internal/day_03/part_01/part_01_test.go deleted file mode 100644 index a077fbd..0000000 --- a/2023/go/internal/day_03/part_01/part_01_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package part_01 - -import ( - "os" - "strings" - "testing" -) - -func TestWalkLines(t *testing.T) { - lines := getSampleLines() - expected := 4361 - - validNumbers := walkLines(lines) - - actual := 0 - for _, number := range validNumbers { - actual += number - } - - if actual != expected { - t.Errorf("Expected answer to be %d, got %d", expected, actual) - } -} - -func TestCheckValidity(t *testing.T) { - lines := getSampleLines() - - tests := []struct { - x int - y int - length int - expected bool - }{ - {3, 0, 3, true}, // 467 - {8, 0, 3, false}, // 114 - {9, 0, 1, false}, // 3 - Added to check for '\r' counting as a symbol - {4, 2, 2, true}, // 35 - {9, 2, 3, true}, // 633 - {9, 3, 1, false}, // 3 - Added to check if number continues to next line - {3, 4, 3, true}, // 617 - {9, 5, 2, false}, // 58 - {5, 6, 3, true}, // 592 - {9, 7, 3, true}, // 775 - {4, 9, 3, true}, // 664 - {8, 9, 3, true}, // 598 - } - - for _, test := range tests { - actual := checkValidity(lines, test.x, test.y, test.length) - - if actual != test.expected { - t.Errorf("Expected %d, %d, %d to be %t, got %t", test.x, test.y, test.length, test.expected, actual) - } - } -} - -func getSampleLines() []string { - contents, err := os.ReadFile("../../../../_input/day_03_part_01_sample.txt") - if err != nil { - panic(err) - } - - lines := strings.Split(string(contents), "\n") - - var filteredLines []string - for _, line := range lines { - if line == "" || line == "\n" { - continue - } - - // Counts as a symbol... - filteredLine := strings.ReplaceAll(line, "\r", "") - - filteredLines = append(filteredLines, filteredLine) - } - - return filteredLines -} diff --git a/2023/go/internal/day_04/part_01/part_01.go b/2023/go/internal/day_04/part_01/part_01.go deleted file mode 100644 index 1a215b1..0000000 --- a/2023/go/internal/day_04/part_01/part_01.go +++ /dev/null @@ -1,130 +0,0 @@ -package part_01 - -import ( - "os" - "slices" - "strconv" - "strings" -) - -const USE_SAMPLE = false - -type UnparsedCard struct { - id string - winningNumbers []string - haveNumbers []string -} - -type Card struct { - id int - winningNumbers []int - haveNumbers []int -} - -func (c UnparsedCard) parse() Card { - var card Card - - id, err := strconv.Atoi(c.id) - if err != nil { - panic(err) - } - card.id = id - - for _, number := range c.winningNumbers { - num, err := strconv.Atoi(number) - if err != nil { - panic(err) - } - card.winningNumbers = append(card.winningNumbers, num) - } - - for _, number := range c.haveNumbers { - num, err := strconv.Atoi(number) - if err != nil { - panic(err) - } - card.haveNumbers = append(card.haveNumbers, num) - } - - return card -} - -func Solve() { - var contents []byte - if USE_SAMPLE { - contents, _ = os.ReadFile("../_input/day_04_part_01_sample.txt") - } else { - contents, _ = os.ReadFile("../_input/day_04.txt") - } - - lines := strings.Split(string(contents), "\n") - - answer := 0 - for _, line := range lines { - if line == "" || line == "\n" { - continue - } - - card := parseCardLine(line) - score := tallyScore(card) - - answer += score - } - - println(answer) -} - -// "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53" -func parseCardLine(line string) Card { - var unparsedCard UnparsedCard - - filteredLine := strings.ReplaceAll(line, "\r", "") - - // "Card 1" - card_parts := strings.Split(filteredLine, ":")[0] - id_parts := strings.Split(card_parts, " ") - id := id_parts[len(id_parts)-1] - unparsedCard.id = strings.ReplaceAll(id, " ", "") - - // "41 48 83 86 17 | 83 86 6 31 17 9 48 53" - numbers := strings.Split(filteredLine, ":")[1] - - // " 41 48 83 86 17" - winningNumberString := strings.Split(numbers, "|")[0] - // ["", "41", "48", "83", "86", "17"] - winningNumbers := strings.Split(winningNumberString, " ") - for _, num := range winningNumbers { - if num == "" || num == " " { - continue - } - unparsedCard.winningNumbers = append(unparsedCard.winningNumbers, num) - } - - // " 83 86 6 31 17 9 48 53" - haveNumberString := strings.Split(numbers, "|")[1] - // ["", "83", "86", "", "6", "31", "17", "", "9", "48", "53"] - haveNumbers := strings.Split(haveNumberString, " ") - for _, num := range haveNumbers { - if num == "" || num == " " { - continue - } - unparsedCard.haveNumbers = append(unparsedCard.haveNumbers, num) - } - - return unparsedCard.parse() -} - -func tallyScore(card Card) int { - score := 0 - for _, winningNumber := range card.winningNumbers { - if slices.Contains(card.haveNumbers, winningNumber) { - if score == 0 { - score = 1 - } else { - score *= 2 - } - } - } - - return score -} diff --git a/2023/go/internal/day_04/part_01/part_01_test.go b/2023/go/internal/day_04/part_01/part_01_test.go deleted file mode 100644 index f6f1a83..0000000 --- a/2023/go/internal/day_04/part_01/part_01_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package part_01 - -import ( - "testing" -) - -func TestParseCardLine(t *testing.T) { - input := "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53" - expected := Card{1, []int{41, 48, 83, 86, 17}, []int{83, 86, 6, 31, 17, 9, 48, 53}} - - actual := parseCardLine(input) - - if actual.id != expected.id { - t.Errorf("ERROR: ID %d does not match expected %d", actual.id, expected.id) - } - - if len(actual.winningNumbers) != len(expected.winningNumbers) { - t.Errorf("ERROR: len(WinningNumbers) %d does not match expected %d", len(actual.winningNumbers), len(expected.winningNumbers)) - } - - if len(actual.haveNumbers) != len(expected.haveNumbers) { - t.Errorf("ERROR: len(HaveNumbers) %d does not match expected %d", len(actual.haveNumbers), len(expected.haveNumbers)) - } - - for i, num := range actual.winningNumbers { - if num != expected.winningNumbers[i] { - t.Errorf("ERROR: WinningNumber %d does not match expected %d", num, expected.winningNumbers[i]) - } - } - - for i, num := range actual.haveNumbers { - if num != expected.haveNumbers[i] { - t.Errorf("ERROR: HaveNumber %d does not match expected %d", num, expected.haveNumbers[i]) - } - } - -} - -func TestTallyScore(t *testing.T) { - card := Card{1, []int{41, 48, 83, 86, 17}, []int{83, 86, 6, 31, 17, 9, 48, 53}} - expected := 8 - - actual := tallyScore(card) - - if actual != expected { - t.Errorf("ERROR: Score %d does not match expected %d", actual, expected) - } -} diff --git a/2023/go/internal/day_04/part_02/part_02.go b/2023/go/internal/day_04/part_02/part_02.go deleted file mode 100644 index a9e3152..0000000 --- a/2023/go/internal/day_04/part_02/part_02.go +++ /dev/null @@ -1,142 +0,0 @@ -package part_02 - -import ( - "os" - "slices" - "strconv" - "strings" -) - -const USE_SAMPLE = false - -type UnparsedCard struct { - id string - winningNumbers []string - haveNumbers []string -} - -type Card struct { - id int - winningNumbers []int - haveNumbers []int -} - -func (c UnparsedCard) parse() Card { - var card Card - - id, err := strconv.Atoi(c.id) - if err != nil { - panic(err) - } - card.id = id - - for _, number := range c.winningNumbers { - num, err := strconv.Atoi(number) - if err != nil { - panic(err) - } - card.winningNumbers = append(card.winningNumbers, num) - } - - for _, number := range c.haveNumbers { - num, err := strconv.Atoi(number) - if err != nil { - panic(err) - } - card.haveNumbers = append(card.haveNumbers, num) - } - - return card -} - -func Solve() { - var contents []byte - if USE_SAMPLE { - contents, _ = os.ReadFile("../_input/day_04_part_02_sample.txt") - } else { - contents, _ = os.ReadFile("../_input/day_04.txt") - } - - lines := strings.Split(string(contents), "\n") - - dict := map[int]Card{} - var cards []Card - for _, line := range lines { - if line == "" || line == "\n" { - continue - } - - card := parseCardLine(line) - - dict[card.id] = card - cards = append(cards, card) - } - - answer := processCards(dict, cards) - - println(answer) -} - -// "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53" -func parseCardLine(line string) Card { - var unparsedCard UnparsedCard - - filteredLine := strings.ReplaceAll(line, "\r", "") - - // "Card 1" - card_parts := strings.Split(filteredLine, ":")[0] - id_parts := strings.Split(card_parts, " ") - id := id_parts[len(id_parts)-1] - unparsedCard.id = strings.ReplaceAll(id, " ", "") - - // "41 48 83 86 17 | 83 86 6 31 17 9 48 53" - numbers := strings.Split(filteredLine, ":")[1] - - // " 41 48 83 86 17" - winningNumberString := strings.Split(numbers, "|")[0] - // ["", "41", "48", "83", "86", "17"] - winningNumbers := strings.Split(winningNumberString, " ") - for _, num := range winningNumbers { - if num == "" || num == " " { - continue - } - unparsedCard.winningNumbers = append(unparsedCard.winningNumbers, num) - } - - // " 83 86 6 31 17 9 48 53" - haveNumberString := strings.Split(numbers, "|")[1] - // ["", "83", "86", "", "6", "31", "17", "", "9", "48", "53"] - haveNumbers := strings.Split(haveNumberString, " ") - for _, num := range haveNumbers { - if num == "" || num == " " { - continue - } - unparsedCard.haveNumbers = append(unparsedCard.haveNumbers, num) - } - - return unparsedCard.parse() -} - -func processCards(dict map[int]Card, cards []Card) int { - for i := 0; i < len(cards); i++ { - card := cards[i] - matchCount := calculateNumberOfMatches(card) - for j := card.id + 1; j < (card.id + 1 + matchCount); j++ { - copyCard := dict[j] - cards = append(cards, copyCard) - } - } - - return len(cards) -} - -func calculateNumberOfMatches(card Card) int { - matchCount := 0 - for _, winningNumber := range card.winningNumbers { - if slices.Contains(card.haveNumbers, winningNumber) { - matchCount++ - } - } - - return matchCount -} diff --git a/2023/go/internal/day_04/part_02/part_02_test.go b/2023/go/internal/day_04/part_02/part_02_test.go deleted file mode 100644 index 3c66a2e..0000000 --- a/2023/go/internal/day_04/part_02/part_02_test.go +++ /dev/null @@ -1,143 +0,0 @@ -package part_02 - -import ( - "testing" -) - -func TestParseCardLine(t *testing.T) { - input := "Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53" - expected := Card{1, []int{41, 48, 83, 86, 17}, []int{83, 86, 6, 31, 17, 9, 48, 53}} - - actual := parseCardLine(input) - - if actual.id != expected.id { - t.Errorf("ERROR: ID %d does not match expected %d", actual.id, expected.id) - } - - if len(actual.winningNumbers) != len(expected.winningNumbers) { - t.Errorf("ERROR: len(WinningNumbers) %d does not match expected %d", len(actual.winningNumbers), len(expected.winningNumbers)) - } - - if len(actual.haveNumbers) != len(expected.haveNumbers) { - t.Errorf("ERROR: len(HaveNumbers) %d does not match expected %d", len(actual.haveNumbers), len(expected.haveNumbers)) - } - - for i, num := range actual.winningNumbers { - if num != expected.winningNumbers[i] { - t.Errorf("ERROR: WinningNumber %d does not match expected %d", num, expected.winningNumbers[i]) - } - } - - for i, num := range actual.haveNumbers { - if num != expected.haveNumbers[i] { - t.Errorf("ERROR: HaveNumber %d does not match expected %d", num, expected.haveNumbers[i]) - } - } - -} - -func TestProcessCards(t *testing.T) { - cards := []Card{ - // Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 - { - 1, - []int{41, 48, 83, 86, 17}, - []int{83, 86, 6, 31, 17, 9, 48, 53}, - }, - // Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 - { - 2, - []int{13, 32, 20, 16, 61}, - []int{61, 30, 68, 82, 17, 32, 24, 19}, - }, - // Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 - { - 3, - []int{1, 21, 53, 59, 44}, - []int{69, 82, 63, 72, 16, 21, 14, 1}, - }, - // Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 - { - 4, - []int{41, 92, 73, 84, 69}, - []int{59, 84, 76, 51, 58, 5, 54, 83}, - }, - // Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 - { - 5, - []int{87, 83, 26, 28, 32}, - []int{88, 30, 70, 12, 93, 22, 82, 36}, - }, - // Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 - { - 6, - []int{31, 18, 13, 56, 72}, - []int{74, 77, 10, 23, 35, 67, 36, 11}, - }, - } - dict := map[int]Card{} - for _, card := range cards { - dict[card.id] = card - } - expected := 30 - - actual := processCards(dict, cards) - - if actual != expected { - t.Errorf("ERROR: Total number of cards %d does not match expected %d", actual, expected) - } -} - -func TestCalculateNumberOfMatches(t *testing.T) { - cards := []Card{ - // Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 - { - 1, - []int{41, 48, 83, 86, 17}, - []int{83, 86, 6, 31, 17, 9, 48, 53}, - }, - // Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 - { - 2, - []int{13, 32, 20, 16, 61}, - []int{61, 30, 68, 82, 17, 32, 24, 19}, - }, - // Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 - { - 3, - []int{1, 21, 53, 59, 44}, - []int{69, 82, 63, 72, 16, 21, 14, 1}, - }, - // Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 - { - 4, - []int{41, 92, 73, 84, 69}, - []int{59, 84, 76, 51, 58, 5, 54, 83}, - }, - // Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 - { - 5, - []int{87, 83, 26, 28, 32}, - []int{88, 30, 70, 12, 93, 22, 82, 36}, - }, - // Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 - { - 6, - []int{31, 18, 13, 56, 72}, - []int{74, 77, 10, 23, 35, 67, 36, 11}, - }, - } - expected := 9 - - total := 0 - for _, card := range cards { - matches := calculateNumberOfMatches(card) - total += matches - - cards = append(cards, card) - } - - if total != expected { - t.Errorf("ERROR: Score %d does not match expected %d", total, expected) - } -} diff --git a/2023/go/internal/day_06/part_01/part_01.go b/2023/go/internal/day_06/part_01/part_01.go deleted file mode 100644 index 5735924..0000000 --- a/2023/go/internal/day_06/part_01/part_01.go +++ /dev/null @@ -1,85 +0,0 @@ -package part_01 - -import ( - "os" - "strconv" - "strings" -) - -const USE_SAMPLE = false - -/** - * Tried: - * - 72128 (too low) - * - 3317888 (correct!) - */ -func Solve() { - var filePath string - if USE_SAMPLE { - filePath = "../_input/day_06_part_01_sample.txt" - } else { - filePath = "../_input/day_06.txt" - } - contents, _ := os.ReadFile(filePath) - - lines := strings.Split(string(contents), "\r\n") - - timeLine := lines[0] - times := parseTimeLine(timeLine) - - distLine := lines[1] - distances := parseDistanceLine(distLine) - - answer := calculateAnswer(times, distances) - - println(answer) -} - -func parseTimeLine(timeLine string) []int { - prefix := "Time:" - return parseLine(prefix, timeLine) -} - -func parseDistanceLine(distLine string) []int { - prefix := "Distance:" - return parseLine(prefix, distLine) -} - -func parseLine(prefix string, line string) []int { - withoutTitle := strings.TrimPrefix(line, prefix) - - numbers := []int{} - for _, number := range strings.Split(withoutTitle, " ") { - if number == "" { - continue - } - numberInt, _ := strconv.Atoi(number) - numbers = append(numbers, numberInt) - } - return numbers -} - -func calculateAnswer(times []int, distances []int) int { - answer := 1 - for i, maxTime := range times { - recordDistance := distances[i] - - var greaterThanRecord []int - for buttonPressedFor := 0; buttonPressedFor <= maxTime; buttonPressedFor++ { - distance := calculateDistance(buttonPressedFor, maxTime) - if distance > recordDistance { - greaterThanRecord = append(greaterThanRecord, distance) - } - } - - if len(greaterThanRecord) > 0 { - answer *= len(greaterThanRecord) - } - } - - return answer -} - -func calculateDistance(buttonPressedFor int, maxTime int) int { - return buttonPressedFor * (maxTime - buttonPressedFor) -} diff --git a/2023/go/internal/day_06/part_01/part_01_test.go b/2023/go/internal/day_06/part_01/part_01_test.go deleted file mode 100644 index 7af828c..0000000 --- a/2023/go/internal/day_06/part_01/part_01_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package part_01 - -import "testing" - -func TestParseTimeLine(t *testing.T) { - tests := map[string]struct { - input string - expected []int - }{ - "empty": {"", []int{}}, - "sample": {"Time: 7 15 30", []int{7, 15, 30}}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := parseTimeLine(test.input) - if len(actual) != len(test.expected) { - t.Errorf("Expected %d, got %d", len(test.expected), len(actual)) - } - for i := 0; i < len(actual); i++ { - if actual[i] != test.expected[i] { - t.Errorf("Expected %d, got %d", test.expected[i], actual[i]) - } - } - }) - } -} - -func TestParseDistLine(t *testing.T) { - tests := map[string]struct { - input string - expected []int - }{ - "empty": {"", []int{}}, - "sample": {"Distance: 9 40 200", []int{9, 40, 200}}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := parseDistanceLine(test.input) - if len(actual) != len(test.expected) { - t.Errorf("Expected %d, got %d", len(test.expected), len(actual)) - } - for i := 0; i < len(actual); i++ { - if actual[i] != test.expected[i] { - t.Errorf("Expected %d, got %d", test.expected[i], actual[i]) - } - } - }) - } -} - -func TestCalculateAnswer(t *testing.T) { - tests := map[string]struct { - times []int - distances []int - expected int - }{ - "sample": {[]int{7, 15, 30}, []int{9, 40, 200}, 288}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := calculateAnswer(test.times, test.distances) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} - -func TestCalculateDistance(t *testing.T) { - tests := map[string]struct { - maxTime int - buttonPressedFor int - expected int - }{ - "7_7": {7, 7, 0}, - "7_6": {7, 6, 6}, - "7_5": {7, 5, 10}, - "7_4": {7, 4, 12}, - "7_3": {7, 3, 12}, - "7_2": {7, 2, 10}, - "7_1": {7, 1, 6}, - "7_0": {7, 0, 0}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := calculateDistance(test.buttonPressedFor, test.maxTime) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} diff --git a/2023/go/internal/day_06/part_02/part_02.go b/2023/go/internal/day_06/part_02/part_02.go deleted file mode 100644 index 316b169..0000000 --- a/2023/go/internal/day_06/part_02/part_02.go +++ /dev/null @@ -1,81 +0,0 @@ -package part_02 - -import ( - "os" - "strconv" - "strings" -) - -const USE_SAMPLE = false - -/** - * Tried: - * - 24655068 (correct!) - */ -func Solve() { - var filePath string - if USE_SAMPLE { - filePath = "../_input/day_06_part_02_sample.txt" - } else { - filePath = "../_input/day_06.txt" - } - contents, _ := os.ReadFile(filePath) - - lines := strings.Split(string(contents), "\r\n") - - timeLine := lines[0] - time := parseTimeLine(timeLine) - - distLine := lines[1] - distance := parseDistanceLine(distLine) - - answer := calculateAnswer(time, distance) - - println(answer) -} - -func parseTimeLine(timeLine string) int { - prefix := "Time:" - return parseLine(prefix, timeLine) -} - -func parseDistanceLine(distLine string) int { - prefix := "Distance:" - return parseLine(prefix, distLine) -} - -func parseLine(prefix string, line string) int { - withoutTitle := strings.TrimPrefix(line, prefix) - - numbers := []string{} - for _, number := range strings.Split(withoutTitle, " ") { - if number == "" { - continue - } - numbers = append(numbers, number) - } - - number := strings.Join(numbers, "") - numberInt, err := strconv.Atoi(number) - if err != nil { - panic(err) - } - - return numberInt -} - -func calculateAnswer(maxTime int, recordDistance int) int { - var greaterThanRecord []int - for buttonPressedFor := 0; buttonPressedFor <= maxTime; buttonPressedFor++ { - distance := calculateDistance(buttonPressedFor, maxTime) - if distance > recordDistance { - greaterThanRecord = append(greaterThanRecord, distance) - } - } - - return len(greaterThanRecord) -} - -func calculateDistance(buttonPressedFor int, maxTime int) int { - return buttonPressedFor * (maxTime - buttonPressedFor) -} diff --git a/2023/go/internal/day_06/part_02/part_02_test.go b/2023/go/internal/day_06/part_02/part_02_test.go deleted file mode 100644 index 67924dc..0000000 --- a/2023/go/internal/day_06/part_02/part_02_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package part_02 - -import "testing" - -func TestParseTimeLine(t *testing.T) { - tests := map[string]struct { - input string - expected int - }{ - "sample": {"Time: 7 15 30", 71530}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := parseTimeLine(test.input) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} - -func TestParseDistLine(t *testing.T) { - tests := map[string]struct { - input string - expected int - }{ - "sample": {"Distance: 9 40 200", 940200}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := parseDistanceLine(test.input) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} - -func TestCalculateAnswer(t *testing.T) { - tests := map[string]struct { - maxTime int - recordDistance int - expected int - }{ - "sample": {71530, 940200, 71503}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := calculateAnswer(test.maxTime, test.recordDistance) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} - -func TestCalculateDistance(t *testing.T) { - tests := map[string]struct { - maxTime int - buttonPressedFor int - expected int - }{ - "7_7": {7, 7, 0}, - "7_6": {7, 6, 6}, - "7_5": {7, 5, 10}, - "7_4": {7, 4, 12}, - "7_3": {7, 3, 12}, - "7_2": {7, 2, 10}, - "7_1": {7, 1, 6}, - "7_0": {7, 0, 0}, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := calculateDistance(test.buttonPressedFor, test.maxTime) - if actual != test.expected { - t.Errorf("Expected %d, got %d", test.expected, actual) - } - }) - } -} diff --git a/2023/go/internal/day_07/part_01/part_01.go b/2023/go/internal/day_07/part_01/part_01.go deleted file mode 100644 index a485dfd..0000000 --- a/2023/go/internal/day_07/part_01/part_01.go +++ /dev/null @@ -1,273 +0,0 @@ -package part_01 - -import ( - "os" - "strconv" - "strings" -) - -const USE_SAMPLE = false - -type handType int - -const ( - HIGH_CARD handType = iota - PAIR - TWO_PAIR - THREE_OF_A_KIND - FULL_HOUSE - FOUR_OF_A_KIND - FIVE_OF_A_KIND -) - -func (h handType) String() string { - return [...]string{"HIGH_CARD", "PAIR", "TWO_PAIR", "THREE_OF_A_KIND", "FULL_HOUSE", "FOUR_OF_A_KIND", "FIVE_OF_A_KIND"}[h] -} - -type cardType int - -const ( - TWO cardType = iota - THREE - FOUR - FIVE - SIX - SEVEN - EIGHT - NINE - TEN - JACK - QUEEN - KING - ACE -) - -func (c cardType) String() string { - return [...]string{"TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "TEN", "JACK", "QUEEN", "KING", "ACE"}[c] -} - -type hand struct { - strength handType - cards []cardType - bet int -} - -/** - * Tried: - * - 252489894 (too high) - * - 229176554 (too low) - * - 200253108 (too low) - */ -func Solve() { - var filePath string - if USE_SAMPLE { - filePath = "../_input/day_07_part_01_sample.txt" - } else { - filePath = "../_input/day_07.txt" - } - contents, err := os.ReadFile(filePath) - if err != nil { - panic(err) - } - - lines := strings.Split(string(contents), "\r\n") - var hands []hand - for _, line := range lines { - if line == "" { - continue - } - - hands = append(hands, parseLine(line)) - } - - mappedByStrength := mapByStrength(hands) - - sortedByHighest := make(map[handType][]hand) - for _, strength := range []handType{HIGH_CARD, PAIR, TWO_PAIR, THREE_OF_A_KIND, FULL_HOUSE, FOUR_OF_A_KIND, FIVE_OF_A_KIND} { - if _, ok := mappedByStrength[strength]; !ok { - continue - } - - toBeSorted := mappedByStrength[strength] - sortedByHighest[strength] = sortByHighest(toBeSorted) - } - - flattened := flatten(sortedByHighest) - - answer := calculateWinnings(flattened) - - println("Answer: ", answer) -} - -func parseLine(line string) hand { - parts := strings.Split(line, " ") - - unparsedCards := strings.Split(parts[0], "") - cards := parseCards(unparsedCards) - strength := calculateStrength(cards) - - bet, err := strconv.Atoi(parts[1]) - if err != nil { - panic(err) - } - - return hand{ - strength, - cards, - bet, - } -} - -func parseCards(unparsedCards []string) []cardType { - var cards []cardType - for _, card := range unparsedCards { - switch card { - case "2": - cards = append(cards, TWO) - case "3": - cards = append(cards, THREE) - case "4": - cards = append(cards, FOUR) - case "5": - cards = append(cards, FIVE) - case "6": - cards = append(cards, SIX) - case "7": - cards = append(cards, SEVEN) - case "8": - cards = append(cards, EIGHT) - case "9": - cards = append(cards, NINE) - case "T": - cards = append(cards, TEN) - case "J": - cards = append(cards, JACK) - case "Q": - cards = append(cards, QUEEN) - case "K": - cards = append(cards, KING) - case "A": - cards = append(cards, ACE) - } - } - return cards -} - -func calculateStrength(cards []cardType) handType { - strength := map[cardType]int{} - for _, card := range cards { - if _, ok := strength[card]; !ok { - strength[card] = 0 - } - strength[card]++ - } - - var pairs int - var hasThreeOfAKind bool - for _, count := range strength { - if count == 5 { - return FIVE_OF_A_KIND - } - - if count == 4 { - return FOUR_OF_A_KIND - } - - if count == 3 { - hasThreeOfAKind = true - } - - if count == 2 { - pairs++ - } - } - - if hasThreeOfAKind && pairs == 1 { - return FULL_HOUSE - } - - if hasThreeOfAKind { - return THREE_OF_A_KIND - } - - if pairs == 2 { - return TWO_PAIR - } - - if pairs == 1 { - return PAIR - } - - return HIGH_CARD -} - -func mapByStrength(hands []hand) map[handType][]hand { - - handsByStrength := make(map[handType][]hand) - for _, hand := range hands { - handsByStrength[hand.strength] = append(handsByStrength[hand.strength], hand) - } - - return handsByStrength -} - -// low to high -func sortByHighest(hands []hand) []hand { - var partition = func(arr []hand, low, high int) ([]hand, int) { - pivot := arr[high] - index := low - - for i := low; i < high; i++ { - // Always 5 cards - for j := 0; j < 5; j++ { - if arr[i].cards[j] < pivot.cards[j] { - arr[i], arr[index] = arr[index], arr[i] - index++ - break - } - - if arr[i].cards[j] != pivot.cards[j] { - break - } - } - } - - arr[high], arr[index] = arr[index], arr[high] - - return arr, index - } - - var quickSort func(arr []hand, low, high int) []hand - quickSort = func(arr []hand, low, high int) []hand { - if low < high { - arr, pivot := partition(arr, low, high) - - quickSort(arr, low, pivot-1) - quickSort(arr, pivot+1, high) - } - - return arr - } - - hands = quickSort(hands, 0, len(hands)-1) - - return hands -} - -func flatten(hands map[handType][]hand) []hand { - var flat []hand - for _, handType := range []handType{HIGH_CARD, PAIR, TWO_PAIR, THREE_OF_A_KIND, FULL_HOUSE, FOUR_OF_A_KIND, FIVE_OF_A_KIND} { - flat = append(flat, hands[handType]...) - } - return flat -} - -func calculateWinnings(hands []hand) int { - var winnings int - for i, hand := range hands { - earned := hand.bet * (i + 1) - winnings += earned - println("hand ", i, ": { strength: ", hand.strength.String(), ", cards: [", hand.cards[0], hand.cards[1], hand.cards[2], hand.cards[3], hand.cards[4], "], earned: ", earned, " }") - } - return winnings -} diff --git a/2023/go/internal/day_07/part_01/part_01_test.go b/2023/go/internal/day_07/part_01/part_01_test.go deleted file mode 100644 index 6ceabe8..0000000 --- a/2023/go/internal/day_07/part_01/part_01_test.go +++ /dev/null @@ -1,432 +0,0 @@ -package part_01 - -import "testing" - -func TestParseLine(t *testing.T) { - tests := map[string]struct { - input string - expected hand - }{ - "sample_1": { - input: "32T3K 765", - expected: hand{ - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - }, - "sample_2": { - input: "T55J5 684", - expected: hand{ - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - }, - "sample_3": { - input: "KK677 28", - expected: hand{ - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - }, - "sample_4": { - input: "KTJJT 220", - expected: hand{ - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - }, - "sample_5": { - input: "QQQJA 483", - expected: hand{ - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - "full_house": { - input: "QQQAA 999", - expected: hand{ - strength: FULL_HOUSE, - cards: []cardType{QUEEN, QUEEN, QUEEN, ACE, ACE}, - bet: 999, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := parseLine(test.input) - - if actual.strength != test.expected.strength { - t.Errorf("Strength: expected %v, got %v", test.expected.strength, actual.strength) - } - - if len(actual.cards) != len(test.expected.cards) { - t.Errorf("Cards: expected %v, got %v", test.expected.cards, actual.cards) - } - - for i, card := range actual.cards { - if card != test.expected.cards[i] { - t.Errorf("Card Order: expected %v, got %v", test.expected.cards, actual.cards) - } - } - - if actual.bet != test.expected.bet { - t.Errorf("Bet: expected %v, got %v", test.expected.bet, actual.bet) - } - }) - } -} - -func TestMapByStrength(t *testing.T) { - tests := map[string]struct { - input []hand - expected map[handType][]hand - }{ - "sample": { - input: []hand{ - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - expected: map[handType][]hand{ - PAIR: { - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - }, - TWO_PAIR: { - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - }, - THREE_OF_A_KIND: { - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := mapByStrength(test.input) - - for strength, hands := range actual { - expected := test.expected[strength] - - if len(hands) != len(expected) { - t.Errorf("Length: expected %v, got %v", len(expected), len(hands)) - } - - for i, hand := range hands { - if hand.strength != expected[i].strength { - t.Errorf("Strength: expected %v, got %v", expected[i].strength, hand.strength) - } - - if len(hand.cards) != len(expected[i].cards) { - t.Errorf("Cards: expected %v, got %v", expected[i].cards, hand.cards) - } - - for j, card := range hand.cards { - if card != expected[i].cards[j] { - t.Errorf("Card Order: expected %v, got %v", expected[i].cards, hand.cards) - } - } - - if hand.bet != expected[i].bet { - t.Errorf("Bet: expected %v, got %v", expected[i].bet, hand.bet) - } - } - } - }) - } -} - -func TestSortByHighest(t *testing.T) { - tests := map[string]struct { - input []hand - expected []hand - }{ - "sample": { - input: []hand{ - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - expected: []hand{ - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := sortByHighest(test.input) - - if len(actual) != len(test.expected) { - t.Errorf("Length: expected %v, got %v", len(test.expected), len(actual)) - } - - for i, hand := range actual { - if hand.strength != test.expected[i].strength { - t.Errorf("Strength: expected %v, got %v", test.expected[i].strength, hand.strength) - } - - if len(hand.cards) != len(test.expected[i].cards) { - t.Errorf("Cards: expected %v, got %v", test.expected[i].cards, hand.cards) - } - - for j, card := range hand.cards { - if card != test.expected[i].cards[j] { - t.Errorf("Card Order: expected %v, got %v", test.expected[i].cards, hand.cards) - } - } - - if hand.bet != test.expected[i].bet { - t.Errorf("Bet: expected %v, got %v", test.expected[i].bet, hand.bet) - } - } - }) - } -} - -func TestFlatten(t *testing.T) { - tests := map[string]struct { - input map[handType][]hand - expected []hand - }{ - "sample": { - // Order jumbled to ensure sorting works - input: map[handType][]hand{ - TWO_PAIR: { - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - }, - PAIR: { - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - }, - THREE_OF_A_KIND: { - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - }, - expected: []hand{ - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := flatten(test.input) - - if len(actual) != len(test.expected) { - t.Errorf("Length: expected %v, got %v", len(test.expected), len(actual)) - } - - for i, hand := range actual { - expected := test.expected[i] - - if hand.strength != expected.strength { - t.Errorf("Strength: expected %v, got %v", expected.strength, hand.strength) - } - - if len(hand.cards) != len(expected.cards) { - t.Errorf("Cards: expected %v, got %v", expected.cards, hand.cards) - } - - for i, card := range hand.cards { - if card != expected.cards[i] { - t.Errorf("Card Order: expected %v, got %v", expected.cards, hand.cards) - } - } - - if hand.bet != expected.bet { - t.Errorf("Bet: expected %v, got %v", expected.bet, hand.bet) - } - } - }) - } -} - -func TestCalculateWinnings(t *testing.T) { - tests := map[string]struct { - input []hand - expected int - }{ - "sample": { - input: []hand{ - { - strength: PAIR, - cards: []cardType{THREE, TWO, TEN, THREE, KING}, - bet: 765, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, TEN, JACK, JACK, TEN}, - bet: 220, - }, - { - strength: TWO_PAIR, - cards: []cardType{KING, KING, SIX, SEVEN, SEVEN}, - bet: 28, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{TEN, FIVE, FIVE, JACK, FIVE}, - bet: 684, - }, - { - strength: THREE_OF_A_KIND, - cards: []cardType{QUEEN, QUEEN, QUEEN, JACK, ACE}, - bet: 483, - }, - }, - expected: 6440, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual := calculateWinnings(test.input) - - if actual != test.expected { - t.Errorf("Winnings: expected %v, got %v", test.expected, actual) - } - }) - } -} diff --git a/2023/go/main.go b/2023/go/main.go deleted file mode 100644 index 7d71b47..0000000 --- a/2023/go/main.go +++ /dev/null @@ -1,86 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_01" - day_02_part_01 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_02/part_01" - day_02_part_02 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_02/part_02" - day_03_part_01 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_03/part_01" - day_04_part_01 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_04/part_01" - day_04_part_02 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_04/part_02" - day_06_part_01 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_06/part_01" - day_06_part_02 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_06/part_02" - day_07_part_01 "github.com/DJOLEARY/Advent_of_Code/2023/Go/internal/day_07/part_01" - _ "github.com/outrigdev/outrig/autoinit" -) - -func main() { - day := flag.Int("day", 1, "Day to run") - part := flag.Int("part", 2, "Part to run, must be 1 or 2") - - flag.Parse() - - if *part < 1 || *part > 2 { - println("Invalid part number, must be 1 or 2") - os.Exit(1) - } - - switch *day { - case 1: - switch *part { - case 1: - println("Day 1 part 1 not implemented") - os.Exit(1) - case 2: - day_01.Solve() - } - - case 2: - switch *part { - case 1: - day_02_part_01.Solve() - case 2: - day_02_part_02.Solve() - } - - case 3: - switch *part { - case 1: - day_03_part_01.Solve() - case 2: - println("Day 3 part 2 not implemented") - os.Exit(1) - } - - case 4: - switch *part { - case 1: - day_04_part_01.Solve() - case 2: - day_04_part_02.Solve() - } - - case 6: - switch *part { - case 1: - day_06_part_01.Solve() - case 2: - day_06_part_02.Solve() - } - - case 7: - switch *part { - case 1: - day_07_part_01.Solve() - case 2: - println("Day 7 part 2 not implemented") - os.Exit(1) - } - - default: - println("Day not implemented") - os.Exit(1) - } -} -- cgit v1.2.3