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

2023-06

2023-06.livemd

2023-06

Mix.install([
  {:benchee, "~> 1.2"},
  {:kino, "~> 0.11.0"},
  {:kino_aoc, "~> 0.1.5"}
])

Problem

{:ok, input} = KinoAOC.download_puzzle("2023", "6", System.fetch_env!("LB_AOC_SESSION"))
{:ok, "Time:        40     82     91     66\nDistance:   277   1338   1349   1063"}

Solvers

defmodule PartOne do
  @doc ~S"""
      iex> PartOne.parse("Time:      7  15   30\nDistance:  9  40  200")
      [{7,9},{15,40},{30,200}]
  """
  def parse(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(&String.split(&1, ~r/:\s+/, parts: 2))
    |> Enum.map(fn [_label, nums] ->
      nums |> String.split() |> Enum.map(&String.to_integer/1)
    end)
    |> Enum.zip()
  end

  def process(input) do
    input
    |> Enum.map(fn {time, previous_best} ->
      Enum.count(0..time, fn hold ->
        distance = (time - hold) * hold
        distance > previous_best
      end)
    end)
    |> Enum.product()
  end

  def solve(input) do
    input
    |> parse()
    |> process()
  end
end
{:module, PartOne, <<70, 79, 82, 49, 0, 0, 13, ...>>, {:solve, 1}}
defmodule PartTwo do
  def parse(input) do
    [distance, time] =
      ~r/^Time:\s+(?(\d|\s)*)\nDistance:\s+(?(\d|\s)*)$/
      |> Regex.run(input, capture: :all_names)

    distance = collapse_number(distance)
    time = collapse_number(time)
    {distance, time}
  end

  def process({distance, time}) do
    for hold <- 0..time,
        new_dist = (time - hold) * hold,
        new_dist > distance,
        reduce: 0 do
      acc -> acc + 1
    end
  end

  def solve(input) do
    input
    |> parse()
    |> process()
  end

  defp collapse_number(s) do
    s |> String.split() |> Enum.join("") |> String.to_integer()
  end
end
{:module, PartTwo, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:collapse_number, 1}}

Solutions

PartOne.solve(input)
505494
PartTwo.solve(input)
23632299

Tests

ExUnit.start(auto_run: false, seed: 12345, timeout: 5000)

defmodule PartOneTest do
  use ExUnit.Case, async: true

  doctest PartOne

  describe "Part One" do
    @test_input """
    Time:      7  15   30
    Distance:  9  40  200
    """
    test "counts ways to win" do
      assert PartOne.solve(@test_input) == 288
    end
  end
end

defmodule PartTwoTest do
  use ExUnit.Case, async: true

  doctest PartOne

  describe "Part Two" do
    @test_input """
    Time:      7  15   30
    Distance:  9  40  200
    """
    test "counts ways to win single race" do
      assert PartTwo.solve(@test_input) == 71503
    end
  end
end

ExUnit.run()
....
Finished in 0.00 seconds (0.00s async, 0.00s sync)
2 doctests, 2 tests, 0 failures

Randomized with seed 12345
%{total: 4, skipped: 0, failures: 0, excluded: 0}

Golfing

Benchmarks

Benchee.run(
  %{
    "PartOne" => &amp;PartOne.solve/1,
    "PartTwo" => &amp;PartTwo.solve/1
  },
  inputs: %{
    input: input,
    test_input: """
    Time:      7  15   30
    Distance:  9  40  200
    """
  },
  warmup: 2,
  time: 3,
  memory_time: 3,
  reduction_time: 3
)
Operating System: Linux
CPU Information: AMD Ryzen 9 5950X 16-Core Processor
Number of Available Cores: 32
Available memory: 62.71 GB
Elixir 1.15.7
Erlang 26.1.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 3 s
memory time: 3 s
reduction time: 3 s
parallel: 1
inputs: input, test_input
Estimated total run time: 44 s

Benchmarking PartOne with input input ...
Benchmarking PartOne with input test_input ...
Benchmarking PartTwo with input input ...
Benchmarking PartTwo with input test_input ...

##### With input input #####
Name              ips        average  deviation         median         99th %
PartOne       72.74 K      0.0137 ms    ±26.40%      0.0136 ms      0.0178 ms
PartTwo     0.00324 K      308.49 ms     ±0.69%      307.75 ms      314.30 ms

Comparison: 
PartOne       72.74 K
PartTwo     0.00324 K - 22438.17x slower +308.48 ms

Memory usage statistics:

Name       Memory usage
PartOne         3.10 KB
PartTwo         0.74 KB - 0.24x memory usage -2.35938 KB

**All measurements for memory usage were the same**

Reduction count statistics:

Name    Reduction count
PartOne       0.00159 M
PartTwo        102.07 M - 64156.53x reduction count +102.07 M

**All measurements for reduction count were the same**

##### With input test_input #####
Name              ips        average  deviation         median         99th %
PartOne       87.79 K       11.39 μs    ±24.11%       11.16 μs       19.92 μs
PartTwo        1.78 K      562.17 μs     ±4.82%      556.85 μs      720.72 μs

Comparison: 
PartOne       87.79 K
PartTwo        1.78 K - 49.36x slower +550.78 μs

Memory usage statistics:

Name       Memory usage
PartOne         2.64 KB
PartTwo         0.77 KB - 0.29x memory usage -1.87500 KB

**All measurements for memory usage were the same**

Reduction count statistics:

Name    Reduction count
PartOne          0.52 K
PartTwo        178.92 K - 341.46x reduction count +178.40 K

**All measurements for reduction count were the same**
%Benchee.Suite{
  system: %{
    erlang: "26.1.2",
    os: :Linux,
    elixir: "1.15.7",
    available_memory: "62.71 GB",
    cpu_speed: "AMD Ryzen 9 5950X 16-Core Processor",
    num_cores: 32
  },
  configuration: %Benchee.Configuration{
    parallel: 1,
    time: 3000000000.0,
    warmup: 2000000000.0,
    memory_time: 3000000000.0,
    reduction_time: 3000000000.0,
    pre_check: false,
    formatters: [Benchee.Formatters.Console],
    percentiles: ~c"2c",
    print: %{configuration: true, benchmarking: true, fast_warning: true},
    inputs: [
      {"input", "Time:        40     82     91     66\nDistance:   277   1338   1349   1063"},
      {"test_input", "Time:      7  15   30\nDistance:  9  40  200\n"}
    ],
    save: false,
    load: false,
    unit_scaling: :best,
    assigns: %{},
    before_each: nil,
    after_each: nil,
    before_scenario: nil,
    after_scenario: nil,
    measure_function_call_overhead: false,
    title: nil,
    profile_after: false
  },
  scenarios: [
    %Benchee.Scenario{
      name: "PartOne",
      job_name: "PartOne",
      function: &PartOne.solve/1,
      input_name: "input",
      input: "Time:        40     82     91     66\nDistance:   277   1338   1349   1063",
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 13748.504690221274,
          ips: 72735.18266399235,
          std_dev: 3629.2035066354165,
          std_dev_ratio: 0.2639707799799286,
          std_dev_ips: 19199.962899796643,
          median: 13550.0,
          percentiles: %{50 => 13550.0, 99 => 17830.0},
          mode: 13540,
          minimum: 13330,
          maximum: 1340254,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 214169
        },
        samples: [25820, 14811, 26950, 15190, 21530, 15791, 28960, 21710, 14280, 20210, 14101,
         18970, 15030, 14870, 14010, 14841, 14180, 14020, 13960, 15680, 14130, 13950, 13921, 14070,
         15650, 15780, 14850, 14150, 14781, 14090, 13950, 13980, 15100, ...]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 3176.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 3176.0,
          percentiles: %{50 => 3176.0, 99 => 3176.0},
          mode: 3176,
          minimum: 3176,
          maximum: 3176,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 93715
        },
        samples: [3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176,
         3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176,
         3176, 3176, 3176, 3176, ...]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 1591.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 1591.0,
          percentiles: %{50 => 1591.0, 99 => 1591.0},
          mode: 1591,
          minimum: 1591,
          maximum: 1591,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 32377
        },
        samples: [1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591,
         1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591,
         1591, 1591, 1591, ...]
      }
    },
    %Benchee.Scenario{
      name: "PartTwo",
      job_name: "PartTwo",
      function: &PartTwo.solve/1,
      input_name: "input",
      input: "Time:        40     82     91     66\nDistance:   277   1338   1349   1063",
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 308491230.7,
          ips: 3.241583229872991,
          std_dev: 2140555.4427733654,
          std_dev_ratio: 0.006938788625907496,
          std_dev_ips: 0.022492660845375198,
          median: 307754029.5,
          percentiles: %{50 => 307754029.5, 99 => 314304011.0},
          mode: nil,
          minimum: 307021015,
          maximum: 314304011,
          relative_more: 22438.166015204304,
          relative_less: 4.456692223965145e-5,
          absolute_difference: 308477482.19530976,
          sample_size: 10
        },
        samples: [307021015, 307399118, 307859122, 308390188, 314304011, 309237815, 307280934,
         307648937, 307553856, 308217311]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 760.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 760.0,
          percentiles: %{50 => 760.0, 99 => 760.0},
          mode: 760,
          minimum: 760,
          maximum: 760,
          relative_more: 0.23929471032745592,
          relative_less: 4.178947368421053,
          absolute_difference: -2416.0,
          sample_size: 10
        },
        samples: [760, 760, 760, 760, 760, 760, 760, 760, 760, 760]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 102073037.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 102073037.0,
          percentiles: %{50 => 102073037.0, 99 => 102073037.0},
          mode: 102073037,
          minimum: 102073037,
          maximum: 102073037,
          relative_more: 64156.52859836581,
          relative_less: 1.5586878246798907e-5,
          absolute_difference: 102071446.0,
          sample_size: 10
        },
        samples: [102073037, 102073037, 102073037, 102073037, 102073037, 102073037, 102073037,
         102073037, 102073037, 102073037]
      }
    },
    %Benchee.Scenario{
      name: "PartOne",
      job_name: "PartOne",
      function: &PartOne.solve/1,
      input_name: "test_input",
      input: "Time:      7  15   30\nDistance:  9  40  200\n",
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 11390.20788310508,
          ips: 87794.71018112713,
          std_dev: 2746.6531865007623,
          std_dev_ratio: 0.24114162047690374,
          std_dev_ips: 21170.958682377113,
          median: 11160.0,
          percentiles: %{50 => 11160.0, 99 => 19924.329999999958},
          mode: 11150,
          minimum: 10960,
          maximum: 931501,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 257462
        },
        samples: [23420, 15650, 12110, 17411, 11930, 11850, 14890, 12520, 13460, 11930, 13101,
         11870, 13230, 15210, 12400, 13770, 11890, 12991, 12180, 11830, 11780, 13440, 12100, 11850,
         11811, 11780, 11740, 13580, 12930, 12000, 15410, ...]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 2704.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 2704.0,
          percentiles: %{50 => 2704.0, 99 => 2704.0},
          mode: 2704,
          minimum: 2704,
          maximum: 2704,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 107851
        },
        samples: [2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704,
         2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704, 2704,
         2704, 2704, ...]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 524.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 524.0,
          percentiles: %{50 => 524.0, 99 => 524.0},
          mode: 524,
          minimum: 524,
          maximum: 524,
          relative_more: nil,
          relative_less: nil,
          absolute_difference: nil,
          sample_size: 33550
        },
        samples: [524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524,
         524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, 524, ...]
      }
    },
    %Benchee.Scenario{
      name: "PartTwo",
      job_name: "PartTwo",
      function: &PartTwo.solve/1,
      input_name: "test_input",
      input: "Time:      7  15   30\nDistance:  9  40  200\n",
      before_each: nil,
      after_each: nil,
      before_scenario: nil,
      after_scenario: nil,
      tag: nil,
      run_time_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 562169.6537307836,
          ips: 1778.8224486391223,
          std_dev: 27118.01888522485,
          std_dev_ratio: 0.04823814075565763,
          std_dev_ips: 85.80708765677755,
          median: 556846.0,
          percentiles: %{50 => 556846.0, 99 => 720718.0},
          mode: [557886, 554886],
          minimum: 541446,
          maximum: 772308,
          relative_more: 49.355521821918735,
          relative_less: 0.020261157477133612,
          absolute_difference: 550779.4458476786,
          sample_size: 5334
        },
        samples: [560166, 557966, 562076, 561596, 554756, 557666, 554986, 560576, 554676, 560986,
         561816, 557496, 557896, 556046, 568606, 562586, 557576, 556156, 557235, 557756, 554416,
         556936, 554536, 557386, 553846, 557156, 555116, 557726, 559376, 554716, ...]
      },
      memory_usage_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 784.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 784.0,
          percentiles: %{50 => 784.0, 99 => 784.0},
          mode: 784,
          minimum: 784,
          maximum: 784,
          relative_more: 0.28994082840236685,
          relative_less: 3.4489795918367347,
          absolute_difference: -1920.0,
          sample_size: 5251
        },
        samples: [784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784,
         784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, ...]
      },
      reductions_data: %Benchee.CollectionData{
        statistics: %Benchee.Statistics{
          average: 178924.0,
          ips: nil,
          std_dev: 0.0,
          std_dev_ratio: 0.0,
          std_dev_ips: nil,
          median: 178924.0,
          percentiles: %{50 => 178924.0, 99 => 178924.0},
          mode: 178924,
          minimum: 178924,
          maximum: 178924,
          relative_more: 341.4580152671756,
          relative_less: 0.002928617737139791,
          absolute_difference: 178400.0,
          sample_size: 5286
        },
        samples: [178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924,
         178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924, 178924,
         178924, 178924, 178924, 178924, 178924, 178924, 178924, ...]
      }
    }
  ]
}

Failures

Sometimes my ideas don’t work out.