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.7.0"}
])

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

# Note: when making the next template, something like this works well:
#   `cat day04.livemd | sed 's/03/04/' > day04.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
  def dest_names(dest) do
    String.split(dest, ", ", trim: true)
  end

  def src_module("%" <> name, dest_names) do
    %{
      name: name,
      type: :flip_flop,
      value: :off,
      dests: dest_names,
      trigger: nil,
      action: fn acc, pulse_dir, me -> nq_pulse(acc, :low, me.dests) end
    }
  end

  def src_module("&" <> name, dest_names) do
    %{
      name: name,
      type: :conjunction,
      value:
        Enum.reduce(dest_names, %{}, fn name, acc ->
          Map.put(acc, name, :low)
        end),
      dests: dest_names,
      trigger: nil,
      # fn acc, _pulse_dir, me,  -> nq_pulse(acc, :low, me.dests) end
      action: nil
    }
  end

  def src_module(name, dest_names) do
    %{
      name: name,
      type: :broadcast,
      value: :off,
      dests: dest_names,
      trigger: nil,
      # fn acc, _pulse_dir, me,  -> nq_pulse(acc, :low, me.dests) end
      action: nil
    }
  end

  def enqueue_pulse(config, pulse_dir, module_name_or_names) do
    module_name_or_names
    |> List.wrap()
    |> Enum.reduce(config, fn module_name, acc ->
      qqq = :queue.in({pulse_dir, module_name}, config.controls.qqq)
      put_in(acc, [:contols, :qqq], qqq)
    end)
  end

  @total_button_pushes 1000

  def process_entire_queue(config, times \\ 1) do
    Stream.cycle([1, 2])
    |> Enum.reduce_while(config, fn _x, acc ->
      {item, qqq} = :queue.out(acc.controls.qqq)

      case item do
        :empty ->
          {:halt, acc}

        {:value, {pulse_dir, module_name}} ->
          {:cont, "zzzzz"}
      end
    end)
  end

  @button_module %{
    name: :button,
    type: :poke,
    value: :off,
    dests: ["broadcast"],
    trigger: nil,
    action: fn acc, _pulse_dir, me -> enqueue_pulse(acc, :low, me.dests) end
  }

  def solve(text) do
    acc_template = %{
      data: %{"@button_module" => @button_module},
      controls: %{
        button_pushes: 0,
        low_pulses: 0,
        high_pulses: 0,
        # from https://blog.jola.dev/erlang-queue-module-elixir
        # examples:
        #  qqq = :queue.in("b", qqq)
        #  {{:value, value3}, qqq} = :queue.out(qqq)
        # . {:empty, {[], []}}
        qqq: :queue.new()
      }
    }

    config =
      text
      |> AOC.as_single_lines()
      |> Enum.reduce(acc_template, fn line, acc ->
        [src, dests] = String.split(line, " -> ", trim: true)
        src = src_module(src, dest_names(dests))

        put_in(acc, [:data, src.name], src)
      end)

    config
    |> IO.inspect("before pressing")
    |> enqueue_pulse(:_push, @button_module)
    |> IO.inspect("after pressing")
    |> process_entire_queue()
  end

  def solve2(text) do
    text
  end
end

p1data.()
|> Day20.solve()
|> IO.inspect(label: "\n*** Part 1 solution (example: 11687500)")

#

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

#