# Advent of Code 2017, Day 13: Packet Scanners

## Part A

On Day 13 we are simulating packet scanners in an imaginary firewall. Our input looks like this:

``````0: 3
1: 2
4: 4
6: 4
``````

First number is a layer number in the firewall and second number is range describing how many cells scanner in the given layer will scan. Scanner goes from the beginning to the end and then moves back. For example if the range is 3, scanner will check cells number 0, 1, 2, 1, 0, 1, 2 etc.

Each scanner is moving to the next cell in one picosecond. When our packet is caught we can calculate the severity of this incident by multiplying the layer number by its range.

Our goal is to calculate the severity of the whole trip.

Here is the solution:

``````data = File.readlines("13.txt", chomp: true)

layers = {}
size = 0

data.each do |line|
depth, range = line.split(":").map(&:strip).map(&:to_i)

layers[depth] = range
size = depth if depth > size
end

def position(range, second)
modulo = range * 2 - 2
middle = modulo / 2

reminder = second % modulo

if reminder > middle
modulo - reminder
else
reminder
end
end

severity = 0
(0..size).each do |second|
range = layers[second]

next unless range

pos = position(range, second)

if pos == 0
severity += (second * range)
end
end

puts severity
``````

We have `position` method which calculates the scanner position with given range and at given second. Our packet will be always traveling in the first cell, so for each time packet moves to another layer we need to check what is the current position of the scanner for this layer. If it is 0 it means our packet was caught and we add up to our severity.

## Part B

In the second part we need to calculate the delay required to pass through all layers undetected.

Here is the solution:

``````data = File.readlines("13.txt", chomp: true)

layers = {}
size = 0

data.each do |line|
depth, range = line.split(":").map(&:strip).map(&:to_i)

layers[depth] = range
size = depth if depth > size
end

def position(range, second)
modulo = range * 2 - 2
middle = modulo / 2

reminder = second % modulo

if reminder > middle
modulo - reminder
else
reminder
end
end

def caught?(layers, size, delay)
(0..size).each do |depth|
range = layers[depth]
second = depth + delay

next unless range

if position(range, second) == 0
return true
end
end

false
end

delay = 0
while true
if caught?(layers, size, delay)
delay += 1
else
puts delay
break
end
end
``````

Here we are reusing the solution for the first part, but we also have parametrized delay. It is basically brute-force approach. We start with 0 delay and check if we were caught. If yes, we try to delay by one more picosecond until we find the delay that let us pass undetected.