-
-
Save al2o3cr/a5d0473675d666d1a6d1c5e947787742 to your computer and use it in GitHub Desktop.
2022 AOC Day 14
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Sand do | |
def read(filename) do | |
t = :ets.new(__MODULE__, [:ordered_set, :named_table]) | |
File.stream!(filename) | |
|> Stream.map(&String.trim/1) | |
|> Stream.map(&String.split(&1, " -> ")) | |
|> Stream.flat_map(&to_point_groups/1) | |
|> Stream.each(&insert_points(&1)) | |
|> Stream.run() | |
t | |
end | |
defp to_point_groups(point_strings) do | |
point_strings | |
|> Enum.map(&String.split(&1, ",")) | |
|> Enum.map(fn [x, y] -> {String.to_integer(x), String.to_integer(y)} end) | |
|> Enum.chunk_every(2, 1, :discard) | |
end | |
defp insert_points([{x_1, y}, {x_2, y}]) do | |
Enum.each(x_1..x_2, fn x -> put_rock({x, y}) end) | |
end | |
defp insert_points([{x, y_1}, {x, y_2}]) do | |
Enum.each(y_1..y_2, fn y -> put_rock({x, y}) end) | |
end | |
def move(start_pos) do | |
case next_open(start_pos) do | |
:escaped -> | |
:escaped | |
{:stopped, pos} -> | |
put_sand(pos) | |
{:stopped, pos} | |
end | |
end | |
defp put_rock(pos), do: :ets.insert(__MODULE__, {pos, :rock}) | |
defp put_sand(pos), do: :ets.insert(__MODULE__, {pos, :sand}) | |
defp next_open({x, y} = pos) do | |
case :ets.next(__MODULE__, pos) do | |
{^x, new_y} when y == new_y - 1 -> consider_left(pos) | |
{^x, new_y} -> next_open({x, new_y - 1}) | |
{_, _} -> :escaped | |
:"$end_of_table" -> :escaped | |
end | |
end | |
def consider_left({x, y} = pos) do | |
new_pos = {x-1, y+1} | |
case :ets.lookup(__MODULE__, new_pos) do | |
[{^new_pos, _}] -> consider_right(pos) | |
[] -> next_open(new_pos) | |
end | |
end | |
def consider_right({x, y} = pos) do | |
new_pos = {x+1, y+1} | |
case :ets.lookup(__MODULE__, new_pos) do | |
[{^new_pos, _}] -> {:stopped, pos} | |
[] -> next_open(new_pos) | |
end | |
end | |
end | |
Sand.read("input.txt") | |
Stream.repeatedly(fn -> Sand.move({500, 0}) end) | |
|> Stream.take_while(& &1 != :escaped) | |
|> Enum.count | |
|> IO.inspect() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Sand do | |
def read(filename) do | |
:ets.new(__MODULE__, [:ordered_set, :named_table]) | |
File.stream!(filename) | |
|> Stream.map(&String.trim/1) | |
|> Stream.map(&String.split(&1, " -> ")) | |
|> Stream.flat_map(&to_point_groups/1) | |
|> Stream.map(&insert_points(&1)) | |
|> Enum.max() | |
end | |
defp to_point_groups(point_strings) do | |
point_strings | |
|> Enum.map(&String.split(&1, ",")) | |
|> Enum.map(fn [x, y] -> {String.to_integer(x), String.to_integer(y)} end) | |
|> Enum.chunk_every(2, 1, :discard) | |
end | |
defp insert_points([{x_1, y}, {x_2, y}]) do | |
Enum.each(x_1..x_2, fn x -> put_rock({x, y}) end) | |
y | |
end | |
defp insert_points([{x, y_1}, {x, y_2}]) do | |
Enum.each(y_1..y_2, fn y -> put_rock({x, y}) end) | |
max(y_1, y_2) | |
end | |
def move(start_pos, floor) do | |
case next_open(start_pos, floor) do | |
{:stopped, ^start_pos} -> | |
:blocked | |
{:stopped, pos} -> | |
put_sand(pos) | |
{:stopped, pos} | |
end | |
end | |
defp put_rock(pos), do: :ets.insert(__MODULE__, {pos, :rock}) | |
defp put_sand(pos), do: :ets.insert(__MODULE__, {pos, :sand}) | |
defp next_open({_x, y} = pos, floor) when y == floor-1, do: {:stopped, pos} | |
defp next_open({x, y} = pos, floor) do | |
case :ets.next(__MODULE__, pos) do | |
{^x, new_y} when y == new_y - 1 -> consider_left(pos, floor) | |
{^x, new_y} -> next_open({x, new_y - 1}, floor) | |
{_, _} -> next_open({x, floor-1}, floor) | |
:"$end_of_table" -> next_open({x, floor-1}, floor) | |
end | |
end | |
def consider_left({x, y} = pos, floor) do | |
new_pos = {x-1, y+1} | |
case :ets.lookup(__MODULE__, new_pos) do | |
[{^new_pos, _}] -> consider_right(pos, floor) | |
[] -> next_open(new_pos, floor) | |
end | |
end | |
def consider_right({x, y} = pos, floor) do | |
new_pos = {x+1, y+1} | |
case :ets.lookup(__MODULE__, new_pos) do | |
[{^new_pos, _}] -> {:stopped, pos} | |
[] -> next_open(new_pos, floor) | |
end | |
end | |
end | |
floor = Sand.read("input.txt") + 2 | |
Stream.repeatedly(fn -> Sand.move({500, 0}, floor) end) | |
|> Stream.take_while(& &1 != :blocked) | |
|> Enum.count() | |
|> IO.inspect() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment