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

Day 20

day20.livemd

Day 20

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

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

# 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 Day20 do
  @presents_per_elf 10
  @presents_per_elf_part2 11
  
  # factors_of/1 cribbed from:
  #   https://github.com/tajacks/elixir-multitool/blob/main/lib/multitool/numbers/factors.ex
  def factors_of(n) when is_integer(n) do
    upper_range = floor(:math.sqrt(n))
    factors = for x <- 1..upper_range, rem(n, x) == 0, do: [x, div(n, x)]
    List.flatten(factors) |> Enum.dedup()
  end

  def solve1(text) do
    target = String.to_integer(text) / @presents_per_elf
    t_over_e = floor(target / Math.e())
    factors = factors_of(t_over_e)
    IO.inspect([target, Math.log(target), t_over_e, Enum.sum(factors)])

    Enum.each(floor(t_over_e / 2)..(2 * t_over_e), fn house_num ->
      factors = factors_of(house_num)
      factor_sum = Enum.sum(factors)
      if factor_sum >= target do
        IO.puts("SUCCESS! house_num=#{house_num}")
        raise String
      end
    end)
  end

  def solve2(text) do
    target = ceil(String.to_integer(text) / @presents_per_elf_part2)
    part1_answer = 831600

    Enum.each(part1_answer..(2 * part1_answer), fn guess ->
      presents = (guess
        |> factors_of()
        |> Enum.reject(fn x -> x < guess / 50 end)
        |> Enum.sum()
      )
      if presents >= target do
        IO.inspect([target, guess, presents], label: "Success at #{guess}!")
        raise Integer
      end
    end)
  end
end

# Example data:

# p1data.()
# |> Day20.solve1()
# |> IO.inspect(label: "\n*** Part 1 solution (example: 2)")
# 831600

p1data.()
|> Day20.solve2()
|> IO.inspect(label: "\n*** Part 2 solution (example: 2)")
# 776160 is too low
# 856800 is also too low