diff options
| author | DJ O'Leary <dijitol@proton.me> | 2026-06-26 18:04:09 +0200 |
|---|---|---|
| committer | DJ O'Leary <dijitol@proton.me> | 2026-06-26 18:04:09 +0200 |
| commit | 6d8fb621d1e93b83786890d6d9cb6f0d8defa8ae (patch) | |
| tree | 17c90d3984c114aa023600cc5bec6f6004b02243 /go/2023/internal/day_02 | |
| parent | ad4ea5ca4bc9f7540ee1d6a4fa2d881709dc6459 (diff) | |
refactor!: invert repo directory structure
now is language first
Diffstat (limited to 'go/2023/internal/day_02')
| -rw-r--r-- | go/2023/internal/day_02/part_01/part_01.go | 138 | ||||
| -rw-r--r-- | go/2023/internal/day_02/part_01/part_01_test.go | 102 | ||||
| -rw-r--r-- | go/2023/internal/day_02/part_02/part_02.go | 114 | ||||
| -rw-r--r-- | go/2023/internal/day_02/part_02/part_02_test.go | 84 |
4 files changed, 438 insertions, 0 deletions
diff --git a/go/2023/internal/day_02/part_01/part_01.go b/go/2023/internal/day_02/part_01/part_01.go new file mode 100644 index 0000000..9efe20f --- /dev/null +++ b/go/2023/internal/day_02/part_01/part_01.go @@ -0,0 +1,138 @@ +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/go/2023/internal/day_02/part_01/part_01_test.go b/go/2023/internal/day_02/part_01/part_01_test.go new file mode 100644 index 0000000..33e5fbf --- /dev/null +++ b/go/2023/internal/day_02/part_01/part_01_test.go @@ -0,0 +1,102 @@ +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/go/2023/internal/day_02/part_02/part_02.go b/go/2023/internal/day_02/part_02/part_02.go new file mode 100644 index 0000000..ffb9691 --- /dev/null +++ b/go/2023/internal/day_02/part_02/part_02.go @@ -0,0 +1,114 @@ +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/go/2023/internal/day_02/part_02/part_02_test.go b/go/2023/internal/day_02/part_02/part_02_test.go new file mode 100644 index 0000000..6952899 --- /dev/null +++ b/go/2023/internal/day_02/part_02/part_02_test.go @@ -0,0 +1,84 @@ +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) + } + } +} |
