Day 1: Chronal Calibration - Advent of Code 2018
I did the Advent of Code 2018 day 1 challenge in Elixir! Parts one and two are as follows:
defmodule Day1 do
  def frequency(input) do
    input
    |> read_input()
    |> Enum.reduce(0, fn line, acc ->
      String.to_integer(line) + acc
    end)
  end
  def repeated_frequency(input) do
      input
      |> read_input()
      |> Stream.cycle()
      |> Enum.reduce_while({0, MapSet.new([0])}, fn line, {acc, seen} ->
        value = String.to_integer(line) + acc
        if MapSet.member?(seen, value) do
          {:halt, value}
        else
          {:cont, {value, MapSet.put(seen, value)}}
        end
      end)
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
end
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.frequency()
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.repeated_frequency()
ARTICLES: 9
Day 7: The Sum of Its Parts - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 7 challenge in Elixir! Parts one and two are as follows:
defmodule Day7 do
  @instruction_info ~r/Step (\w+) must be finished before step (\w+) can begin/
  def part1(input) do
    input
    |> read_input()
    |> parse_input()
    |> discover_dependencies([])
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
  defp parse_input(lines) do
    Enum.reduce(lines, %{}, fn line, acc ->
      [step, dependency] = Regex.run(@instruction_info, line, capture: :all_but_first)
      acc
      |> Map.put_new(step, [])
      |> Map.update(dependency, [step], fn dependencies ->
        Enum.sort([step | dependencies])
      end)
    end)
    |> Enum.to_list()
  end
  defp discover_dependencies(deps_tree, acc) when map_size(deps_tree) == 0do
    acc |> Enum.reverse() |> Enum.join()
  end
  defp discover_dependencies(deps_tree, acc) do
    {step, []} = Enum.find(deps_tree, fn {_, deps} -> Enum.empty?(deps) end)
    new_dependencies =
      Enum.reduce(deps_tree, %{}, fn
        {^step, _}, acc -> Map.delete(acc, step)
        {other_step, deps}, acc -> Map.put_new(acc, other_step, List.delete(deps, step))
      end)
    discover_dependencies(new_dependencies, [step | acc])
  end
end
# r Day7; :aoc2018 |> :code.priv_dir() |> Path.join("day7.txt") |> Day7.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day7.txt") |> Day7.part2()
input = "Step D must be finished before step E can begin.
Step F must be finished before step E can begin.
Step C must be finished before step A can begin.
Step B must be finished before step E can begin.
Step A must be finished before step D can begin.
Step C must be finished before step F can begin.
Step A must be finished before step B can begin."
# r Day7; Day7.part1(input)
 
READ MORE
Day 6: Chronal Coordinates - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 6 challenge in Elixir! Parts one and two are as follows:
defmodule Day6 do
  def part1(input) do
    {_infinites, finites} =
      input
      |> read_input()
      |> create_grid()
      |> group_by_infinites()
    {_coordinates, layout} =
      finites
      |> Enum.group_by(fn {x, y, _dist} -> {x, y} end)
      |> Enum.max_by(fn {_, v} -> length(v) end)
    length(layout)
  end
  def part2(input) do
    {max_x, max_y, coordinates} =
      input
      |> read_input()
    for x <- 0..max_x,
        y <- 0..max_y do
      coordinates
      |> Enum.reduce(0, fn {point_x, point_y}, acc ->
        distance = abs(x - point_x) + abs(y - point_y)
        distance + acc
      end)
    end
    |> Enum.filter(&(&1 < 10_000))
    |> Enum.count()
  end
  defp read_input(input) do
    {max_x, max_y, coordinates} =
      input
      |> File.read!()
      |> String.trim()
      |> String.split("\n", trim: true)
      |> Enum.reduce({-1, -1, []}, fn line, {max_x, max_y, coordinates} ->
        [x, y] = String.split(line, ", ")
        x = String.to_integer(x)
        y = String.to_integer(y)
        coordinate = {x, y}
        max_x = if x > max_x, do: x, else: max_x
        max_y = if y > max_y, do: y, else: max_y
        {max_x, max_y, [coordinate | coordinates]}
      end)
    {max_x, max_y, Enum.reverse(coordinates)}
  end
  defp create_grid({max_x, max_y, coordinates}) do
    for x <- 0..max_x,
        y <- 0..max_y do
      [{px, py, dist1}, {_, _, dist2} | _] =
        Enum.map(coordinates, fn {point_x, point_y} ->
          distance = abs(x - point_x) + abs(y - point_y)
          {point_x, point_y, distance}
        end)
        |> Enum.sort_by(fn {_, _, distance} -> distance end)
      if dist1 == dist2 do
        nil
      else
        cond do
          x == 0 ->
            {:infinite, px, py}
          x == max_x ->
            {:infinite, px, py}
          y == 0 ->
            {:infinite, px, py}
          y == max_y ->
            {:infinite, px, py}
          true ->
            {px, py, dist1}
        end
      end
    end
  end
  defp group_by_infinites(grid) do
    Enum.reduce(grid, {MapSet.new(), []}, fn
      nil, acc ->
        acc
      {:infinite, px, py}, {infinites, finites} ->
        {MapSet.put(infinites, {px, py}), finites}
      {px, py, dist}, {infinites, finites} ->
        if MapSet.member?(infinites, {px, py}) do
          {infinites, finites}
        else
          {infinites, [{px, py, dist} | finites]}
        end
    end)
  end
end
# r Day6; :aoc2018 |> :code.priv_dir() |> Path.join("day6.txt") |> Day6.part1()
# r Day6; :aoc2018 |> :code.priv_dir() |> Path.join("day6.txt") |> Day6.part2()
 
READ MORE
Day 5: Alchemical Reduction - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 5 challenge in Elixir! Parts one and two are as follows:
defmodule Day5 do
  def part1(input) do
    input
    |> read_input()
    |> String.codepoints()
    |> reduce_polymer()
  end
  def part2(input) do
    chars =
      input
      |> read_input()
      |> String.codepoints()
    unit_types =
      chars
      |> Enum.map(&String.downcase/1)
      |> Enum.uniq()
    Enum.reduce(unit_types, 1_000_000, fn unit_type, min_size ->
      without_unit =
        Enum.reject(chars, fn char ->
          String.downcase(char) == unit_type
        end)
      min(min_size, reduce_polymer(without_unit))
    end)
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.trim()
  end
  defp reduce_polymer(chars) do
    Enum.reduce(chars, [], fn
      char, [] ->
        [char]
      char, [last_seen | rest] = acc ->
        result =
          if char != last_seen &&
               (char == String.upcase(last_seen) || char == String.downcase(last_seen)) do
            rest
          else
            [char | acc]
          end
        result
    end)
    |> length()
  end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day5.txt") |> Day5.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day5.txt") |> Day5.part2()
# input = "dabAcCaCBAcCcaDA"
# r Day5; Day5.part2(input)
READ MORE
Day 4: Repose Record - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 4 challenge in Elixir! Parts one and two are as follows:
defmodule Day4_1 do
  # 1518-11-01 00:00
  @log_info ~r/\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.*)/
  @guard_entry ~r/Guard #(\d+) begins shift/
  def part1(input) do
    {_, _, guards} =
      input
      |> read_input()
      |> extract_logs()
    {guard_id, _time_asleep} = most_asleep(guards)
    {minute, _size} = get_most_asleep_minutes(guards[guard_id])
    minute * String.to_integer(guard_id)
  end
  def part2(input) do
    {_, _, guards} =
      input
      |> read_input()
      |> extract_logs()
    {guard_id, minute, _size} = most_times_asleep(guards)
    minute * String.to_integer(guard_id)
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
  def extract_logs(lines) do
    lines
    |> Enum.sort()
    |> Enum.map(fn line ->
      [_year, _month, _day, _hour, minute, message] =
        Regex.run(@log_info, line, capture: :all_but_first)
      case message do
        "falls asleep" ->
          {:sleep, String.to_integer(minute)}
        "wakes up" ->
          {:wake, String.to_integer(minute)}
        _ ->
          [guard_id] = Regex.run(@guard_entry, message, capture: :all_but_first)
          {:guard, guard_id}
      end
    end)
    |> Enum.reduce({nil, nil, %{}}, fn log, {current_guard_id, last_minute, guards} ->
      case log do
        {:guard, guard_id} ->
          {guard_id, nil, Map.put_new(guards, guard_id, [])}
        {:sleep, minute} ->
          {current_guard_id, minute, guards}
        {:wake, minute} ->
          new_range = for min <- last_minute..(minute - 1), do: min
          {current_guard_id, nil, Map.update!(guards, current_guard_id, &(&1 ++ new_range))}
      end
    end)
  end
  defp most_asleep(guards) do
    Enum.reduce(guards, {nil, 0}, fn {guard_id, sleep_range}, {_, current_bigger_time} = acc ->
      time_asleep = length(sleep_range)
      if time_asleep > current_bigger_time do
        {guard_id, time_asleep}
      else
        acc
      end
    end)
  end
  defp most_times_asleep(guards) do
    Enum.reduce(guards, {nil, 0, 0}, fn {guard_id, asleep_range},
                                        {_current_guard, _minute, max_size} = acc ->
      {minute, size} = get_most_asleep_minutes(asleep_range)
      if size > max_size do
        {guard_id, minute, size}
      else
        acc
      end
    end)
  end
  defp get_minutes_of(guard_intervals) do
    {asleep_range, []} =
      guard_intervals
      |> Enum.reduce({[], []}, fn
        {datetime, _}, {range, []} ->
          {range, [datetime.minute]}
        {datetime, _}, {range, [asleep_time]} ->
          new_range = for min <- asleep_time..(datetime.minute - 1), do: min
          {[new_range | range], []}
      end)
    {minute, _size} = get_most_asleep_minutes(asleep_range)
    minute
  end
  defp get_most_asleep_minutes(asleep_range) do
    asleep_range
    |> Enum.group_by(& &1)
    |> Enum.reduce({nil, 0}, fn {minute, occurrences}, {_, times} = acc ->
      size = length(occurrences)
      if size > times do
        {minute, size}
      else
        acc
      end
    end)
  end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part2()
READ MORE
Day 3: No matter how you slice it - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 3 challenge in Elixir! Parts one and two are as follows:
defmodule Day3 do
  @grid_info ~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/
  def part1(input) do
    {overlaps, _} =
      input
      |> read_input()
      |> extract_grid()
      |> build_map()
      |> Enum.reduce({MapSet.new(), MapSet.new()}, fn {x, y, _id}, {overlap, no_overlap} ->
        if MapSet.member?(no_overlap, {x, y}) do
          {MapSet.put(overlap, {x, y}), no_overlap}
        else
          {overlap, MapSet.put(no_overlap, {x, y})}
        end
      end)
    MapSet.size(overlaps)
  end
  def part2(input) do
    map =
      input
      |> read_input()
      |> extract_grid()
      |> build_keyed_map()
    {id, _} =
      for {id1, coordinates1} <- map,
          {id2, coordinates2} <- map,
          id1 != id2 do
        overlaps = MapSet.intersection(coordinates1, coordinates2)
        if MapSet.size(overlaps) != 0 do
          {id1, id2}
        else
          {id1, nil}
        end
      end
      |> Enum.group_by(fn {key, _} -> key end, fn {_, value} -> value end)
      |> Enum.find(fn {_key, overlaps} ->
        Enum.all?(overlaps, &Kernel.==(&1, nil))
      end)
    id
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
  defp extract_grid(lines) do
    Enum.map(lines, fn line ->
      [id, x, y, width, height] = Regex.run(@grid_info, line, capture: :all_but_first)
      [
        id,
        String.to_integer(x),
        String.to_integer(y),
        String.to_integer(width),
        String.to_integer(height)
      ]
    end)
  end
  defp build_map(grid) do
    Enum.flat_map(grid, fn [id, x, y, width, height] ->
      for x <- x..(x + width - 1),
          y <- y..(y + height - 1) do
        {x, y, id}
      end
    end)
  end
  defp build_keyed_map(grid) do
    Enum.reduce(grid, %{}, fn [id, x, y, width, height], acc ->
      coordinates =
        for x <- x..(x + width - 1),
            y <- y..(y + height - 1) do
          {x, y}
        end
      Map.put_new(acc, id, MapSet.new(coordinates))
    end)
  end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day3.txt") |> Day3.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day3.txt") |> Day3.part2()
 
READ MORE
Day 2: Inventory Management System - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 2 challenge in Elixir! Parts one and two are as follows:
defmodule Day2 do
  def checksum(input) do
    {two, three} =
      input
      |> read_input()
      |> Enum.reduce({0, 0}, fn line, {appears_two_times, appears_three_times} ->
        {two_times, three_times, _} =
          line
          |> String.graphemes()
          |> Enum.group_by(& &1)
          |> get_checksum_values()
        {appears_two_times + two_times, appears_three_times + three_times}
      end)
    two * three
  end
  def differ(input) do
    lines = input |> read_input()
    # length(diff) == 4 # [eq: "_", del: "_", ins: "_", eq: "_"]
    for line1 <- lines,
        line2 <- lines,
        line1 != line2,
        diff = String.myers_difference(line1, line2),
        length(diff) == 4 do
      diff
      |> Keyword.get_values(:eq)
      |> Enum.join()
    end
    |> Enum.uniq()
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
  defp get_checksum_values(groups) do
    Enum.reduce(groups, {0, 0, MapSet.new()}, fn {_key, chars},
                                                 {two_times, three_times, seen} = acc ->
      value = length(chars)
      if MapSet.member?(seen, value) do
        acc
      else
        new_seen = MapSet.put(seen, value)
        case value do
          2 -> {two_times + 1, three_times, new_seen}
          3 -> {two_times, three_times + 1, new_seen}
          _ -> {two_times, three_times, new_seen}
        end
      end
    end)
  end
end
:aoc2018 |> :code.priv_dir() |> Path.join("day2.txt") |> Day2.checksum()
:aoc2018 |> :code.priv_dir() |> Path.join("day2.txt") |> Day2.differ()
READ MORE
Day 1: Chronal Calibration - Advent of Code 2018
 
                                                
                                        
I did the Advent of Code 2018 day 1 challenge in Elixir! Parts one and two are as follows:
defmodule Day1 do
  def frequency(input) do
    input
    |> read_input()
    |> Enum.reduce(0, fn line, acc ->
      String.to_integer(line) + acc
    end)
  end
  def repeated_frequency(input) do
      input
      |> read_input()
      |> Stream.cycle()
      |> Enum.reduce_while({0, MapSet.new([0])}, fn line, {acc, seen} ->
        value = String.to_integer(line) + acc
        if MapSet.member?(seen, value) do
          {:halt, value}
        else
          {:cont, {value, MapSet.put(seen, value)}}
        end
      end)
  end
  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end
end
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.frequency()
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.repeated_frequency()
READ MORE




 
                                                
                                        