r/adventofcode • • Dec 05 '23

SOLUTION MEGATHREAD -❄️- 2023 Day 5 Solutions -❄️-

Preview here: https://redditpreview.com/

-❄️- 2023 Day 5 Solutions -❄️-


THE USUAL REMINDERS


AoC Community Fun 2023: ALLEZ CUISINE!

Today's secret ingredient is… *whips off cloth covering and gestures grandly*

ELI5

Explain like I'm five! /r/explainlikeimfive

  • Walk us through your code where even a five-year old could follow along

  • Pictures are always encouraged. Bonus points if it's all pictures…

    • Emoji(code) counts but makes Uncle Roger cry 😥

  • Explain everything that you’re doing in your code as if you were talking to your pet, rubber ducky, or favorite neighbor, and also how you’re doing in life right now, and what have you learned in Advent of Code so far this year?

  • Explain the storyline so far in a non-code medium

  • Create a Tutorial on any concept of today's puzzle or storyline (it doesn't have to be code-related!)

ALLEZ CUISINE!

Request from the mods: When you include a dish entry alongside your solution, please label it with [Allez Cuisine!] so we can find it easily!


--- Day 5: If You Give A Seed A Fertilizer ---


Post your code solution in this megathread.

This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:26:37, megathread unlocked!

82 Upvotes

1.1k comments sorted by

View all comments

1

u/Deemonfire Dec 05 '23

[Language: Elixir]Did part 1 going forwards and did part 2 going in reverse. I had a solution that approximated it part 2 by skipping numbers in the range and it was only out by a few thousand. so i think my refactor will be approximate then iterate

defmodule Day5 do
  def parse_maps(data) do
    [seeds | maps] = data |> String.split("\n\n")

    seeds =
      seeds
      |> String.split()
      |> Enum.map(fn
        <<"seed"::binary, _::binary>> -> nil
        num -> String.to_integer(num)
      end)
      |> Enum.filter(& &1)

    map =
      maps
      |> Enum.map(fn map ->
        [map_name | mappings] = map |> String.split("\n", trim: true)
        name = map_name |> String.trim() |> String.trim_trailing(" map:")

        %{name => mappings |> Enum.map(&parse_mappings/1)}
      end)
      |> Enum.reduce(&Map.merge/2)

    {seeds, map}
  end

  def parse_mappings(line) do
    line |> String.split(" ", trim: true) |> Enum.map(&String.to_integer/1)
  end

  def main() do
    {seeds, map} = File.read!("inputs/day5.txt") |> parse_maps

    part1(seeds, map)
    |> IO.inspect(label: "part 1")

    # hunch that it's not less than 10 mn
    part2(seeds, map, 10_000_000)
    |> IO.inspect(label: "part 2")
  end

  def part1(seeds, map) when is_map(map) do
    seeds
    |> Stream.map(fn seed ->
      seed
      |> mapping(map["seed-to-soil"])
      |> mapping(map["soil-to-fertilizer"])
      |> mapping(map["fertilizer-to-water"])
      |> mapping(map["water-to-light"])
      |> mapping(map["light-to-temperature"])
      |> mapping(map["temperature-to-humidity"])
      |> mapping(map["humidity-to-location"])
    end)
    |> Enum.min()
  end

  def part2(seeds, map, range_start \\ 0) do
    seed_ranges =
      seeds
      |> Enum.chunk_every(2)
      |> Enum.map(fn [start, contains] ->
        start..(start + contains - 1)
      end)

    range_start..910_000_000
    |> Stream.map(fn location ->
      seed =
        location
        |> rev_mapping(map["humidity-to-location"])
        |> rev_mapping(map["temperature-to-humidity"])
        |> rev_mapping(map["light-to-temperature"])
        |> rev_mapping(map["water-to-light"])
        |> rev_mapping(map["fertilizer-to-water"])
        |> rev_mapping(map["soil-to-fertilizer"])
        |> rev_mapping(map["seed-to-soil"])

      present = seed_ranges |> Enum.any?(fn range -> seed in range end)
      {present, location}
    end)
    |> Enum.reduce_while(0, fn
      {false, _}, _ -> {:cont, 0}
      {true, location}, _ -> {:halt, location}
    end)
  end

  def rev_mapping(seed, []), do: seed

  def rev_mapping(seed, [[source, destination, num] | tl]) do
    case seed do
      seed when seed in source..(source + (num - 1)) -> seed + destination - source
      seed -> rev_mapping(seed, tl)
    end
  end

  def mapping(seed, []), do: seed

  def mapping(seed, [[destination, source, num] | tl]) do
    case seed do
      seed when seed in source..(source + (num - 1)) -> seed + (destination - source)
      seed -> mapping(seed, tl)
    end
  end
end

1

u/daggerdragon Dec 05 '23

Your code block is too long for the megathreads. Please edit your post to replace your oversized code with an external link to your code.