lud
At first I was scared but I found is a simple way to compute the sides.
defmodule AdventOfCode.Solutions.Y24.Day12 do
alias AdventOfCode.Grid
alias AoC.Input
def parse(input, _part) do
input |> Input.stream!() |> Grid.parse_lines(fn c -> {:ok, <<c>>} end) |> elem(0)
end
def part_one(full_grid) do
regions = compute_regions(full_grid)
regions
|> Enum.map(&cost_p1/1)
|> Enum.sum()
end
def part_two(full_grid) do
regions = compute_regions(full_grid)
regions
|> Enum.map(&cost_p2/1)
|> Enum.sum()
end
defp compute_regions(grid) do
{regions, rest} =
Enum.reduce(grid, {[], grid}, fn {pos, tag}, {regions, rest_grid} ->
case Map.fetch(rest_grid, pos) do
:error ->
{regions, rest_grid}
{:ok, _} ->
{region, rest_grid} = take_region(rest_grid, tag, [pos])
{[region | regions], rest_grid}
end
end)
0 = map_size(rest)
regions
end
defp take_region(mut_grid, tag, open, closed \\ [])
defp take_region(mut_grid, tag, [pos | open], closed) do
neighs = pos |> Grid.cardinal4() |> Enum.filter(fn xy -> xy not in closed && Map.get(mut_grid, xy) == tag end)
take_region(mut_grid, tag, neighs ++ open, [pos | closed])
end
defp take_region(mut_grid, tag, [], closed) do
region = Map.new(closed, &{&1, tag})
mut_grid = Map.drop(mut_grid, closed)
{region, mut_grid}
end
defp cost_p1(region) do
area(region) * perimeter(region)
end
defp area(region) do
map_size(region)
end
defp perimeter(region) do
keys = Map.keys(region)
Enum.reduce(region, 0, fn {xy, _}, acc ->
borders = xy |> Grid.cardinal4() |> Enum.count(fn neigh -> neigh not in keys end)
acc + borders
end)
end
defp cost_p2(region) do
area(region) * count_sides(region)
end
defp count_sides(region) do
poses = Map.keys(region)
individual_sides =
Enum.flat_map(poses, fn pos ->
[
{:up, Grid.translate(pos, :n)},
{:down, Grid.translate(pos, :s)},
{:left, Grid.translate(pos, :w)},
{:right, Grid.translate(pos, :e)}
]
|> Enum.filter(fn {_, xy} -> xy not in poses end)
end)
sides_by_direction =
Enum.group_by(
individual_sides,
fn
# group sides by their orientation and level
{:up, {_x, y}} -> {:up, y}
{:down, {_x, y}} -> {:down, y}
{:right, {x, _y}} -> {:right, x}
{:left, {x, _y}} -> {:left, x}
end,
fn
# keep side value by orientation and cross direction to know if their
# are touching
{:up, {x, _y}} -> x
{:down, {x, _y}} -> x
{:right, {_x, y}} -> y
{:left, {_x, y}} -> y
end
)
Enum.reduce(sides_by_direction, 0, fn {{_direction, _level}, cross_coords}, acc ->
distinct_sides(cross_coords) + acc
end)
end
defp distinct_sides(cross_coords) do
[h | cross_coords] = Enum.sort(cross_coords)
distinct_sides(cross_coords, h, 0)
end
defp distinct_sides([h | t], prev, acc) when h == prev + 1 do
# No need to accumulate the whole side cross coordinates, we can just keep
# the previous nuber
distinct_sides(t, h, acc)
end
defp distinct_sides([h | t], _prev, acc) do
distinct_sides(t, h, acc + 1)
end
defp distinct_sides([], _prev, acc) do
acc + 1
end
end
BEAM capability of guards like when h == prev + 1 is really neat.
Trending in Challenges
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
Aetherus
For part 2, I expanded every border tile to 1~4 entries depending on which sides the fence is on, like
{{i, j}, :up}and{{i, j}, :left}, and thenHere’s my solution:
https://github.com/Aetherus/advent-of-code/blob/d30deadc820fb0b94e9ce09e86d7353895953bf6/2024/day-12.livemd
sevenseacat
This was a fun one! Took a bit of thinking outside the box (or maybe I didn’t need to think outside the box, I haven’t looked at anyone else’s solutions yet, I’ll do that now!)
The core of mine is the
group_connectingfunction, which takes a list of coordinates and groups them together if they’re adjacent. This is how I figure out where all the regions are, and also how I split up all the borders into sides.https://github.com/sevenseacat/advent_of_code/blob/main/lib/y2024/day12.ex
adamu
I said I was going to take a break today, but I’m too addicted…
For part 1, I computed the perimeter at the same time as finding the regions, which meant part 2 was a massive troll because I had to go back and walk around the edges to find the sides anyway.
For part 2, I’m not happy with the duplication for the four directions (like day 4), but I’ve spent long enough on this.
The times are 24.371ms for part 1, and 46.861ms for part 2.
https://git.adamu.jp/adam/AdventOfCode/src/branch/main/2024/day12.exs
I am going to take a break for a few days from tomorrow, not sure if I’ll be back so just in case it’s been fun seeing everyone’s approaches so far!
liamcmitchell
I appreciate the solutions others post, it’s helped me learn a lot
I used a recursive function to build a set of region positions, then iterated over individual fences, building up a map of
%{fenceStart => fenceEnd, fenceEnd => fenceStart}.Pattern matching on maps is really clean.
https://github.com/liamcmitchell/advent-of-code/blob/3145e87a67328dfed30606d963c8a62fb2fea7f9/2024/12/1.exs#L66-L92
rvnash
My solution solves parts 1 and 2 simultaneously. For part 2 I just count the number of corners, both inside and outside. That’s equivalent to the number of sides.
https://github.com/rvnash/aoc2024/blob/main/lib/d12.ex
adamu
lud
yeah … I feel dumb now
jarlah
this task is starting to annoy me. Its simple to get wall count .. it was not so simple to get side count
https://github.com/jarlah/advent_of_code/blob/master/lib/2024/day_12/Part1.ex#L15
anyone who can kick me in the right direction ? i tried to keep the code readable in the domain of the problem. I think ill read the comments here … its time ..
jarlah
haha .. no idea what your doing .. the variable names and functions doesnt speak to me
When i do AOC I make code with as good as quality i would do at work, so i will remember after 1 year what the code does …
But terse can also be good
good work
rvnash
I verbosified it if you’re still interested.