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

Day 18

day18.livemd

Day 18

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

# 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

Solution

defmodule Day18 do
  @on "#"
  @off "."

  def count_on_cells(grid, cell_ids) do
    cell_ids
    |> Enum.filter(fn cell_id -> grid[cell_id] == @on end)
    |> Enum.count()
  end
  
  def live_or_die?(grid, cell_id) do
    cell = grid[cell_id]
    neighbor_ids = AOC.neighbors8(grid, cell_id)
    on_count = count_on_cells(grid, neighbor_ids)

    case {cell, on_count} do
      {@on, 2} -> @on
      {@on, 3} -> @on
      {@off, 3} -> @on
      _ -> @off
    end
  end

  def iterate_life(grid) do
    grid
    |> AOC.grid_cells()
    |> Enum.reduce(grid, fn cell_id, acc ->
      Map.put(acc, cell_id, live_or_die?(grid, cell_id))
    end)
  end

  def solve1(text) do
    grid = AOC.as_grid(text)
    steps = (grid.grid_width < 20) &amp;&amp; 4 || 100

    updated = Enum.reduce((1..steps), grid, fn step, acc ->
        acc = iterate_life(acc)
        # IO.puts("=== #{step}")
        # IO.puts(AOC.to_text_grid(acc))
        acc
      end)

    count_on_cells(updated, AOC.grid_cells(updated))
  end

  def corners_stuck_on(grid) do
    grid
    |> Map.put(0, @on)
    |> Map.put(grid.grid_width - 1, @on)
    |> Map.put(grid.last_cell - grid.grid_width + 1, @on)
    |> Map.put(grid.last_cell, @on)
  end

  def solve2(text) do
    grid = text
      |> AOC.as_grid()
      |> corners_stuck_on()
    steps = (grid.grid_width < 20) &amp;&amp; 5 || 100

    # IO.puts("=== 0\n#{AOC.to_text_grid(grid)}")
    updated = (1..steps)
      |> Enum.reduce(grid, fn step, acc ->
        acc = acc
          |> iterate_life()
          |> corners_stuck_on()
        # IO.puts("=== #{step}")
        # IO.puts(AOC.to_text_grid(acc))
        acc
      end)
      |> corners_stuck_on()

    count_on_cells(updated, AOC.grid_cells(updated))
  end
end

# Example data:
# .#.#.#
# ...##.
# #....#
# ..#...
# #.#..#
# ####..

p1data.()
|> Day18.solve1()
|> IO.inspect(label: "\n*** Part 1 solution (example: 4)")
# 1061

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