bjorng

bjorng

Erlang Core Team

Advent of Code 2020 - Day 14

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

Thanks to @egze, we have a private leaderboard:
https://adventofcode.com/2020/leaderboard/private/view/39276

The join code is:
39276-eeb74f9a

Most Liked

bjorng

bjorng

Erlang Core Team

Hello, everyone. I’m back. This year I didn’t want to do every AOC puzzle the minute it was posted every day for 25 straight days as I did the last two years. Two weeks in I realized that I missed this yearly opportunity to learn some more Elixir, so I will drop in here now and then, probably doing some of the puzzles out of order.

Today’s puzzle was a fun one. Here is my solution.

Aetherus

Aetherus

Today I reinstalled the operating system on my laptop, and I just finished recovering my GitHub account, so it’s a bit late to post my solutions to today’s quizzes.

I didn’t use bitwise operations, either, because I couldn’t find a neat one. I hope to see some smart solutions.

Anyway, here’s my solution:

Part 1

#!/usr/bin/env elixir

initial_state = %{
  mem: %{},
  mask: ""
}

parse_mem_set = fn line ->
  [address, value] = Regex.run(~r/^mem\[(\d+)\] = (\d+)$/, line, capture: :all_but_first)
  {address, value}
end

apply_mask = fn value, mask ->
  value = value
          |> String.to_integer()
          |> Integer.to_string(2)
          |> String.pad_leading(36, "0")
          |> :binary.bin_to_list()

  mask
  |> :binary.bin_to_list()
  |> Enum.zip(value)
  |> Enum.map(fn
    {?0, _} -> ?0
    {?1, _} -> ?1
    {?X, v} -> v
  end)
  |> List.to_integer(2)
end

"day14.txt"
|> File.stream!()
|> Stream.map(&String.trim/1)
|> Enum.reduce(initial_state, fn
  "mask = " <> mask, state -> %{state | mask: mask}
  "mem" <> _ = line, state ->
    {address, value} = parse_mem_set.(line)
    masked_value = apply_mask.(value, state.mask)
    put_in(state, [:mem, String.to_integer(address)], masked_value)
end)
|> Map.get(:mem)
|> Map.values()
|> Enum.sum()
|> IO.inspect()

Part 2

#!/usr/bin/env elixir

initial_state = %{
  mem: %{},
  mask: ""
}

parse_mem_set = fn line ->
  [address, value] = Regex.run(~r/^mem\[(\d+)\] = (\d+)$/, line, capture: :all_but_first)
  {address, value}
end

do_mask = fn zipped ->
  # acc is a list of lists of codepoints.
  zipped
  |> Enum.reduce([[]], fn
    {?0, v}, acc -> Enum.map(acc, &[v  | &1])
    {?1, _}, acc -> Enum.map(acc, &[?1 | &1])
    {?X, _}, acc -> Enum.map(acc, &[?0 | &1]) ++ Enum.map(acc, &[?1 | &1])
  end)
  |> Enum.map(&Enum.reverse/1)
  |> Enum.map(&List.to_integer(&1, 2))
end

apply_mask = fn address, mask ->
  address = address
            |> String.to_integer()
            |> Integer.to_string(2)
            |> String.pad_leading(36, "0")
            |> :binary.bin_to_list()

  mask
  |> :binary.bin_to_list()
  |> Enum.zip(address)
  |> do_mask.()
end

"day14.txt"
|> File.stream!()
|> Stream.map(&String.trim/1)
|> Enum.reduce(initial_state, fn
  "mask = " <> mask, state -> %{state | mask: mask}
  "mem" <> _ = line, state ->
    {address, value} = parse_mem_set.(line)
    masked_addresses = apply_mask.(address, state.mask)
    for address <- masked_addresses, reduce: state do
      st -> put_in(st, [:mem, address], String.to_integer(value))
    end
end)
|> Map.get(:mem)
|> Map.values()
|> Enum.sum()
|> IO.inspect()
cblavier

cblavier

Hi there :wave:

Part1 was easy to me (used Bitwise operator), but I struggled with recursion for Part2 until I found out that I could manage without recursion :sweat_smile:

My code here :

Part1 / Part2

the bitwise part for anyone interested
  def run_program_chunk({mask, instructions}, memory) do
    {or_mask, _} = mask |> String.replace("X", "0") |> Integer.parse(2)
    {and_mask, _} = mask |> String.replace("X", "1") |> Integer.parse(2)

    Enum.reduce(instructions, memory, fn {address, value}, memory ->
      Map.put(memory, address, (value ||| or_mask) &&& and_mask)
    end)
  end

EDIT : simplified my Part 2 code, to remove a lot of string manipulations

Part2 address generation
  def find_addresses(address_and_mask) do
    Enum.reduce(address_and_mask, [0], fn
      {_, "X"}, acc -> fork(acc)
      {_, "1"}, acc -> add_bit(acc, 1)
      {"1", _}, acc -> add_bit(acc, 1)
      _, acc -> add_bit(acc, 0)
    end)
  end

  def add_bit(acc, bit), do: Enum.map(acc, &(&1 * 2 + bit))
  def fork(acc), do: Enum.flat_map(acc, &[&1 * 2, &1 * 2 + 1])

Last Post!

stevensonmt

stevensonmt

FINALLY GOT IT

defmodule Day14Part2Only do
  use Bitwise
  @moduledoc false

  @input File.read!("lib/input")

  defmodule MyParser do
    import NimbleParsec

    mask =
      ignore(string("mask = "))
      |> ascii_string([?1, ?0, ?X], 36)
      |> ignore(string("\n"))

    mem =
      ignore(string("mem["))
      |> integer(min: 1)
      |> ignore(string("] = "))
      |> integer(min: 1)
      |> ignore(string("\n"))
      |> reduce({List, :to_tuple, []})

    group =
      mask
      |> repeat(mem)
      |> reduce({List, :wrap, []})

    defparsec(:nimble_parse, repeat(group))
  end

  def nimble_parse do
    MyParser.nimble_parse(@input)
    |> elem(1)
    |> Enum.map(fn [mask | assignments] -> {mask, assignments} end)
  end

  def initialize(version \\ 1) do
    nimble_parse()
    |> build_mem_map(version)
  end

  def build_mem_map(processed_lines, version \\ 1) do
    processed_lines
    |> Enum.reduce(%{}, fn {mask, assignments}, memory ->
      assign_memory(mask, assignments, memory, version)
    end)
  end

  def assign_memory(mask, assignments, memory, 2 = version) do
    assignments
    |> Enum.map(&apply_mask(&1, mask, version))
    |> Enum.reduce(memory, fn {addresses, val}, acc ->
      update_memory({addresses, val}, acc, version)
    end)
  end

  def apply_mask({address, value}, mask, 2) do
    {address
     |> Integer.to_string(2)
     |> String.pad_leading(36, "0")
     |> String.codepoints()
     |> Enum.zip(String.codepoints(mask))
     |> Enum.reduce([0], fn {a, b}, acc ->
       case b do
         "0" -> Enum.map(acc, fn addr -> addr * 2 + String.to_integer(a) end)
         "1" -> Enum.map(acc, fn addr -> addr * 2 + 1 end)
         "X" -> fork(acc)
       end
     end), value}
  end

  def fork(acc) do
    acc
    |> Enum.flat_map(fn addr -> [addr * 2, addr * 2 + 1] end)
  end

  def update_memory({addresses, val}, memory, 2) do
    addresses
    |> Enum.reduce(memory, fn address, acc ->
      Map.put(acc, address, val)
    end)
  end

  def run2 do
    initialize(2)
    |> sum_memory()
    |> IO.puts()
  end

  def sum_memory(mem_map) do
    mem_map
    |> Map.values()
    |> Enum.sum()
  end
end

Day14Part2Only.run2()

I’ve done a half dozen approaches to the branching/flat mapping portion of applying the mask, but in the end there was something squirrelly about how I was processing the input. Once I broke down and used Nimble Parsec it just worked. UGGGGH.

Where Next?

Popular in Challenges Top

connorlay
Note by the Moderators: This topic is for general discussion about the Advent of Code 2018. To prevent people from being spoiled about s...
New
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
Aetherus
Hello, guys. I’m back again, but only for the weekends, maybe. This topic is about Day 13 of the Advent of Code 2020 . Thanks to @egze,...
New
bjorng
This topic is about Day 17 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/l...
New
Aetherus
I tried to use combinatorial to solve today’s puzzles but failed (my brain burned out :exploding_head:). In the end I just used brute for...
New
code-shoily
Here’s my day 3 code https://github.com/code-shoily/advent_of_code/blob/master/lib/2024/day_03.ex This was quite easy. I was afraid Par...
New
bjorng
Here is my solution for day 4: https://github.com/bjorng/advent-of-code/blob/main/2024/day04/lib/day04.ex
New

Other popular topics Top

greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44139 214
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

We're in Beta

About us Mission Statement