christhekeele

christhekeele

Advent of Code 2023 - Day 2

Thought I’d kick today’s thread off!

Parsing

Enum rocks, so most of my code was actually in parsing input.

Preprocessing input

Data model is:

%{
  id :: integer() => [
    pull :: %{
      red: integer(),
      green: integer(),
      blue: integer()
    }
  ]
}

I modeled each pull as a struct rather than a bare map, just so I didn’t have to write any extra code to hydrate my maps with default 0 values where input was empty for a color.

Source available here.

defmodule AoC.Day.Two.Input do
  defmodule Pull do
    defstruct red: 0, green: 0, blue: 0
  end

  def parse(input_file \\ System.fetch_env!("INPUT_FILE")) do
    input_file
    |> File.read!()
    |> String.split("\n")
    |> Enum.reject(&(&1 == ""))
    |> Enum.map(&parse_game/1)
    |> Map.new()
  end

  def parse_game("Game " <> game) do
    {id, rest} = Integer.parse(game)
    <<": ">> <> pulls = rest

    pulls =
      pulls
      |> String.trim()
      |> String.split(";")
      |> Enum.map(&String.trim/1)
      |> Enum.map(&parse_pull/1)

    {id, pulls}
  end

  def parse_pull(pull) do
    result =
      pull
      |> String.split(",")
      |> Enum.map(&String.trim/1)
      |> Enum.map(&parse_pull_color/1)

    struct!(Pull, result)
  end

  def parse_pull_color(result) do
    case Integer.parse(result) do
      {num, " red"} -> {:red, num}
      {num, " green"} -> {:green, num}
      {num, " blue"} -> {:blue, num}
    end
  end
end

Part 1

Solution

input |> Enum.filter(Enum.all?) |> Enum.map |> Enum.sum. Source available here.

defmodule AoC.Day.Two.Part.One do
  @red_limit 12
  @green_limit 13
  @blue_limit 14

  def solve(input) do
    input
    |> Enum.filter(fn {_id, pulls} ->
      Enum.all?(pulls, fn
        %{red: red, green: green, blue: blue}
        when red <= @red_limit and green <= @green_limit and blue <= @blue_limit ->
          true

        _ ->
          false
      end)
    end)
    |> Enum.map(fn {id, _} -> id end)
    |> Enum.sum()
  end
end

Part 2

Solution

Simpler still. Could have avoided iterating over pulls 3 times, but not too fussed about it. Source available here.

defmodule AoC.Day.Two.Part.Two do
  def solve(input) do
    input
    |> Enum.map(fn {id, pulls} ->
      min_red = pulls |> Enum.map(&Map.fetch!(&1, :red)) |> Enum.max()
      min_green = pulls |> Enum.map(&Map.fetch!(&1, :green)) |> Enum.max()
      min_blue = pulls |> Enum.map(&Map.fetch!(&1, :blue)) |> Enum.max()

      {id, min_red * min_green * min_blue}
    end)
    |> Enum.map(fn {_id, power} -> power end)
    |> Enum.sum()
  end
end

Most Liked

adamu

adamu

After seeing part 2, we know that both parts only need the aggregate of all the rounds, so for each game I used a single map representing the maximum number of cubes seen.

|> Enum.reduce(
  %{"red" => 0, "green" => 0, "blue" => 0},
  &Map.merge(&1, &2, fn _colour, count1, count2 -> max(count1, count2) end
)

https://git.adamu.jp/adam/AdventOfCode/src/branch/main/2023/day2.exs

awerment

awerment

Just wanted to say I love the use of Integer.parse/1 here!

stevensonmt

stevensonmt

My code here. The only notable thing was I decided to force myself to parse manually doing nothing but pattern matching on binaries. Painful and pointless, but also was kind of a fun challenge. Only worked because I knew the limits of the input size. It would fail if any round included any cubes of more than 99 or if there were more than 100 games. Since I knew neither of those conditions applied it was fine.

Here’s the parsing:

def parse(input) do
      input
      |> Day2.input()
      |> Input.lines()
      |> Enum.map(&parse_game/1)
      |> Enum.map(fn map ->
        [k] = Map.keys(map)

        v =
          Map.values(map)
          |> hd()
          |> un_nest()

        {k, v}
      end)
      |> Enum.into(%{})
    end

    defp parse_game(<<"Game ", rest::binary>>), do: parse_game(rest)

    defp parse_game(<<i, j, ": ", rest::binary>>) when i in 49..57 and j in 48..57 do
      k = (i - 48) * 10 + (j - 48)
      Map.put(%{}, k, parse_game(rest))
    end

    defp parse_game(<<i, ": ", rest::binary>>) when i in 49..57,
      do: %{(i - 48) => parse_game(rest)}

    defp parse_game(<<"100: ", rest::binary>>), do: %{100 => parse_game(rest)}

    defp parse_game(<<i, " blue", rest::binary>>) when i in 49..57 do
      [{"blue", i - 48} | parse_game(rest)]
    end

    defp parse_game(<<i, " red", rest::binary>>) when i in 49..57 do
      [{"red", i - 48} | parse_game(rest)]
    end

    defp parse_game(<<i, " green", rest::binary>>) when i in 49..57 do
      [{"green", i - 48} | parse_game(rest)]
    end

    defp parse_game(<<i, j, " blue", rest::binary>>) when i in 49..57 and j in 48..57 do
      [{"blue", (i - 48) * 10 + (j - 48)} | parse_game(rest)]
    end

    defp parse_game(<<i, j, " red", rest::binary>>) when i in 49..57 and j in 48..57 do
      [{"red", (i - 48) * 10 + (j - 48)} | parse_game(rest)]
    end

    defp parse_game(<<i, j, " green", rest::binary>>) when i in 49..57 and j in 48..57 do
      [{"green", (i - 48) * 10 + (j - 48)} | parse_game(rest)]
    end

    defp parse_game(<<", ", rest::binary>>), do: parse_game(rest)
    defp parse_game(<<"; ", rest::binary>>), do: [parse_game(rest)]
    defp parse_game(""), do: []

    defp un_nest(nested, m \\ %{})
    defp un_nest([], m), do: [m]

    defp un_nest([hd], m) when is_list(hd),
      do: un_nest(hd) ++ [m]

    defp un_nest([{k, v} | tl], m), do: un_nest(tl, Map.put(m, k, v))

Where Next?

Popular in Challenges Top

sasajuric
Note by the Moderators: This topic is to talk about Day 5 of the Advent of Code. For general discussion about the Advent of Code 2018 an...
New
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 10 of the Advent of Code 2021. We have a private leaderboard (shared with users of Erlang Forums ): https://adv...
New
lud
At first I was scared but I found is a simple way to compute the sides. defmodule AdventOfCode.Solutions.Y24.Day12 do alias AdventOfCo...
New
rugyoga
part 1 https://github.com/rugyoga/aoc2021/blob/main/day7.exs part 2 https://github.com/rugyoga/aoc2021/blob/main/day7b.exs
New
christhekeele
Continuation of Advent of Code 2022​:christmas_tree:, Day 1: Day 2! Leaderboard:
New
Aetherus
Today’s problem is really tense. I don’t think I can do it without libgraph.
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
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
christhekeele
Thought I’d kick today’s thread off! Parsing Enum rocks, so most of my code was actually in parsing input. ▶ Preprocessing input Part 1...
New

Other popular topics Top

New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
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
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
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