kwando

kwando

Advent of Code 2022 - Day 9

Took a while, but another use case for “move vectors” today and pattern matching. :slight_smile:

The trick was to first generate a list of position for the head with the help of the instructions.
Then you you use that list to move the tail, and repeat that process for as many knots there are… a perfect job for Enum.scan :slight_smile:

Quite happy with this solution.

Most Liked

milli

milli

I forgot to mention I was refactoring mainly for beauty :wink: It looks like we’ll get to enjoy enough of 10k optimizing in Day 11, though :smile:

Arzar

Arzar

It was really fun coding this ̶s̶n̶a̶k̶e̶ rope-thing simulator (code below is part 2)

defmodule Day9 do

  def move_head({x, y}, "L"), do: {x - 1, y}
  def move_head({x, y}, "R"), do: {x + 1, y}
  def move_head({x, y}, "U"), do: {x, y + 1}
  def move_head({x, y}, "D"), do: {x, y - 1}

  def move_toward(prev, current) do
    if prev - current > 0, do: current + 1, else: current - 1
  end

  def move_knot({x_prev, y_prev}, {x, y}) do
    cond do
      abs(x_prev - x) <= 1 and abs(y_prev - y) <= 1 -> {x, y}  # adjacent
      x == x_prev -> {x, move_toward(y_prev, y)}               # same line
      y == y_prev -> {move_toward(x_prev, x), y}               # same column
      true -> {move_toward(x_prev, x), move_toward(y_prev, y)} # not touching
    end
  end

  def start() do

    moves = File.stream!("input09")
    |> Stream.map(&String.trim/1)
    |> Enum.map(&String.split/1)
    |> Enum.flat_map(fn [dir, step] -> for _ <-1..String.to_integer(step), do: dir end)

    knots = for _ <- 1..9, do: {0, 0}

    {_, _, tail_history} = Enum.reduce(moves , {{0, 0}, knots, []}, fn dir, {head, knots, tail_history} ->
      head = move_head(head, dir)
      {knots, tail} = Enum.map_reduce(knots, head, fn knot, prev_knot ->
        knot = move_knot(prev_knot, knot)
        {knot, knot}
      end)

      {head, knots, [tail | tail_history]}
    end)

    tail_history |> Enum.uniq |> Enum.count
  end
end
milli

milli

After a lot of refactoring I’m solving both parts using the same function and I’m happy with my code :slight_smile:

  defp move([dir | rest], [head | knots], tail_path) do
    new_head = move_head(dir, head)
    new_rope = Enum.scan([new_head | knots], fn tail, head -> follow(head, tail) end)
    move(rest, new_rope, MapSet.put(tail_path, Enum.at(new_rope, -1)))
  end

Full solution on GitHub

adamu

adamu

You’re not supposed to share the problem text or input according to the AoC ToS. Although that’s probably a lost cause by now :see_no_evil:

Enjoyed this one. Part 2 took me by surprise, but it was fun. I managed to reuse the functions from part 1, just updated motion function to keep track of the intermediary knots in a list, with map_reduce to simultaneously enumerate the knots + track the previous one.

  defp step_head({x, y}, "R"), do: {x + 1, y}
  defp step_head({x, y}, "L"), do: {x - 1, y}
  defp step_head({x, y}, "U"), do: {x, y + 1}
  defp step_head({x, y}, "D"), do: {x, y - 1}

  defp step_tail({hx, hy}, {tx, ty}) when abs(hx - tx) <= 1 and abs(hy - ty) <= 1, do: {tx, ty}
  defp step_tail({tx, hy}, {tx, ty}) when hy - ty > 0, do: {tx, ty + 1}
  defp step_tail({tx, hy}, {tx, ty}) when hy - ty < 0, do: {tx, ty - 1}
  defp step_tail({hx, ty}, {tx, ty}) when hx - tx > 0, do: {tx + 1, ty}
  defp step_tail({hx, ty}, {tx, ty}) when hx - tx < 0, do: {tx - 1, ty}
  defp step_tail({hx, hy}, {tx, ty}) do
    dx = if hx - tx > 0, do: 1, else: -1
    dy = if hy - ty > 0, do: 1, else: -1
    {tx + dx, ty + dy}
  end

kwando

kwando

Oh, didnt know that. Gonna stop adding that to my livebooks :slight_smile: thanks for the heads up!

Where Next?

Popular in Challenges Top

antoine-duchenet
Everything went smoothly today. Nothing to change to solve part 2 because I already used memoization for part 1 (it looked like an AoC e...
New
kwando
Phew, this one took a while to get right. My naive attempts was way to slow so I reached for Dijkstras shortest path algorithm… and that ...
New
igorb
I found today a bit tedious: advent-of-code-2024/lib/advent_of_code2024/day15.ex at main · ibarakaiev/advent-of-code-2024 · GitHub.
New
sukhmeetsd
All in all, from what I understand, it is better not to use GenServer.cast when we want some concurrent operations to happen for sure, be...
New
groovyda
Today’s challenge for me was about using reduce: defmodule Prob5 do def move([[h1 | rest] = _list1, list2]) do [rest, [h1 | list2]...
New
Aetherus
This topic is about Day 7 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/le...
New
jkwchui
Monkeys fitted squarely as GenServers in my head. My initial problem was using cast instead of call; I imagine impolite monkeys slinging...
New
Qqwy
Note by the Moderators: This topic is to talk about Day 6 of the Advent of Code. For general discussion about the Advent of Code 2018 an...
New
igorb
So… that’s it? Everyone is stuck on part 2? :slight_smile: I looked at Reddit hints and thought I probably wouldn’t have come up with the...
New
rvnash
Anyone have a solution to Part 2 today? Part 1 was straight forward, but I can’t figure out a programatic way to do part 2. I understand ...
New

Other popular topics Top

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement