Skip to content

Instantly share code, notes, and snippets.

@sasa1977
Last active December 14, 2017 09:26
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 sasa1977/39a44ebb6078397a1c5e9b653fc4e0ef to your computer and use it in GitHub Desktop.
Save sasa1977/39a44ebb6078397a1c5e9b653fc4e0ef to your computer and use it in GitHub Desktop.
defmodule Day14 do
def part1(input), do:
input |> grid_points(128) |> Enum.count()
def part2(input), do:
input |> groups(128) |> Enum.count()
defp groups(input, size), do:
input |> new_groupper(size) |> Stream.unfold(&pop_group/1)
defp new_groupper(input, size) do
unresolved = input |> grid_points(size) |> Enum.to_list()
%{unresolved: unresolved, points: MapSet.new(unresolved)}
end
defp pop_group(%{unresolved: []}), do:
nil
defp pop_group(%{unresolved: [point | rest]} = groupper) do
groupper = %{groupper | unresolved: rest}
if MapSet.member?(groupper.points, point) do
{group, remaining_points} = connected_points(groupper.points, point)
{group, %{groupper | points: remaining_points}}
else
pop_group(groupper)
end
end
defp connected_points(points, point) do
[{-1, 0}, {1, 0}, {0, -1}, {0, 1}]
|> Stream.map(fn {x, y} -> %{row: point.row + x, col: point.col + y} end)
|> Stream.filter(&MapSet.member?(points, &1))
|> Enum.reduce(
{[point], MapSet.delete(points, point)},
fn neighbour, {collected, remaining} ->
{new, remaining} = connected_points(remaining, neighbour)
{Stream.concat(new, collected), remaining}
end
)
end
defp grid_points(input, size), do:
Stream.flat_map(0..(size - 1), &row_points(input, size, &1))
defp row_points(input, size, row), do:
"#{input}-#{row}"
|> knot_hash()
|> Stream.take(div(size, 8))
|> Stream.flat_map(&binary_digits/1)
|> Stream.with_index()
|> Stream.reject(&match?({0, _col}, &1))
|> Stream.map(fn {_value, col} -> %{row: row, col: col} end)
defp binary_digits(num) do
for << digit::1 <- <<num::8>> >>, do: digit
end
defp knot_hash(input), do:
input |> lengths() |> sparse_hash() |> dense_hash()
defp lengths(input), do:
input |> to_charlist() |> Enum.concat([17, 31, 73, 47, 23])
defp sparse_hash(lengths), do:
Enum.reduce(1..64, initial_state(), fn _step, state -> round(state, lengths) end).elements
defp dense_hash(elements), do:
elements
|> Stream.chunk_every(16)
|> Stream.map(fn chunk -> Enum.reduce(chunk, 0, &:erlang.bxor/2) end)
defp round(state, lengths), do:
Enum.reduce(lengths, state, &step(&2, &1))
defp initial_state(), do:
%{elements: 0..255, size: 256, skip_size: 0, pos: 0}
defp step(state, length) do
%{state |
elements: state.elements |> shift(state.pos) |> reverse(length) |> shift(state.size - state.pos),
skip_size: state.skip_size + 1,
pos: rem(state.pos + state.skip_size + length, state.size)
}
end
defp reverse(elements, count) do
{to_reverse, rest} = Enum.split(elements, count)
Enum.reverse(to_reverse) ++ rest
end
defp shift(elements, offset) do
{tail, front} = Enum.split(elements, offset)
front ++ tail
end
end
System.argv() |> hd() |> Day14.part1() |> IO.inspect
System.argv() |> hd() |> Day14.part2() |> IO.inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment