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.

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.