This topic is about Day 7 of the Advent of Code 2021.
We have a private leaderboard (shared with users of the elixir forum):
https://adventofcode.com/2021/leaderboard/private/view/370884
The entry code is:
370884-a6a71927
This topic is about Day 7 of the Advent of Code 2021.
We have a private leaderboard (shared with users of the elixir forum):
https://adventofcode.com/2021/leaderboard/private/view/370884
The entry code is:
370884-a6a71927
This day also seems straightforward, I suppose bruteforce approach works here :
main(File) ->
{ok, RawData} = file:read_file(File),
Data = [ binary_to_integer(X) || X <- binary:split(RawData, <<",">>, [global, trim]) ],
io:format("part 1: ~p~n", [solve1(Data)]),
io:format("part 2: ~p~n", [solve2(Data)]),
ok.
solve1(Data) ->
run(fun(X) -> X end, Data).
run(FuelFun, Data) ->
lists:min([ lists:sum([ FuelFun(abs(D - N)) || D <- Data ])
|| N <- lists:seq(lists:min(Data), lists:max(Data)) ]).
solve2(Data) ->
run(fun fuel/1, Data).
fuel(X) ->
X * (1 + X) div 2.
The first one is equivalent to finding the median, so it can theoretically be done in linear time. The second one I have also just brute-forced.
I used bisection for both parts: pick a pivot, compute the number of moves needed for all to align, compute the same for the adjacent positions to determine which part of all positions to use next.
For part 2 I only needed to adapt the function to compute the number of moves, the rest remained the same.
The first is about Manhattan distance, it’s the median. For the second, after I sorted the list I need to traverse points while fuel value is decreasing. When I get a greater fuel, previous position is the solution.
Was tricked into the linear time solution for the first (median) assuming brute force will be too slow for the second. Well then this time it wasn’t.
Aren’t you guys posting your solutions a bit early?
I mean, yes the leaderboard is very wonky anyway and mainly tells what timezone people live in and if they are early risers, since all tasks don’t take much time.
But shouldn’t everyone try their own solution first so why post so early?
In an earlier thread (day 1 or 2?), it was mentioned that it’s a reasonable assumption that the AoC threads should be avoided by those not wanting to be spoiled.
I don’t think someone who is overly competitive is going to wait for others to post their solutions first. Those just doing it for fun at their own leisure will likely avoid the thread or maybe even come here for hints if stuck.
I’m avoiding but people stuck might rather ask questions early on and get hints than just see a full solution here.
Regarding competitiveness: the leaderboard has little to do with coding and lots to do with willingness to set alarm clock (for me it would be 6am) and get up early (I’m a late person), or people living in convenient time zones.
There is a missed opportunity here … 24 days of AoC and 24 hours in a day would make a nice shifting through timezones pattern (except that depending on the direction. we could do only 23 or 25 puzzle days then)
Done. A prettier code this time. Not efficient, though.
Yesterday I was stuck, @peerst. I came to the thread, read only the first few words (no code) and was able to do it on my own.
Par1:
part1() ->
Bin = <<"16,1,2,0,4,2,7,1,2,14\n">>,
Data = [binary_to_integer(X) || X <- re:split(Bin, "[,/\n]+"), X /= <<>>],
lists:min(fuel(Data, Data)).
fuel([], _) -> [];
fuel([H|T], Data) -> [lists:sum([abs(D - H) || D <- Data]) | fuel(T, Data)].
Part2:
part2() ->
Bin = <<"16,1,2,0,4,2,7,1,2,14\n">>,
Data = [binary_to_integer(X) || X <- re:split(Bin, "[,/\n]+"), X /= <<>>],
lists:min(fuel2(lists:seq(lists:min(Data), lists:max(Data)), Data)).
fuel2([], _) ->
[];
fuel2([H|T], Data) ->
Inc = fun(X) -> X * (1 + X) div 2 end,
[lists:sum([Inc(abs(D - H)) || D <- Data]) | fuel2(T, Data)].
for part 2 you can use the mean of the crabs’ positions instead of bruteforcing
-module(d7).
-export([main/0]).
-define(FILENAME, 'd7.in').
main() ->
{_, Raw} = file:read_file(?FILENAME),
CrabsPos = lists:map(fun binary_to_integer/1, string:lexemes(Raw, ",\n")),
CrabsCount = length(CrabsPos),
Median = lists:nth(round(CrabsCount/2), lists:sort(CrabsPos)),
MeanFloor = floor(lists:sum(CrabsPos) / CrabsCount),
MeanCeil = ceil(lists:sum(CrabsPos) / CrabsCount),
Fuel1 = element(1, lists:foldl(fun fuel1/2, {0, Median }, CrabsPos)),
Fuel2 = min(element(1, lists:foldl(fun fuel2/2, {0, MeanCeil }, CrabsPos)),
element(1, lists:foldl(fun fuel2/2, {0, MeanFloor}, CrabsPos))),
{Fuel1, Fuel2}.
fuel1(Pos, {Fuel, Median}) ->
{Fuel + abs(Median-Pos), Median}.
fuel2(Pos, {Fuel, Mean}) ->
Goal = abs(Mean-Pos),
{Fuel + Goal*(Goal+1)/2, Mean}.
My first AOC problem with LFE.
(defmodule day7
(export (part1 0) (part2 0)))
(defun part1 ()
(lists:min
(lists:map
(lambda (x) (fuel_consumption x (load_data)))
(min_max (load_data)))))
(defun part2 ()
(lists:min
(lists:map
(lambda (x) (fuel_consumption2 x (load_data)))
(min_max (load_data)))))
(defun min_max (list)
(lists:seq (lists:min list) (lists:max list)))
(defun fuel_consumption (pos list)
(lists:sum
(lists:map
(lambda(x) (abs (- pos x)))
list)))
(defun fuel_consumption2 (pos list)
(lists:sum
(lists:map
(lambda(x) (cost (abs (- pos x))))
list)))
(defun cost (x) (* x (/ (+ x 1) 2)))
(defun load_data ()
(lists:map
(lambda (x) (element 1 (string:to_integer x)))
(string:split
(string:trim
(element 2 (file:read_file "input.txt"))
) "," 'all)))
I feel like I have been assimilated by a functional cyborg
Congrats!
Fwiw I only had time to do the Awk version today until AWS started melting down, so that’s all I get to show:
func min(a,b) { return (a<b) ? a : b }
func max(a,b) { return (a>b) ? a : b }
func abs(x) { return (x<0) ? x*-1 : x }
BEGIN { FS="," }
{ for (i=1; i<=NF; i++) { l[$i]++ } }
END {
minf=2^PREC
for (i in l) { mi=max(i, mi) }
for (i=0; i<=mi; i++) {
g=0;
for (j in l) {
d=abs(j-i);
g+=(d+1)/2*d*l[j]
}
minf=min(minf,g)
}
print minf
}
I wish there was a nicer way to set the initial max value. I started with just 999999999
and cleaned it up with 2^PREC
(which is 2^53, the max float value). Also I’m a bit annoyed with having to define basic functionality like abs()
and min()
or max()
.
Day 7 in Sesterl: adventofcode/main.sest at master · michallepicki/adventofcode · GitHub
Ugly code this time, I over-complicated my solution a bit. Didn’t really have to use Arrays but wanted to write the bindings. And there’s probably some way to solve this dynamically by following a gradient instead of computing all costs. But it got the answer and I am a day behind…
edit: After looking at other people’s solutions I feel a bit silly I didn’t think of checking the median / mean values first, but oh well, it worked