Part 1
Read in a series of present dimensions, one per line, in the format lxwxh, where l is the length, w is the width, and h is the height. Calculate the wrapping paper required for the present using the total surface area (2*l*w + 2*l*h + 2*w*h), plus the area of the smallest side.
Test input: There is no test file for today, just a few examples.
Solution
To start with, we should design a simple data structure to represent a present. We need to store the length, width, height, areas of the sides, and the wrapping paper requirement.
type Present struct {
length int
width int
height int
sideAreas []int
wrappingPaper int
}We use int rather than uint for storing dimensions as that is the Go Way (e.g. len returns int), even though it is impossible for a dimension to be negative in normal usage (there may be some areas of abstract mathematics where it is useful to have negative dimensions).
We could also use [3]int as the definition for sideAreas because there will always be three sides (mirrored to make six in total), however using a slice instead of an array allows us to pass the value directly into other functions, most of which expect slices. If we used an array, we would have to convert it to a slice using sideAreas[:].
Next, we need a function which parses the text representation of a present’s dimensions and returns a populated Present struct:
func getPresent(input string) (Present, error) {
present := Present{}
input = strings.TrimSpace(input)
dimensions := strings.Split(input, "x")
if len(dimensions) == 3 {
present.length, _ = strconv.Atoi(dimensions[0])
present.width, _ = strconv.Atoi(dimensions[1])
present.height, _ = strconv.Atoi(dimensions[2])
present.sideAreas = []int{
present.length * present.width,
present.length * present.height,
present.width * present.height,
}
present.wrappingPaper = lo.SumBy(present.sideAreas, func(item int) int {
return 2 * item
})
present.wrappingPaper += lo.Min(present.sideAreas)
return present, nil
}
return present, errors.New("could not parse present string")
}This function will either parse the string and return a Present struct with a nil error, or an empty struct with a non-nil error.
Before we use this function, we should write some tests for it. These include the tests from the puzzle page, as well as invalid values to ensure that the parsing works as expected.
func TestGetPresent(t *testing.T) {
present, err := getPresent("2x3x4")
assert.Nil(t, err)
assert.Equal(t, Present{
length: 2,
width: 3,
height: 4,
sideAreas: []int{6, 8, 12},
wrappingPaper: 58,
}, present)
present, err = getPresent("1x1x10")
assert.Nil(t, err)
assert.Equal(t, Present{
length: 1,
width: 1,
height: 10,
sideAreas: []int{1, 10, 10},
wrappingPaper: 43,
}, present)
present, err = getPresent("")
assert.Error(t, err)
assert.Equal(t, Present{}, present)
}Now we need to iterate over every line in the file to generate a slice of Presents, and sum the wrappingPaper member:
func main() {
inputBytes, _ := os.ReadFile("../2015-02-input.txt")
inputString := string(inputBytes)
presentStrings := strings.Split(inputString, "\n")
presents := []Present{}
for ps := range presentStrings {
if len(presentStrings[ps]) > 0 {
present, _ := getPresent(presentStrings[ps])
presents = append(presents, present)
}
}
totalWrapperPaper := lo.SumBy(presents, func(present Present) int {
return present.wrappingPaper
})
fmt.Println(totalWrapperPaper)
}