Skip to content

Commit

Permalink
DAY 12 PUZZLE 12
Browse files Browse the repository at this point in the history
Key was calculating corners instead of edges.
  • Loading branch information
ariejan committed Dec 12, 2024
1 parent 9d76f96 commit f3bbec3
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 42 deletions.
143 changes: 102 additions & 41 deletions lib/solutions/day_12.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ def part_two(input)
@cols = @map[0].length
@visited = Array.new(@rows) { Array.new(@cols, false) }

@grid = Grid.new(@map)

price_perimeter, price_sides = @grid.calculate_price_area_perimeter

puts "Price perimeter: #{price_perimeter}"
puts "Price sides: #{price_sides}"

price_sides
end
end

class Day12Part1
def part_one(input)
@map = input.split("\n")
@rows = @map.length
@cols = @map[0].length
@visited = Array.new(@rows) { Array.new(@cols, false) }

total_price
end

Expand Down Expand Up @@ -71,65 +89,108 @@ def out_of_bounds?(row, col)
end
end

class Day12Part1
def part_one(input)
@map = input.split("\n")
@rows = @map.length
@cols = @map[0].length
@visited = Array.new(@rows) { Array.new(@cols, false) }
class Grid
attr_reader :width, :height

total_price
end
def initialize(grid)
@grid = grid
@height = @grid.size
@width = @grid[0].size
@visited = Array.new(@height) { Array.new(@width, false) }

def total_price
regions = find_regions
regions.sum { |region| region[:area] * region[:perimeter] }
# directions: up, down, left, right
@directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]
end

def find_regions
regions = []
(0...@rows).each do |row|
(0...@cols).each do |col|
next if @visited[row][col]

char = @map[row][col]
area, perimeter = explore_region(row, col, char)
regions << { area: area, perimeter: perimeter }
end
end
regions
def on_map?(x, y)
# check if x, y coord exist
x.between?(0, @height - 1) && y.between?(0, @width - 1)
end

def explore_region(row, col, char)
queue = [[row, col]]
def find_plot_BFS(start_x, start_y)
plant_type = @grid[start_x][start_y]
queue = [[start_x, start_y]]
@visited[start_x][start_y] = true

area = 0
perimeter = 0
cells = Set.new([[start_x, start_y]])

until queue.empty?
current_row, current_col = queue.shift
next if out_of_bounds?(current_row, current_col) || @visited[current_row][current_col]

next unless @map[current_row][current_col] == char

@visited[current_row][current_col] = true
x, y = queue.shift
area += 1

# Check all four directions
[[0, 1], [1, 0], [0, -1], [-1, 0]].each do |dr, dc|
new_row = current_row + dr
new_col = current_col + dc
if out_of_bounds?(new_row, new_col) || @map[new_row][new_col] != char
perimeter += 1
@directions.each do |dx, dy|
nx = x + dx
ny = y + dy

if on_map?(nx, ny)
if @grid[nx][ny] == plant_type && !@visited[nx][ny]
@visited[nx][ny] = true
queue << [nx, ny]
cells.add([nx, ny])
elsif @grid[nx][ny] != plant_type
perimeter += 1
end
else
queue << [new_row, new_col] unless @visited[new_row][new_col]
# Out of bounds contributes to perimeter
perimeter += 1
end
end
end

[area, perimeter]
# Calculate the number of sides (== corners) for the plot
sides = calculate_corners(cells)
[area, perimeter, sides]
end

def out_of_bounds?(row, col)
row < 0 || row >= @rows || col < 0 || col >= @cols
def calculate_corners(cells)
corners = 0

cells.each do |cell|
x, y = cell
u = [x - 1, y] # Up
d = [x + 1, y] # Down
r = [x, y + 1] # Right
l = [x, y - 1] # Left

# External corners
corners += 1 if !cells.include?(u) && !cells.include?(r)
corners += 1 if !cells.include?(r) && !cells.include?(d)
corners += 1 if !cells.include?(d) && !cells.include?(l)
corners += 1 if !cells.include?(l) && !cells.include?(u)

# Internal (diagonal) corners
ur = [x - 1, y + 1] # Up-Right
ul = [x - 1, y - 1] # Up-Left
dr = [x + 1, y + 1] # Down-Right
dl = [x + 1, y - 1] # Down-Left

corners += 1 if cells.include?(u) && cells.include?(r) && !cells.include?(ur)
corners += 1 if cells.include?(r) && cells.include?(d) && !cells.include?(dr)
corners += 1 if cells.include?(d) && cells.include?(l) && !cells.include?(dl)
corners += 1 if cells.include?(l) && cells.include?(u) && !cells.include?(ul)
end

corners
end

def calculate_price_area_perimeter
total_price_perimeter = 0
total_price_sides = 0
@visited = Array.new(@height) { Array.new(@width, false) }

@height.times do |x|
@width.times do |y|
next if @visited[x][y]

area, perimeter, sides = find_plot_BFS(x, y)
total_price_perimeter += area * perimeter
total_price_sides += area * sides
end
end

[total_price_perimeter, total_price_sides]
end
end

2 changes: 1 addition & 1 deletion spec/solutions/day_12_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
end

describe '#part_two' do
xit 'calculates the correct solutions for part two' do
it 'calculates the correct solutions for part two' do
expect(subject.part_two(input)).to eq(1206)
end
end
Expand Down

0 comments on commit f3bbec3

Please sign in to comment.