## --- Day 5: Hydrothermal Venture ---

You come across a field of hydrothermal vents on the ocean floor! These vents constantly produce large, opaque clouds, so it would be best to avoid them if possible.

They tend to form in *lines*; the submarine helpfully produces a list of nearby lines of vents (your puzzle input) for you to review. For example:

```
0,9 -> 5,9
8,0 -> 0,8
9,4 -> 3,4
2,2 -> 2,1
7,0 -> 7,4
6,4 -> 2,0
0,9 -> 2,9
3,4 -> 1,4
0,0 -> 8,8
5,5 -> 8,2
```

Each line of vents is given as a line segment in the format `x1,y1 -> x2,y2`

where `x1`

,`y1`

are the coordinates of one end the line segment and `x2`

,`y2`

are the coordinates of the other end. These line segments include the points at both ends. In other words:

- An entry like
`1,1 -> 1,3`

covers points `1,1`

, `1,2`

, and `1,3`

.
- An entry like
`9,7 -> 7,7`

covers points `9,7`

, `8,7`

, and `7,7`

.

For now, *only consider horizontal and vertical lines*: lines where either `x1 = x2`

or `y1 = y2`

.

So, the horizontal and vertical lines from the above list would produce the following diagram:

```
.......1..
..1....1..
..1....1..
.......1..
.112111211
..........
..........
..........
..........
222111....
```

In this diagram, the top left corner is `0,0`

and the bottom right corner is `9,9`

. Each position is shown as *the number of lines which cover that point* or `.`

if no line covers that point. The top-left pair of `1`

s, for example, comes from `2,2 -> 2,1`

; the very bottom row is formed by the overlapping lines `0,9 -> 5,9`

and `0,9 -> 2,9`

.

To avoid the most dangerous areas, you need to determine *the number of points where at least two lines overlap*. In the above example, this is anywhere in the diagram with a `2`

or larger - a total of *5*

points.

Consider only horizontal and vertical lines. *At how many points do at least two lines overlap?*

### Part One Solution Source

```
# crystal-lang
def main(input)
# parse input
vents = [] of {ax: Int32, ay: Int32, bx: Int32, by: Int32}
input.lines.each do |line|
a, b = line.split(" -> ")
ax, ay = a.split(",")
bx, by = b.split(",")
vent = {
ax: ax.to_i32,
ay: ay.to_i32,
bx: bx.to_i32,
by: by.to_i32,
}
vents << vent
end
# walk the vents, marking positions
# x y count
grid_map = Hash(Tuple(Int32, Int32), Int32).new
vents.each do |v|
if v[:ax] == v[:bx]
x = v[:ax]
v[:ay].step(to: v[:by]).each do |y|
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
end
next
end
if v[:ay] == v[:by]
y = v[:ay]
v[:ax].step(to: v[:bx]).each do |x|
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
end
next
end
end
# count dangerous vents
dangerous_vents = 0
grid_map.each do |k, v|
dangerous_vents += 1 if v > 1
end
puts dangerous_vents
end
```

## --- Part Two ---

Unfortunately, considering only horizontal and vertical lines doesn't give you the full picture; you need to also consider *diagonal lines*.

Because of the limits of the hydrothermal vent mapping system, the lines in your list will only ever be horizontal, vertical, or a diagonal line at exactly 45 degrees. In other words:

- An entry like
`1,1 -> 3,3`

covers points `1,1`

, `2,2`

, and `3,3`

.
- An entry like
`9,7 -> 7,9`

covers points `9,7`

, `8,8`

, and `7,9`

.

Considering all lines from the above example would now produce the following diagram:

```
1.1....11.
.111...2..
..2.1.111.
...1.2.2..
.112313211
...1.2....
..1...1...
.1.....1..
1.......1.
222111....
```

You still need to determine *the number of points where at least two lines overlap*. In the above example, this is still anywhere in the diagram with a `2`

or larger - now a total of *12*

points.

Consider all of the lines. *At how many points do at least two lines overlap?*

### Part Two Solution Source

```
# crystal-lang
def main(input)
# parse input
vents = [] of {ax: Int32, ay: Int32, bx: Int32, by: Int32}
input.lines.each do |line|
a, b = line.split(" -> ")
ax, ay = a.split(",")
bx, by = b.split(",")
vent = {
ax: ax.to_i32,
ay: ay.to_i32,
bx: bx.to_i32,
by: by.to_i32,
}
vents << vent
end
# walk the vents, marking positions
# x y count
grid_map = Hash(Tuple(Int32, Int32), Int32).new
vents.each do |v|
if v[:ax] == v[:bx]
x = v[:ax]
v[:ay].step(to: v[:by]).each do |y|
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
end
next
end
if v[:ay] == v[:by]
y = v[:ay]
v[:ax].step(to: v[:bx]).each do |x|
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
end
next
end
x = v[:ax]
y = v[:ay]
if v[:ax] < v[:bx]
x_step = 1
else
x_step = -1
end
if v[:ay] < v[:by]
y_step = 1
else
y_step = -1
end
while x != (v[:bx] + x_step) && y != (v[:by] + y_step)
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
x += x_step
y += y_step
end
end
# count dangerous vents
dangerous_vents = 0
grid_map.each do |k, v|
dangerous_vents += 1 if v > 1
end
puts dangerous_vents
end
```

### Cleaned-up Part 2 Solution Source

```
# crystal-lang
def main(input)
grid_map = Hash(Tuple(Int32, Int32), Int32).new
dangerous_vents = 0
input.lines.each do |line|
a, b = line.split(" -> ")
ax, ay = a.split(",").map(&.to_i32)
bx, by = b.split(",").map(&.to_i32)
x = ax
y = ay
x_step = (ax <=> bx).sign * -1
y_step = (ay <=> by).sign * -1
while (x != (bx + x_step) || x_step == 0) && (y != (by + y_step) || y_step == 0)
new_value = (grid_map[{x, y}]? || 0) + 1
grid_map[{x, y}] = new_value
if new_value == 2
dangerous_vents += 1
end
x += x_step
y += y_step
end
end
puts dangerous_vents
end
```