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

Day 10

day10.livemd

Day 10

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

IEx.Helpers.c("/Users/johnb/dev/2015adventOfCode/advent_of_code.ex")
alias AdventOfCode, as: AOC
alias Kino.Input
require Integer
use Bitwise

# Note: when making the next template, something like this works well:
#   `cat day01.livemd | sed 's/01/02/' > day02.livemd`
#

Installation and Data

input_p1example = Kino.Input.textarea("Example Data")
input_p1puzzleInput = Kino.Input.textarea("Puzzle Input")
input_source_select =
  Kino.Input.select("Source", [{:example, "example"}, {:puzzle_input, "puzzle input"}])
p1data = fn ->
  (Kino.Input.read(input_source_select) == :example &&
     Kino.Input.read(input_p1example)) ||
    Kino.Input.read(input_p1puzzleInput)
end

Part 1

defmodule Day10 do

  def look_and_say(text) do
    text
    |> String.split("", trim: true)
    |> Enum.chunk_every(2, 1)
    |> Enum.reduce({1, []}, fn pair, {count, next_line} ->
      cond do
        Enum.count(pair) == 1 -> 
          (next_line ++ ["#{count}", List.first(pair)])
          |> Enum.join()
        List.first(pair) == List.last(pair) -> {count + 1, next_line}
        true -> {1, next_line ++ ["#{count}", List.first(pair)]}
      end
    end)
    # |> IO.inspect()
  end

  def solve1(text) do
    IO.inspect([String.length(text), text])

    Enum.reduce(1..40, text, fn iteration, acc ->
      str = look_and_say(acc)
      IO.inspect([iteration, Time.utc_now(), String.length(str)])
      str
    end)
    # |> IO.inspect()
    |> String.length()
  end
  
  def solve2(text) do
    # Switch to a regex to make it much much faster
    #.  https://stackoverflow.com/questions/47402863/regex-to-match-number-with-different-digits-and-minimum-length
    Enum.reduce(1..50, text, fn iteration, acc ->
      str = Regex.scan(~r/(\d)\1*(?!\1)/, acc) 
        |> Enum.map(fn [match, char] -> 
          "#{String.length(match)}#{char}" 
        end) 
        |> Enum.join()
      
      IO.inspect([iteration, Time.utc_now(), String.length(str)])
      str 
    end) 
    |> String.length()
  end
end

# Example data:
# 1
# 11
# 21
# 1211
# 111221
# 312211

# p1data.()
# |> Day10.solve1()
# |> IO.inspect(label: "\n*** Part 1 solution (example: 6 for 5 iterations, 82350 for 40 iterations)")
# 492982 after ~20 min 

p1data.()
|> Day10.solve2()
|> IO.inspect(label: "\n*** Part 2 solution (example: 2)")
# 50 iterations... 6989950 in less than a minute