bjorng
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
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
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
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…
My 2nd grade teacher would be proud.
https://github.com/lud/adventofcode/blob/main/lib/solutions/2023/day14.ex
Popular in Challenges
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








