Advent of Code 2024 - Day 8

Hello, Erlang enthusiasts! :wave: Ukrainian Erlanger is here! :metal: Today’s challenge, Day 8, brings us to a secret Easter Bunny installation where we must decipher the impact of their mysterious antenna signals. :rabbit::satellite:

The task: Identify unique antinode locations on a map based on the resonant frequencies of antennas. The mechanics are fascinating, and it’s an excellent opportunity to showcase the power of Erlang in handling spatial and frequency-based logic.

:bulb: Tips for tackling Day 8:

  • Parse the input carefully to map the antenna frequencies and positions.
  • Think about how to calculate distances and identify resonant collinearity.
  • Use maps or sets to ensure you count each antinode only once.

:sparkles: Motivation for today:
Every new challenge is a chance to flex your problem-solving muscles. Let’s decode, learn, and BEAM together!

Share your solutions, thoughts, or any hurdles you’re facing below. Whether you’re mapping antinodes or just decoding the input, this is your space to collaborate and learn.

Happy coding, and may your recursion always resonate! :christmas_tree::computer:

Here’s mine. Once again, I decided not to produce a list matrix and instead operate on indices, using simple arithmetic to get columns and rows when needed.
Finally got to use some new functions from standard libs. That was a really fun problem to solve.

-module(day_08).

-export([main/1]).

main(File) ->
	{ok, Input} = file:read_file(File),
	{Data, Cols, Len} = process_input(Input),
	Rows = Len div Cols,
	Antennas = maps:groups_from_list(fun({Frequency, _}) -> Frequency end, fun({_, Index}) -> Index end, Data),
	Pairs = maps:fold(fun(_, Value, Acc) -> Acc ++ combinations(Value) end, [], Antennas),
	PairedAntennas = maps:fold(fun(_, Value, Acc) when length(Value) > 1 -> Acc ++ Value end, [], Antennas),
	
	Solution1 = length(lists:uniq(get_antinodes(Pairs, {Cols, Rows}, 1))),
	Solution2 = length(lists:uniq(get_antinodes(Pairs, {Cols, Rows}, -1) ++ PairedAntennas)), 
	{
		Solution1,
		Solution2
	}.

process_input(Input) ->
	process_input(Input, 0, [], -1).
process_input(<<>>, Index, Output, LineLen) -> 
	{Output, LineLen, Index};
process_input(<<H,T/binary>>, Index, Output, LineLen) ->
	case H of 
		$\n ->
			Len = case LineLen of -1 -> Index; _ -> LineLen end,
			process_input(T, Index, Output, Len);
		$. ->
			process_input(T, Index+1, Output, LineLen);
		_ ->
			process_input(T, Index+1, [{H, Index}|Output], LineLen)
	end.

combinations([]) -> [];
combinations([H|T]) -> [{X, H} || X <- T] ++ combinations(T).

get_antinodes(Pairs, Grid, Steps) ->
	get_antinodes(Pairs, Grid, Steps, []).
get_antinodes([], _, _, Antinodes) ->
	Antinodes;
get_antinodes([{X, Y} | T], {_, Cols} = Grid, Steps, Antinodes) ->
	XCol = X rem Cols,
	XRow = X div Cols,
	YCol = Y rem Cols,
	YRow = Y div Cols,

	ColDelta = YCol - XCol,
	RowDelta = YRow - XRow,

	get_antinodes(
		T, 
		Grid,
		Steps,
		Antinodes ++ extrapolate_antinodes(Grid, {XRow, XCol}, {RowDelta, ColDelta}, Steps) ++ extrapolate_antinodes(Grid, {YRow, YCol}, {-RowDelta, -ColDelta}, Steps)
	).

extrapolate_antinodes(Grid, Pos, Delta, Iters) ->
	extrapolate_antinodes(Grid, Pos, Delta, Iters, []).
extrapolate_antinodes(_, _, _, 0, Antinodes) -> 
	Antinodes;
extrapolate_antinodes({_, Cols} = Grid, {Row, Col}, {RowDelta, ColDelta} = Delta, Iters, Antinodes) -> 
	Pos = {Row - RowDelta, Col - ColDelta},
	case in_bounds(Grid, Pos) of
		true -> extrapolate_antinodes(Grid, Pos, Delta, Iters - 1, [to_index(Cols, Pos) | Antinodes]);
		false -> Antinodes
	end.

in_bounds({Rows, Cols}, {Row, Col}) ->
	(Row >= 0) andalso (Row < Rows) andalso (Col >= 0) andalso (Col < Cols).

to_index(Cols, {Row, Col}) -> Row * Cols + Col.

1 Like

I agree with @metsawyr, today was really fun. Here is my solution: advent_of_code_2024/src/solution_day_8_2024.erl at main · chiroptical/advent_of_code_2024 · GitHub

Conceptually, I really enjoyed part 2. Took me a minute to realize the antennas were also nodes. It says it in the problem but I missed that.

1 Like

Nice, your solution made me realize my pairs function was wrong.

Good approach! Operating directly on indices keeps the solution lean and efficient, and it’s great to see how you’ve utilized functions from the standard library. The way you handled antinodes with extrapolation is really clean - good work tackling this challenge! :rocket::christmas_tree:

Great solution! I love how you approached part 2, especially the clean handling of antennas as both nodes and contributors to antinodes. The use of vectors and maps makes the logic very clear and efficient. Great job, and thanks for sharing the link - it’s always inspiring to see detailed and well-thought-out implementations! :rocket::christmas_tree: