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

Day 17 - part1

day17-part1.livemd

Day 17 - part1

Mix.install([{:kino, "~> 0.5.0"}])

Section

input = Kino.Input.textarea("paste input here:")
jets = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>"
jets = input |> Kino.Input.read() |> String.trim()
blocks = [
  [{0, 0}, {1, 0}, {2, 0}, {3, 0}],
  [{1, 0}, {0, 1}, {1, 1}, {2, 1}, {1, 2}],
  [{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}],
  [{0, 0}, {0, 1}, {0, 2}, {0, 3}],
  [{0, 0}, {1, 0}, {0, 1}, {1, 1}]
]
defmodule Tetris do
  def height(tower) do
    tower
    |> Enum.map(&amp;elem(&amp;1, 1))
    |> Enum.max(&amp;>=/2, fn -> 0 end)
    |> Kernel.+(1)
  end

  def pprint({bx, by}, block, tower) do
    for y <- max(height(tower), by + 4)..0 do
      for x <- 0..6 do
        cond do
          MapSet.member?(tower, {x, y}) -> ?#
          {x - bx, y - by} in block -> ?@
          true -> ?\s
        end
      end
      |> then(&amp;('|' ++ &amp;1 ++ '|'))
      |> IO.puts()
    end

    IO.puts('+-------+')
  end

  def free?({x, y}, block, tower) do
    for {dx, dy} <- block do
      {bx, by} = {x + dx, y + dy}

      not MapSet.member?(tower, {bx, by}) and
        bx >= 0 and bx < 7 and
        by >= 0
    end
    |> Enum.all?()
  end

  def add_block({x, y}, block, tower) do
    for {bx, by} <- block, reduce: tower do
      tower ->
        MapSet.put(tower, {x + bx, y + by})
    end
  end

  def move(_, {_, _, _, counter}) when counter == 2022 do
    {:halt, nil}
  end

  def move(jet, {tower, {x, y}, [block | blocks], counter}) do
    dx = if jet == ?>, do: 1, else: -1

    {x, y} =
      if free?({x + dx, y}, block, tower) do
        {x + dx, y}
      else
        {x, y}
      end

    if(free?({x, y - 1}, block, tower)) do
      {
        [height(tower)],
        {tower, {x, y - 1}, [block | blocks], counter}
      }
    else
      tower = add_block({x, y}, block, tower)
      height = height(tower)

      {
        [height],
        {
          tower,
          {2, height + 3},
          blocks ++ [block],
          counter + 1
        }
      }
    end
  end
end
jets
|> to_charlist()
|> Stream.cycle()
|> Stream.transform({MapSet.new(), {2, 3}, blocks, 0}, &amp;Tetris.move/2)
|> Enum.at(-1)