Skip to content

Instantly share code, notes, and snippets.

@al2o3cr
Created December 23, 2022 23:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save al2o3cr/a5d0473675d666d1a6d1c5e947787742 to your computer and use it in GitHub Desktop.
Save al2o3cr/a5d0473675d666d1a6d1c5e947787742 to your computer and use it in GitHub Desktop.
2022 AOC Day 14
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()
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