Advent of Code 2020 - Day 1 (practice for the upcoming AOC 2021)

This topic is about Day 1 of the Advent of Code 2020.

We have a private leaderboard (shared with users of the elixir forum):

https://adventofcode.com/2021/leaderboard/private/view/39276

The join code is:
39276-eeb74f9a

In less than two days, the 2021 season of Advent of Code starts. I am posting this thread as a practice thread. Here you can post your existing or new solutions written in Erlang or another BEAM language for the puzzles from Dec 1, 2020.

10 Likes

Here is my solution.

(This is a newly written solution. Since I write in Erlang extensively in my day job, I take the opportunity to sharpen my Elixir skills every year with the help of Advent of Code.)

8 Likes

@bjorng thanks for this sharing!
Here is my solution for part one of day 1:

% Let's say that "X" already defined and have all data what we need for day 1, eg:
% X = [1721, 979, 366, 299, 675, 1456].
1>  hd([I1 * I2 || I1 <- X, I2 <- X, I1 + I2 == 2020]).
514579

For part two of day 1 - it’s can looks like:

1> hd([I1 * I2 * I3 || I1 <- X, I2 <- X, I3 <- X, I1 + I2 + I3 == 2020]).
8 Likes

Wow, @vkatsuba that is neat. Not sure I’d want to debug it in production mind!

My solution is definitely less concise:


-module(aoc_2020_1).
-export([p1/0, p2/0]).

-include_lib("eunit/include/eunit.hrl").

% find the two entries that sum to 2020
% and then multiply those two numbers together.
p1_test() ->
    ?assert(p1(test_data()) == 514579).

p2_test() ->
    ?assert(p2(test_data()) == 241861950).

p1() ->
    p1(input_data()).

p2() ->
    p2(input_data()).

p1(L1) ->
    [{X, Y}|_] = find_values(L1, 2020),
    X * Y.

p2(L1) ->
    [{X, Y, Z}|_] = find_values3(L1),
    X * Y * Z.
    
find_values3(L1) ->
    lists:filtermap(
        fun(Z) ->
            case find_values(L1, 2020-Z) of
                [] -> false;
                [{X, Y}|_] -> {true, {X, Y, Z}}
            end
        end,
        L1).

find_values(L1, Sum) ->
    lists:filtermap(
        fun(X) ->
            inner(X, Sum-X, lists:delete(X, L1))
        end,
        L1).

inner(X, Y, L2) ->
    case lists:member(Y, L2) of
        true -> {true, {X, Y}};
        false -> false
    end.

test_data() ->
    [
        1721,
        979,
        366,
        299,
        675,
        1456
    ].

input_data() ->
    [
        1254,
        1313,
        1456,
        1782,
        1742,
        1391,
        1273,
        1286,
        1373,
        1891,
        1188,
        1994,
        1887,
        1816,
        1984,
        961,
        1428,
        1105,
        1123,
        1699,
        1154,
        1953,
        1977,
        1450,
        1696,
        1068,
        1241,
        1926,
        1228,
        1591,
        1789,
        1966,
        1508,
        1193,
        1190,
        1654,
        444,
        1282,
        1169,
        1165,
        1778,
        1669,
        1570,
        1671,
        1845,
        1208,
        1728,
        1798,
        847,
        1300,
        1817,
        1200,
        1297,
        1658,
        1296,
        1571,
        1991,
        1305,
        1314,
        1903,
        1472,
        1359,
        1506,
        1999,
        1877,
        1168,
        1137,
        1288,
        1083,
        1656,
        413,
        1430,
        1408,
        1397,
        1846,
        1218,
        684,
        1234,
        2007,
        900,
        1604,
        1460,
        1848,
        1693,
        1324,
        1401,
        1968,
        1918,
        1975,
        1665,
        1413,
        1874,
        1852,
        1521,
        1753,
        1229,
        1940,
        1650,
        1976,
        1235,
        1130,
        1927,
        1365,
        1908,
        1441,
        1302,
        1986,
        1449,
        1692,
        1944,
        1277,
        1312,
        1826,
        1231,
        1289,
        1814,
        1170,
        1606,
        1608,
        1773,
        1883,
        1936,
        1626,
        1497,
        1860,
        1673,
        1295,
        2005,
        1481,
        1995,
        1734,
        1646,
        1557,
        1298,
        1174,
        1894,
        1309,
        1240,
        1982,
        1414,
        1799,
        1620,
        1863,
        1220,
        1642,
        508,
        1146,
        1187,
        1253,
        1284,
        1952,
        1527,
        1610,
        1333,
        1221,
        1362,
        1457,
        1721,
        1493,
        1330,
        156,
        1647,
        1841,
        1724,
        2000,
        1398,
        1745,
        1985,
        1269,
        1722,
        2001,
        1923,
        1395,
        1094,
        1140,
        1958,
        1239,
        1336,
        1588,
        1338,
        1750,
        1757,
        1444,
        1822,
        1335,
        1941,
        1865,
        1767,
        1881,
        1499,
        1157,
        1990,
        1210,
        1779,
        1201,
        1784,
        1961,
        1476,
        1861,
        1468
    ].
5 Likes

My solution was the same:

-module(day1).
-export([run/0]).

-type day1_result() :: {Factor::pos_integer(), Factor::pos_integer(), Product::pos_integer()}.
-type day2_result() :: {Factor::pos_integer(), Factor::pos_integer(), Factor::pos_integer(), Product::pos_integer()}.
-spec run() -> {Day1::day1_result(), Day2::day2_result()}.

run()->
    Numbers = load_file("day1input.txt"),
    {part1(Numbers), part2(Numbers)}.

load_file(Filename)->
    {ok, Binary} = file:read_file(Filename),
    StringContent = unicode:characters_to_list(Binary),
    [ element(1, string:to_integer(Substr)) || Substr <- string:tokens(StringContent, "\n")]. 

part1(L)->
    hd([{X, Y, X*Y} || X <- L, Y <- L, X + Y =:= 2020]).

part2(L)->
    hd([{X, Y, Z, X*Y*Z} || X <- L, Y <- L, Z <- L, X + Y + Z =:= 2020]).

However, I also wrote some longer, less brute force, but much more complicated solutions:

6 Likes

My solution:

%% fun with processes

-module(day1).
-export([start/0, data/0, run/2]).

data() -> 
    [
     1822,
     1917,
      ..
     1691,
     1875
    ].

start() ->
    start(data(), []).

start([], _) ->
    ok;
start([H|Rest], Pids) ->
    Pid = spawn(?MODULE, run, [Pids, H]),
    start(Rest, [Pid|Pids]).

run(Pids, Val) ->
    [Pid ! {getVal, self()} || Pid <- Pids],
    rec(Pids, Val).

rec(Pids, Val) ->
    receive
        {val, OtherVal} ->
            sum(Val, OtherVal),
            rec(Pids, Val);
        {getVal, OtherPid} ->
            OtherPid ! {val, Val},
            rec(Pids, Val)
        after
            5000 ->
                ciao
    end.

sum(A,B) when A+B == 2020 ->
    io:format("~p * ~p = ~p~n", [A,B, A*B]);
sum(_,_) ->
    ok.

5 Likes

2020 DAY 2

Taking inspiration from the brute force list comprehension approach others have taken to Day 1’s problem:

aoc_1(PL) ->
    length([Pwd || {Min, Max, C, Pwd} <-PL,
        Min =< length(lists:filter(fun(PC)->C==PC end, Pwd)),
        Max >= length(lists:filter(fun(PC)->C==PC end, Pwd))
    ]).

aoc_2(PL) ->
    length([Pwd || {One, Two, C, Pwd} <-PL,
        (lists:nth(One, Pwd) == C) xor (lists:nth(Two, Pwd) == C)]).

Has anyone got any tips on an elegant way of avoiding the duplicated length(lists:filter(...)) in part 1?

4 Likes

Maybe this one?:

1> PL = [{1, 3, "a", "abcde"}, {1, 3, "b", "cdefg"}, {2, 9, "c", "ccccccccc"}].
2> length([Pwd || {Min, Max, C, Pwd} <- PL, Size <- [length([PC || PC <- Pwd, [PC] == C])],  Min =< Size, Max >= Size]).

:upside_down_face:

5 Likes

That’s what I was after - I always forget about <- , <-.

3 Likes