1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
require "matrix"

# part one
plan = ARGF.read.scan(/([UDLR])\s+(\d+)\s+\(#(\w+)\)/)
  .map { [_1.to_sym, _2.to_i, _3] }

# part two
plan = plan.map { _3.chars }.map {|hex|
  dist = hex[0..4].join.to_i(16)
  dir = "RDLU".chars.fetch(hex.last.to_i).to_sym
  [dir, dist]
}

deltas = { U: [-1,0], D: [1,0], L: [0,-1], R: [0,1] }

points = plan.inject([[0,0]]) {|points, (dir, dist, _)|
  delta = deltas.fetch(dir).map { _1*dist }
  next_point = points.last.zip(delta).map { _1 + _2 }
  points << next_point
}

p [
  (0.5 * points.each_cons(2).sum { Matrix.columns(_1).determinant }.abs).to_i,
  plan.select {|dir,_,_| %i[ D L ].include?(dir) }.sum { _2 },
  1,
].sum

# trench = plan.inject([[0,0]]) {|trench, (dir, dist, _)|
#   delta = deltas.fetch(dir)
#   dist.times do
#     trench << trench.last.zip(delta).map { _1 + _2 }
#   end
#   trench
# }.uniq

# y_range = Range.new(*trench.map(&:first).minmax)
# x_range = Range.new(*trench.map(&:last).minmax)

# y_range.each do |y|
#   x_range.each do |x|
#     print trench.include?([y,x]) ? ?# : ?.
#   end
#   puts
# end

# part one
# lagoon = trench.to_set

# seed = [1, x_range.find {|x| lagoon.include?([0,x]) } + 1]
# frontier = [seed]
# until frontier.empty?
#   current = frontier.shift
#   lagoon << current

#   frontier.concat(
#     [[-1,0],[1,0],[0,-1],[0,1]].map {|delta|
#       current.zip(delta).map { _1 + _2 }
#     }.reject { lagoon.include?(_1) || frontier.include?(_1) }
#   )
# end

# p lagoon.size

# row_counts = {}

# count = trench.size
# y_range.each do |y|
#   inside = nil

#   segments = trench.select {|y_,_| y_ == y }.map(&:last).sort.slice_when { _1+1 != _2 }
#   if row_count = row_counts[segments]
#     count += row_count
#     next
#   end

#   row_count = 0
#   segments.each do |segment|
#     if [-1,1].all? {|dy| [[y+dy,segment[0]],[y+dy,segment[-1]]].any? { trench.include?(_1) }}
#       if inside
#         row_count += segment[0] - inside
#         inside = nil
#       else
#         inside = segment[-1] + 1
#       end
#     elsif inside
#       row_count += segment[0] - inside
#       inside = segment[-1] + 1
#     end
#   end
#   row_counts[segments] = row_count
#   count += row_count
# end
# p count