bjorng

bjorng

Erlang Core Team

Advent of Code 2023 - Day 14

My solution finishes both parts in 5 seconds on my computer. That time should be possible to reduce by optimizing my rather naive tilt/2 function, but I decided to instead optimize the use of my time and leave as is.

My solution:

https://github.com/bjorng/advent-of-code-2023/blob/main/day14/lib/day14.ex

Most Liked

trnasistor

trnasistor

My beginner’s solution, Day 14 part 1. Parabolic Reflector Dish

defmodule Day14 do
def part1(input), do:
  input
  |> String.split("\n")
  |> Enum.map(&String.graphemes/1)
  |> List.zip
  |> Enum.reduce(0, fn column, acc -> column
       |> Tuple.to_list
       |> Enum.chunk_by(&(&1=="#"))
       |> Enum.map(&Enum.sort(&1, :desc))
       |> List.flatten
       |> Enum.reverse
       |> Enum.with_index(1)
       |> then(&(for {"O", n} <- &1, reduce: 0 do acc -> acc + n end))
       |> Kernel.+(acc)
     end)
end
exists

exists

Not proud of this solution, although runs under 3 seconds for part two.
A few comments:

  • This is probably the worst bit: I did not specifically look for when the repeated cycle begins, I just tried a few numbers for the length of the initial run. The point is that as long as it’s enough to get into the cycles, it will be good enough to find the cycle length. The upside is that I only need two grids at any given time.
  • As others, just one direction of tilting (for me the easiest seemed “to the left”), and use grid transformations to get the other directions. This could definitely be optimised.
defmodule Main do
  def run() do
    get_input()
    |> Enum.map(&String.to_charlist/1)
    # |> solve1()
    |> solve2()
	end

  def get_input() do
    # "testinput14"
    "input14"
    |> File.read!()
    |> String.trim()
    |> String.split("\n")
  end

  def transpose(ls) do
    ls |> List.zip() |> Enum.map(&Tuple.to_list/1)
  end

  def flip_lr(ls) do
    ls |> Enum.map(&Enum.reverse/1)
  end

  def flip_ud(ls) do
    ls |> Enum.reverse()
  end

  def tilt_row_left(l) do
    (l ++ ~c"#")
    |> Enum.reduce({~c"", ~c"", ~c""}, fn c, {lsf, os, ds} ->
          # state: { line_so_far, accumulated_O_s, accumulated_dots }
          case c do
            ?. -> {lsf, os, ds ++ ~c"."}
            ?O -> {lsf, os ++ ~c"O", ds}
            ?# -> {lsf ++ os ++ ds ++ ~c"#", ~c"", ~c""}
          end
       end)
    |> elem(0)
    |> Enum.drop(-1)
  end

  def count_os(l) do
    l |> Enum.filter(fn c -> c == ?O end) |> Enum.count()
  end

  def value(ls) do
    ls
    |> Enum.map(&count_os/1)
    |> Enum.reverse()
    |> Enum.with_index(1)
    |> Enum.map(fn {n,i} -> n*i end)
    |> Enum.sum()
  end
  
  def solve1(ls) do
    ls
    # |> IO.inspect(width: 20)
    |> transpose()
    |> Enum.map(&tilt_row_left/1)
    |> transpose()
    # |> IO.inspect(width: 20)
    |> value()
  end

  def cycle(ls) do
    ls |> transpose() |> Enum.map(&tilt_row_left/1)
    |> transpose() |> Enum.map(&tilt_row_left/1) # after N,W, oriented orig
    |> transpose() |> flip_lr() |> Enum.map(&tilt_row_left/1)
    |> transpose() |> flip_lr() |> Enum.map(&tilt_row_left/1)
    |> flip_ud() |> flip_lr()
  end

  def run_cycles(ls, n) do
    1..n |> Enum.reduce(ls, fn _, gg -> cycle(gg) end)
  end

  def solve2(ls) do
    initial = 150
    ee = run_cycles(ls,initial)
    period = 1 .. 1_000
              |> Enum.reduce_while(ee, fn n, gg ->
                  if (ng = cycle(gg)) == ee do {:halt, n} else {:cont, ng} end
                end)
    run_cycles(ee, rem(1_000_000_000 - initial,period))
    |> value()
  end
  
end

:timer.tc(&Main.run/0)
|> IO.inspect()
lud

lud

My solution completes part 2 in less than a second but I have the same feeling that the tilt could be improved.

I lost so much time with wrong scores until I decided to print all scores in the loop and see that 64 was never coming. This was because my scoring function works with northbound rows but each cycle leaves the platform in eastbound rows.

So I had to add that final rotate() before scoring and it was fine:

    rows_loop_start
    |> apply_cycles(cycles_left)
    |> rotate()
    |> score()

But before I lost like 30 minutes to re-learn the concepts of division, multiplication, remainders and all… :smiley: My 2nd grade teacher would be proud.

https://github.com/lud/adventofcode/blob/main/lib/solutions/2023/day14.ex

Where Next?

Popular in Challenges Top

LostKobrakai
This one has been quite the ride. Struggled at first to find a good data format to suite the problem. I really like how that turned out b...
New
bjorng
This topic is about Day 5 of the Advent of Code 2021. We have a private leaderboard (shared with users of Erlang Forums ): https://adve...
New
coen.bakker
Since I started using Elixir, I have benefited greatly from being able to study various open-source projects. The codebase of LiveBook, i...
New
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
liamcmitchell
A frustrating one for me. I spent a long time trying to understand why some combinations resulted in fewer presses and struggled to keep ...
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
bjorng
My solution finishes both parts in 5 seconds on my computer. That time should be possible to reduce by optimizing my rather naive tilt/2 ...
New
bjorng
Note: This topic is to talk about Day 25 of the Advent of Code 2019. There is a private leaderboard for elixirforum members. You can joi...
New
adamu
Nobody’s doing Advent of Code this year? :grinning_face_with_smiling_eyes: I might do the first week or so. For Day 1, first I solved i...
New
Aetherus
Finished Day 1 with Elixir :tada: Here’s my code: #!/usr/bin/env elixir defmodule Combination do @doc "Yields each combination of 2...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
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
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement