Chronal Calibration is the opening puzzle for the 2018 Advent of Code.
The input is a series of delta values, such as +1
and -2
, to be applied to an initial value of zero to obtain the final cumulative value.
In essence, we wish to add each value in sequence using arithmetic addition, which sounds a bit like a fold:
To construct the values
list, we obtain an enumerator over each line in the input:
However, this would result in a list of strings, which have a different behaviour defined for the addition operator than what we want. Since each input value can be interpreted as an integer value, we'll do exactly that:
The second part of the puzzle cycles through the input list infinitely, repeating the folding operation until the result is one that has been seen before.
We'll handle this with a seen
set, and checking an intermediate result for presence in it:
repeated = frequency if seen.include?(frequency)
Now, we need to cycle infinitely through the values list, which is made easy by the Enumerable#cycle
method.
We will again make use of reduce
, albeit in its block form, which allows the block to break when the repetition criteria is fulfilled, and return the repeated value:
seen = Set.new
repeated = values.cycle.reduce(0) do |frequency, value|
{Test for repeated frequency, 5}
end
Used in section 7
Now that the repetition test will be executing in a reduce
block, it needs to change slightly.
Specifically, we need to break out of the loop (with the repeated value) when it is detected that the value already exists in the set.
This is done using the add?
method, which will return a "falsey" value if the value already exists in the set:
frequency += value break frequency unless seen.add?(frequency) frequency