2022 Day 1
Part 1
Problem
Each line in the file contains an inventory item with the number of calories. Blank lines separate each group of items. Find the inventory group with the highest number of calories and print that number.
General solution
Create a nested data structure which is an array of arrays, where the first level is the list of inventory groups and the second level is the list of items within that group. Iterate over the groups and keep a record of the highest calories count.
Solution: Go
In Go we will use slices instead of arrays, as arrays are of a fixed size in Go whereas slices can grow (and shrink) dynamically (in other languages, such as PHP, an array can be a dynamic size).
For clarity, we will define structs
for individual items and groups of items. These only contain one member and so may seem overkill, but they make the code clearer and allow for future expansion (which is often needed in part 2).
In this case, we could have simply used a slice of integers, since we do not actually need the details of each item - everything is aggregated at the group level.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
type InventoryItem struct {
calories int
}
type InventoryGroup struct {
items []InventoryItem
}
inventoryGroups := []InventoryGroup{}
currentGroupIndex := 0
currentGroupInitialised := false
highestCalories := 0
scanner := bufio.NewScanner(os.Stdin)
// Read in the data and convert into structure
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if len(line) > 0 {
if !currentGroupInitialised {
inventoryGroups = append(inventoryGroups, InventoryGroup{})
currentGroupInitialised = true
}
// ASSUMPTION: Every non-empty line contains a number which can be expressed as an integer
var inventoryItem InventoryItem
inventoryItem.calories, _ = strconv.Atoi(line)
inventoryGroups[currentGroupIndex].items = append(inventoryGroups[currentGroupIndex].items, inventoryItem)
} else {
// Blank line separates groups
currentGroupIndex++
currentGroupInitialised = false
}
}
// Now the data has been transformed into a structure, find the highest calorie group
for groupIndex := range inventoryGroups {
group := inventoryGroups[groupIndex]
groupCalories := 0
for itemIndex := range group.items {
groupCalories += group.items[itemIndex].calories
}
if groupCalories > highestCalories {
highestCalories = groupCalories
}
}
fmt.Println(highestCalories)
}
Part 2
Problem
Find the sum of the calories of the three most calorific groups.
General solution
As previously, iterate over the groups, but this time find the three highest groups and sum their calories.
Solution: Go
The main change from part 1 is that we create an array of highest calories (array is fine as the size is fixed) and initialise this with zeroes. We then check the calorie count of each group and replace the lowest of the highest calories if the group calorie count is greater, always sorting the highest calorie array to ensure it is in ascending order (with a small array this is unlikely to have performance issues).
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func main() {
type InventoryItem struct {
calories int
}
type InventoryGroup struct {
items []InventoryItem
}
inventoryGroups := []InventoryGroup{}
currentGroupIndex := 0
currentGroupInitialised := false
highestCalories := []int{0, 0, 0}
scanner := bufio.NewScanner(os.Stdin)
// Read in the data and convert into structure
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if len(line) > 0 {
if !currentGroupInitialised {
inventoryGroups = append(inventoryGroups, InventoryGroup{})
currentGroupInitialised = true
}
// ASSUMPTION: Every non-empty line contains a number which can be expressed as an integer
var inventoryItem InventoryItem
inventoryItem.calories, _ = strconv.Atoi(line)
inventoryGroups[currentGroupIndex].items = append(inventoryGroups[currentGroupIndex].items, inventoryItem)
} else {
// Blank line separates groups
currentGroupIndex++
currentGroupInitialised = false
}
}
// Now the data has been transformed into a structure, find the highest calorie group
for groupIndex := range inventoryGroups {
group := inventoryGroups[groupIndex]
groupCalories := 0
for itemIndex := range group.items {
groupCalories += group.items[itemIndex].calories
}
// If this group has a higher calorie count than the lowest of the highest
// calorie groups, replace the lowest with the current group
if groupCalories > highestCalories[0] {
highestCalories[0] = groupCalories
// Resort the highest calories into ascending order, i.e. element 0
// is the smallest
sort.Slice(highestCalories, func(x, y int) bool {
return highestCalories[x] < highestCalories[y]
})
}
}
// Finally, find the sum of the highest calories
highestCaloriesSum := 0
for hc := range highestCalories {
highestCaloriesSum += highestCalories[hc]
}
fmt.Println(highestCaloriesSum)
}