master
1package main
2
3import (
4 "advent2023/internal/aoc"
5 "strconv"
6 "strings"
7)
8
9// A collection of cubes
10// Can be used to represent:
11// - A constraint (e.g. maxCubes)
12// - A collected state (e.g. minCubes)
13// - An instance of a revield set of cubes
14type bag struct {
15 blue int
16 red int
17 green int
18}
19
20// Game stuct containing mutliple instances of
21// subsets of cubes that were revealed from the bag
22type game struct {
23 id int
24 bags []bag
25}
26
27const (
28 blue = "blue"
29 green = "green"
30 red = "red"
31)
32
33func (i bag) valid(maxCubes bag) bool {
34 if i.blue > maxCubes.blue {
35 return false
36 }
37 if i.green > maxCubes.green {
38 return false
39 }
40 if i.red > maxCubes.red {
41 return false
42 }
43 return true
44}
45
46func (i bag) power() int {
47 return i.green * i.red * i.blue
48}
49
50// Example input:
51// Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
52func parseGame(input string) game {
53 input = strings.TrimPrefix(input, "Game ")
54 idSplit := strings.Split(input, ":")
55 id, _ := strconv.Atoi(idSplit[0])
56
57 bags := []bag{}
58 bagString := strings.Split(idSplit[1], ";")
59 for _, iString := range bagString {
60
61 i := bag{}
62 cubes := strings.Split(iString, ",")
63 for _, c := range cubes {
64
65 c = strings.Trim(c, " ")
66 countSplit := strings.Split(c, " ")
67 if countSplit[1] == blue {
68 i.blue, _ = strconv.Atoi(countSplit[0])
69 }
70 if countSplit[1] == red {
71 i.red, _ = strconv.Atoi(countSplit[0])
72 }
73 if countSplit[1] == green {
74 i.green, _ = strconv.Atoi(countSplit[0])
75 }
76 }
77 bags = append(bags, i)
78 }
79
80 return game{
81 id: id,
82 bags: bags,
83 }
84}
85
86func solvePart1(input []string) (solution int) {
87 solution = 0
88 maxCubes := bag{
89 blue: 14,
90 red: 12,
91 green: 13,
92 }
93 for _, line := range input {
94 game := parseGame(line)
95 valid := true
96 for _, bag := range game.bags {
97 if !bag.valid(maxCubes) {
98 valid = false
99 break
100 }
101 }
102 if valid {
103 solution += game.id
104 }
105 }
106 return solution
107}
108
109// Show that you can maintain state across bags in a game
110// Find the minimum number of cubes of each color across bags
111func solvePart2(input []string) (solution int) {
112 solution = 0
113 for _, line := range input {
114 minCubes := bag{
115 blue: 0,
116 red: 0,
117 green: 0,
118 }
119 g := parseGame(line)
120 for _, bag := range g.bags {
121 if bag.blue > minCubes.blue {
122 minCubes.blue = bag.blue
123 }
124 if bag.red > minCubes.red {
125 minCubes.red = bag.red
126 }
127 if bag.green > minCubes.green {
128 minCubes.green = bag.green
129 }
130 }
131 solution += minCubes.power()
132 }
133 return solution
134}
135
136func main() {
137 day := aoc.Day2
138 aoc.SolveExample(day, aoc.Part1, solvePart1, 8)
139 aoc.SolvePuzzle(day, aoc.Part1, solvePart1, 2447)
140 aoc.SolveExample(day, aoc.Part2, solvePart2, 2286)
141 aoc.SolvePuzzle(day, aoc.Part2, solvePart2, 56322)
142}