master
Raw Download raw file
  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}