Day 1, 2018: Chronal Calibration

1. Introduction

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.

2. Folding the input value list

In essence, we wish to add each value in sequence using arithmetic addition, which sounds a bit like a fold:

{Fold input value list 2}
total = values.reduce(:+)

Used in sections 4 and 7

To construct the values list, we obtain an enumerator over each line in the input:

{Read and interpret the input 2}
values = ARGF.each_line

Used in sections 4 and 7

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:

{Read and interpret the input 2} +=
  .map(&:to_i)

Used in sections 4 and 7

3.

{Output the solution 3}
puts total

Redefined in section 6

Used in sections 4 and 7

4.

{ruby.rb 4}
{Read and interpret the input, 2}
{Fold input value list, 2}
{Output the solution, 3}

Redefined in section 7

5. Finding the first repeated sum

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:

{Test for repeated frequency 5}
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:

{Cycle until repeated sum is found 5}
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:

{Test for repeated frequency 5} :=
frequency += value
break frequency unless seen.add?(frequency)
frequency

6.

{Output the solution 3} :=
puts total, repeated

Used in sections 4 and 7

7.

{ruby.rb 4} :=
require 'set'

{Read and interpret the input, 2}
{Fold input value list, 2}
{Cycle until repeated sum is found, 5}
{Output the solution, 3}