Advent of Code 2020: Day 15 (Ruby solution)

Today's puzzle is a kind of n-back game.

In this game, the players take turns saying numbers. They begin by taking turns reading from a list of starting numbers (the puzzle input). Then, each turn consists of considering the most recently spoken number:

  • If that was the first time the number has been spoken, the current player says 0.
  • Otherwise, the number had been spoken before; the current player announces how many turns apart the number is from when it was previously spoken.

In the first task, you are asked what would be the 2020th number spoken. Later, you are supposed to check the 30000000th one. If you choose an effective method using an associative array, you can solve both tasks with one function.

My Ruby solution:

def determine_number starting_numbers, nth
  i = starting_numbers.size - 1
  last = starting_numbers.last
  last_spoken = starting_numbers[0..-2].map.with_index { |v, index| {v => index} }.reduce(:merge)
  while i < nth - 1
    prev_last = last
    last = last_spoken.has_key?(prev_last) ? i - last_spoken[prev_last] : 0
    last_spoken[prev_last] = i
    i += 1
  end
  last
end

INPUT = [7, 12, 1, 0, 16, 2].freeze
puts "First task answer: #{determine_number INPUT, 2020}"
puts "Second task answer: #{determine_number INPUT, 30000000}"