Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

day 3

livebook/2022/day3.livemd

day 3

Mix.install([
  {:kino, "~> 0.8.0"}
])

setup

input = Kino.Input.textarea("drop yo text input here")

scratch

?a..?z
|> Enum.to_list()
|> List.to_string()
|> String.split("", trim: true)
|> Enum.with_index(fn e, i -> {e, i + 1} end)
|> Enum.into(%{})
test_input = """
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
"""

MapSet.intersection(MapSet.new([1, 2, 3]), MapSet.new([2, 3, 3])) |> Enum.into([])

part 1

defmodule P1 do
  defguard double_list(a, b) when is_list(a) and is_list(b)
  defguard double_map(a, b) when is_map(a) and is_map(b)

  def sum(items) do
    az_lower_case = alpha_range(?a..?z, 1)
    az_upper_case = alpha_range(?A..?Z, 27)

    items
    |> Enum.reduce(0, fn i, acc ->
      l = Map.get(az_lower_case, i, 0)
      u = Map.get(az_upper_case, i, 0)

      acc + l + u
    end)
  end

  def parse(input_str) do
    input_str
    |> String.split("\n", trim: true)
    |> Enum.map(&process_line/1)
    |> Enum.sum()
  end

  defp process_line(sack) do
    items =
      sack
      |> String.split("", trim: true)

    {left, right} =
      items
      |> Enum.split(div(length(items), 2))

    intersect(left, right)
    |> sum()
  end

  defp intersect(a, b) when double_list(a, b) do
    intersect(MapSet.new(a), MapSet.new(b))
  end

  defp intersect(a, b) when double_map(a, b) do
    MapSet.intersection(a, b)
    |> Enum.into([])
  end

  defp alpha_range(range, offset) do
    range
    |> Enum.to_list()
    |> List.to_string()
    |> String.split("", trim: true)
    |> Enum.with_index(fn e, i -> {e, i + offset} end)
    |> Enum.into(%{})
  end
end

"""
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
"""
|> P1.parse()

input
|> Kino.Input.read()
|> P1.parse()

test 1

ExUnit.start(auto_run: false)

defmodule P1Test do
  use ExUnit.Case, async: false

  test "parse" do
    assert 157 ==
             """
             vJrwpWtwJgWrhcsFMMfFFhFp
             jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
             PmmdzqPrVvPwwTWBwg
             wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
             ttgJtRGJQctTZtZT
             CrZsJsPPZsGzwwsLwLmpwMDw
             """
             |> P1.parse()
  end
end

ExUnit.run()

part 2

defmodule P2 do
  defguard double_list(a, b) when is_list(a) and is_list(b)
  defguard double_map(a, b) when is_map(a) and is_map(b)

  def sum(items) do
    az_lower_case = alpha_range(?a..?z, 1)
    az_upper_case = alpha_range(?A..?Z, 27)

    items
    |> Enum.reduce(0, fn i, acc ->
      l = Map.get(az_lower_case, i, 0)
      u = Map.get(az_upper_case, i, 0)

      acc + l + u
    end)
  end

  def parse(input_str) do
    sacks =
      input_str
      |> String.split("\n", trim: true)
      |> Enum.chunk_every(3)

    sacks
    |> Enum.map(fn b -> process_line(b) end)
    |> Enum.sum()
  end

  defp process_line(group) do
    lines =
      group
      |> Enum.map(fn s -> String.split(s, "", trim: true) end)

    [a, b, c] = lines

    ab = inter(a, b)
    ac = inter(a, c)

    inter(ab, ac) |> sum()
  end

  def inter(a, b) when double_list(a, b) do
    inter(MapSet.new(a), MapSet.new(b))
  end

  def inter(a, b) when double_map(a, b) do
    MapSet.intersection(a, b)
    |> Enum.into([])
  end

  defp alpha_range(range, offset) do
    range
    |> Enum.to_list()
    |> List.to_string()
    |> String.split("", trim: true)
    |> Enum.with_index(fn e, i -> {e, i + offset} end)
    |> Enum.into(%{})
  end
end

a = ["P", "m", "m", "d", "z", "q", "P", "r", "V", "v", "P", "w", "w", "T", "W", "B", "w", "g"]

b = [
  "j",
  "q",
  "H",
  "R",
  "N",
  "q",
  "R",
  "j",
  "q",
  "z",
  "j",
  "G",
  "D",
  "L",
  "G",
  "L",
  "r",
  "s",
  "F",
  "M",
  "f",
  "F",
  "Z",
  "S",
  "r",
  "L",
  "r",
  "F",
  "Z",
  "s",
  "S",
  "L"
]

c = [
  "v",
  "J",
  "r",
  "w",
  "p",
  "W",
  "t",
  "w",
  "J",
  "g",
  "W",
  "r",
  "h",
  "c",
  "s",
  "F",
  "M",
  "M",
  "f",
  "F",
  "F",
  "h",
  "F",
  "p"
]

ab = P2.inter(a, b)
ac = P2.inter(a, c)

# intersection of ab + ac 
P2.inter(ab, ac)

"""
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw
"""
|> P2.parse()

input
|> Kino.Input.read()
|> P2.parse()

I asked ChatGPT to explain intesersection sets to me :)

> In set theory, an intersection is a combination of two or more sets that contains only the elements that are common to all of the sets. For example, if you have the sets A = {1, 2, 3} and B = {2, 3, 4}, the intersection of these sets would be the set C = {2, 3}. This is because the set C contains only the elements that are common to both set A and set B. In other words, the intersection of two sets is the set of elements that belong to both sets.

test 2

ExUnit.start(auto_run: false)

defmodule P1Test do
  use ExUnit.Case, async: false

  test "parse" do
    assert 70 ==
             """
             vJrwpWtwJgWrhcsFMMfFFhFp
             jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
             PmmdzqPrVvPwwTWBwg
             wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
             ttgJtRGJQctTZtZT
             CrZsJsPPZsGzwwsLwLmpwMDw
             """
             |> P2.parse()
  end
end

ExUnit.run()