Skip to content

Instantly share code, notes, and snippets.

@sasa1977
Created December 22, 2017 09:38
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/ebab73b47596ab33a517d856c20f3d70 to your computer and use it in GitHub Desktop.
Save sasa1977/ebab73b47596ab33a517d856c20f3d70 to your computer and use it in GitHub Desktop.
defmodule Day22 do
def part1(), do:
count_infected(10_000, [:clean, :infected])
def part2(), do:
count_infected(10_000_000, [:clean, :weakened, :infected, :flagged])
defp count_infected(num_moves, state_transitions), do:
state_transitions |> new_virus() |> count_infected(num_moves, 0)
defp new_virus(state_transitions), do:
%{map: map(), pos: {0, 0}, facing: :up, state_transitions: state_transitions(state_transitions)}
defp state_transitions(state_transitions), do:
state_transitions
|> Stream.cycle()
|> Stream.chunk_every(2, 1)
|> Stream.map(&List.to_tuple/1)
|> Stream.take(Enum.count(state_transitions))
|> Map.new()
defp count_infected(_virus, 0, infected), do: infected
defp count_infected(virus, num_moves, infected) do
{node_state, virus} = virus |> turn() |> change_node_state()
infected = if node_state == :infected, do: infected + 1, else: infected
virus |> step() |> count_infected(num_moves - 1, infected)
end
defp turn(virus), do: %{virus | facing: turn(virus.facing, virus |> node_state() |> next_direction())}
defp next_direction(:clean), do: :left
defp next_direction(:weakened), do: :same
defp next_direction(:infected), do: :right
defp next_direction(:flagged), do: :opposite
defp change_node_state(virus) do
node_state = Map.fetch!(virus.state_transitions, node_state(virus))
{node_state, node_state(virus, node_state)}
end
defp node_state(virus), do: Map.get(virus.map, virus.pos, :clean)
defp node_state(virus, :clean), do: %{virus | map: Map.delete(virus.map, virus.pos)}
defp node_state(virus, state), do: %{virus | map: Map.put(virus.map, virus.pos, state)}
defp step(virus), do: %{virus | pos: add_vector(virus.pos, vector(virus.facing))}
defp add_vector({row1, col1}, {row2, col2}), do: {row1 + row2, col1 + col2}
for {orientation, {vector, left, right, opposite}} <- [
left: {{0, -1}, :down, :up, :right},
right: {{0, 1}, :up, :down, :left},
up: {{1, 0}, :left, :right, :down},
down: {{-1, 0}, :right, :left, :up},
] do
defp vector(unquote(orientation)), do: unquote(vector)
defp turn(unquote(orientation), :left), do: unquote(left)
defp turn(unquote(orientation), :right), do: unquote(right)
defp turn(unquote(orientation), :opposite), do: unquote(opposite)
end
defp turn(orientation, :same), do: orientation
def map(), do:
"input.txt"
|> File.stream!()
|> Stream.map(&String.trim/1)
|> Stream.transform(nil, &nodes/2)
|> Stream.filter(&match?({_pos, "#"}, &1))
|> Stream.map(fn {pos, "#"} -> {pos, :infected} end)
|> Map.new()
defp nodes(line, row) do
nodes = String.codepoints(line)
size = length(nodes)
start = div(size - 1, 2)
row = row || start
col = -start
nodes = nodes |> Stream.with_index() |> Stream.map(fn {node, offset} -> {{row, col + offset}, node} end)
{nodes, row - 1}
end
end
Day22.part1() |> IO.inspect
Day22.part2() |> IO.inspect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment