Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Aoc 2019 - day 12

2019/elixir/day-12.livemd

Aoc 2019 - day 12

Section

Mix.install([
  {:nimble_parsec, "~> 1.2"}
])

Setup

input = """




"""

input1 = """




"""

input2 = """




"""
defmodule PosParser do
  import NimbleParsec

  num =
    choice([
      integer(min: 1),
      ignore(string("-")) |> integer(min: 1) |> map({Kernel, :*, [-1]})
    ])

  coord = optional(string(", ")) |> ascii_char([?x, ?y, ?z]) |> ignore(string("="))

  planet =
    ignore(string("<"))
    |> times(ignore(coord) |> concat(num), 3)
    |> ignore(string(">"))
    |> optional(ignore(string("\n")))

  defparsec(:parse, planet |> wrap() |> times(4), debug: true)
end
{:ok, res, _, _, _, _} = PosParser.parse(input)
init_data = res
[apos, bpos, cpos, dpos] = res

[apos, bpos, cpos, dpos]
|> Enum.zip_with(fn [a, b, c, d] ->
  [a, b, c, d]
end)

Part 1

gravity_fn = fn list, p ->
  list
  |> Enum.reduce(0, fn
    ^p, g -> g
    x, g when x > p -> g + 1
    _, g -> g - 1
  end)
end

sum = fn [ps, vs] ->
  [ps, vs]
  |> Enum.map(fn s ->
    Enum.map(s, &amp;abs/1)
    |> Enum.sum()
  end)
  |> Enum.product()
end

init_data
|> Enum.map(fn pos -> [pos, [0, 0, 0]] end)
|> Stream.iterate(fn
  [
    [apos, avs],
    [bpos, bvs],
    [cpos, cvs],
    [dpos, dvs]
  ] ->
    all_pos = List.flatten([apos, bpos, cpos, dpos])
    all_vs = List.flatten([avs, bvs, cvs, dvs])

    list
    |> Enum.map(Enum.reduce(list, &amp;1))

    [apos, bpos, cpos, dpos]
    |> Enum.zip_with(&amp;Function.identity/1)
    # [xlist, ylist, zlist]
    |> Stream.cycle()
    # [ax, ay, az, bx, by, bz, cx, ..., dz]
    |> Stream.zip(all_pos)
    |> Stream.map(fn {xlist, ax} -> {ax, gravity_fn.(xlist, ax)} end)
    |> Stream.zip_with(all_vs, fn {p, vg}, v -> {p + vg + v, vg + v} end)
    |> Stream.chunk_every(3)
    |> Enum.map(&amp;(Enum.unzip(&amp;1) |> Tuple.to_list()))
end)
|> Enum.take(1001)
|> List.last()
|> Enum.map(&amp;sum.(&amp;1))
|> Enum.sum()

Part 2

defmodule Part2 do
  def run(init_data) do
    init_data
    |> Enum.zip_with(&amp;Function.identity/1)
    |> Enum.map(fn axis ->
      Stream.iterate(0, &amp;(&amp;1 + 1))
      |> Enum.reduce_while({axis, [0, 0, 0, 0]}, fn
        c, {^axis, [0, 0, 0, 0]} when c > 0 ->
          {:halt, c}

        _c, {axis, vels} ->
          vels =
            axis
            |> Enum.map(&amp;gravity(axis, &amp;1))
            |> Enum.zip_with(vels, fn g, v -> g + v end)

          axis = Enum.zip_with(axis, vels, fn p, v -> p + v end)
          {:cont, {axis, vels}}
      end)
    end)
    # |> Enum.map(fn {:ok, result} -> result end)
    |> Enum.reduce(fn a, b -> div(a * b, Integer.gcd(a, b)) end)
  end

  def gravity(list, p) do
    list
    |> Enum.reduce(0, fn
      ^p, g -> g
      x, g when x > p -> g + 1
      _, g -> g - 1
    end)
  end
end

Part2.run(init_data)