diff --git a/2023/day02/main.go b/2023/day02/main.go new file mode 100644 index 0000000..888f54e --- /dev/null +++ b/2023/day02/main.go @@ -0,0 +1,118 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "os" + "strconv" + "strings" +) + +var input string + +func init() { + fileBytes, err := os.ReadFile("input.txt") + if err != nil { + fmt.Print(err) + } + input = string(fileBytes) + input = strings.TrimRight(input, "\n") + if len(input) == 0 { + panic("empty input.txt file") + } +} + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(input) + fmt.Println("Output:", ans) + } else { + ans := part2(input) + fmt.Println("Output:", ans) + } +} + +func part1(input string) int { + var maxRed, maxGreen, maxBlue int + var possible bool + var sum, gameId int + + // from puzzle description + maxRed = 12 + maxGreen = 13 + maxBlue = 14 + + for _, line := range strings.Split(input, "\n") { + parts := strings.Split(line, ":") + fmt.Sscanf(parts[0], "Game %d", &gameId) + + hands := strings.Split(parts[1], ";") + possible = true + for _, hand := range hands { + cubes := strings.Split(hand, ",") + for _, cube := range cubes { + counts := strings.Fields(cube) + num, _ := strconv.Atoi(counts[0]) + color := counts[1] + switch color { + case "red": + possible = possible && (num <= maxRed) + case "green": + possible = possible && (num <= maxGreen) + case "blue": + possible = possible && (num <= maxBlue) + } + } + } + if possible { + sum += gameId + } + } + return sum +} + +func part2(input string) int { + var minRed, minGreen, minBlue int + var sum, gameId int + for _, line := range strings.Split(input, "\n") { + parts := strings.Split(line, ":") + fmt.Sscanf(parts[0], "Game %d", &gameId) + + hands := strings.Split(parts[1], ";") + + minRed = 0 + minGreen = 0 + minBlue = 0 + + for _, hand := range hands { + cubes := strings.Split(hand, ",") + for _, cube := range cubes { + counts := strings.Fields(cube) + num, _ := strconv.Atoi(counts[0]) + color := counts[1] + switch color { + case "red": + if num > minRed { + minRed = num + } + case "green": + if num > minGreen { + minGreen = num + } + case "blue": + if num > minBlue { + minBlue = num + } + } + } + } + sum += minRed * minGreen * minBlue + } + return sum +} diff --git a/2023/day02/main_test.go b/2023/day02/main_test.go new file mode 100644 index 0000000..7b375ef --- /dev/null +++ b/2023/day02/main_test.go @@ -0,0 +1,63 @@ +package main + +import ( + "testing" +) + +var example = `Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 8, + }, + // { + // name: "actual", + // input: input, + // want: 0, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + { + name: "example", + input: example, + want: 2286, + }, + // { + // name: "actual", + // input: input, + // want: 0, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +}