1
0
Fork 0
advent-of-code-2024/12/main.rb

120 lines
2.8 KiB
Ruby
Raw Permalink Normal View History

2024-12-13 00:47:02 -05:00
#!/usr/bin/env ruby
require "debug"
@input = (ARGV.first.nil? ? DATA : ARGF)
.readlines(chomp: true)
.map(&:chars)
@shapes = Hash.new { |h, k| h[k] = [] }
@area_counted = Hash.new
@perimeter_counted = Hash.new
def not_bounded?(point)
point.first < 0 ||
point.last < 0 ||
point.first >= @input.size ||
point.last >= @input.first.size
end
def counted?(point)
@area_counted[point]
end
def calculate_area(point, char, parent)
return 0 if counted?(point)
return 0 if not_bounded?(point)
return 0 if @input[point.first][point.last] != char
@shapes[[char, parent]] << point
@area_counted[point] = true
[
[point.first - 1, point.last],
[point.first + 1, point.last],
[point.first, point.last - 1],
[point.first, point.last + 1]
]
.map { calculate_area(_1, char, parent) }.sum + 1
end
def calculate_perimeter(point, char)
return 1 if @perimeter_counted[point] && @input.dig(*point) != char
return 0 if @perimeter_counted[point]
return 1 if not_bounded?(point)
return 1 if @input.dig(*point) != char
@perimeter_counted[point] = true
[
[point.first - 1, point.last],
[point.first + 1, point.last],
[point.first, point.last - 1],
[point.first, point.last + 1]
].map { calculate_perimeter(_1, char) }.sum
end
(0...@input.size).each do |x|
(0...@input.first.size).each do |y|
next if counted?([x, y])
char = @input.dig(x, y)
calculate_area([x, y], char, [x,y])
end
end
perimeters = Hash.new { |h, k| h[k] = [] }
(0...@input.size).each do |x|
(0...@input.first.size).each do |y|
next if @perimeter_counted[[x, y]]
char = @input.dig(x, y)
perimeters[[char, [x,y]]] = calculate_perimeter([x, y], char)
end
end
def sides(members)
char = @input.dig(*members.first)
min_x, max_x = members.map(&:first).min, members.map(&:first).max
min_y, max_y = members.map(&:last).min, members.map(&:last).max
sides = 0
(min_x..max_x).each do |x|
top_side = false
bot_side = false
(min_y..max_y).each do |y|
if top_side == false && members.include?([x,y]) && (x - 1 < 0 || !members.include?([x-1,y]))
top_side = true
sides += 1
elsif top_side == true && !members.include?([x,y])
top_side = false
elsif top_side == true && members.include?([x - 1, y])
top_side = false
end
if bot_side == false && members.include?([x,y]) && (x + 1 >= @input.size || !members.include?([x+1,y]))
bot_side = true
sides += 1
elsif bot_side == true && !members.include?([x,y])
bot_side = false
elsif bot_side == true && members.include?([x + 1, y])
bot_side = false
end
y += 1
end
end
sides * 2
end
p @shapes.keys.map { @shapes[_1].size * perimeters[_1] }.sum
p @shapes.map { |(key, members)| @shapes[key].size * sides(members) }.sum
__END__
AAAAAA
AAABBA
AAABBA
ABBAAA
ABBAAA
AAAAAA