Part 1
Read in a list of characters and use those to increment or decrement a number representing the current floor, starting at zero. Find the final floor.
The only characters in the input are:
(
: Go up one floor)
: Go down one floor
There is no upper or lower limit on the current floor.
Test input: There is no test file for today, just a few examples.
Solution
This is straightforward, we just need to write a function which takes a start floor and input, and returns the final floor.
func finalFloor(startFloor int, input string) int {
currentFloor := startFloor
instructions := strings.Split(input, "")
for i := range instructions {
switch instructions[i] {
case "(":
currentFloor++
case ")":
currentFloor--
}
}
return currentFloor
}
I originally an if
/ else if
block, but the Go tooling suggested rewriting it as a switch
statement. It was interesting that the tooling is intelligent enough to notice this, although I do not know if it there is any reason to prefer one over the other (switch
is perhaps slightly more readable due to having fewer curly braces). case
statements in Go do not fall-through by default and support expressions rather than just constants, so many if
/ else if
blocks can be written as a switch
.
Testing is straightforward, we call our finalFloor
function with the examples from the puzzle page and assert that we end up at the right floor:
func TestFinalFloor(t *testing.T) {
assert.Equal(t, 0, finalFloor(0, "(())"))
assert.Equal(t, 0, finalFloor(0, "()()"))
assert.Equal(t, 3, finalFloor(0, "((("))
assert.Equal(t, 3, finalFloor(0, "(()(()("))
assert.Equal(t, 3, finalFloor(0, "))((((("))
assert.Equal(t, -1, finalFloor(0, "())"))
assert.Equal(t, -1, finalFloor(0, "))("))
assert.Equal(t, -3, finalFloor(0, ")))"))
assert.Equal(t, -3, finalFloor(0, ")())())"))
}
Part 2
Given the same instructions, find the position of the first character that causes the floor to reach a certain value - in this case -1
(the basement).
Solution
This is only slightly more complex than part 1. As well as the start floor and the input, we also need the target floor, and we stop as soon as we have reached the target, returning the position (-1 will be returned if we never reach it, as that is not a valid position).
func targetFloorPosition(startFloor int, targetFloor int, input string) int {
currentFloor := startFloor
instructions := strings.Split(input, "")
for i := range instructions {
switch instructions[i] {
case "(":
currentFloor++
case ")":
currentFloor--
}
if currentFloor == targetFloor {
// range is zero indexed but positions are one indexed
return i + 1
}
}
// Never reached the target floor
return -1
}
Our test suite is fairly simple as there are only two examples on the puzzle page. We also add an additional assertion for the case where the target floor is never reached.
func TestTargetFloorPosition(t *testing.T) {
assert.Equal(t, 1, targetFloorPosition(0, -1, ")"))
assert.Equal(t, 5, targetFloorPosition(0, -1, "()())"))
assert.Equal(t, -1, targetFloorPosition(0, -1, "((((("))
}
Overall thoughts
As is to be expected from the first day, this was a very puzzle to solve.