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

Aoc 2019 - day 13

2019/elixir/day-13.livemd

Aoc 2019 - day 13

Mix.install([
  {:int_code, path: "~/workspace/study/languages/elixir-practices/aoc/2019/int_code"},
  {:kino, "~> 0.6.1"}
])

Setup

input = Kino.Input.textarea("input")

Part 1

init_data =
  input
  |> Kino.Input.read()
  |> String.split(",", trim: true)
  |> Enum.map(&String.to_integer/1)
  |> Enum.with_index()
  |> Map.new(fn {v, k} -> {k, v} end)
{%{outputs: outputs}, :halt} = IntCode.Computer.process(init_data, [])
outputs
|> Enum.reverse()
|> Enum.chunk_every(3)
|> Enum.filter(fn [_x, _y, t] -> t == 2 end)
# |> IO.inspect(limit: :infinity)
|> Enum.count()

Part 2

  1. 메모리 0에 2
  2. 조이스틱으로 paddle 조정 - input은 언제 받는지? 3.
frame = Kino.Frame.new()
Kino.configure(inspect: [pretty: true])
Kino.Frame.render(frame, IO.puts(["a", "b"]))
defmodule Game do
  defstruct board: %{}, cur_ball: nil, cur_paddle: nil, memory: nil, score: nil

  def init(init_data) do
    init_data
    |> put_coin()
    |> IntCode.Computer.init_state()
    |> then(&%__MODULE__{memory: &1})
  end

  defp put_coin(data), do: Map.put(data, 0, 2)

  def update_state(%__MODULE__{} = state) do
    {board, cur_ball, cur_paddle} = board_info(state.memory.outputs)
    board = Map.merge(state.board, board)
    score = board[{-1, 0}]

    %{
      state
      | board: board,
        cur_ball: cur_ball || state.cur_ball,
        cur_paddle: cur_paddle || state.cur_paddle,
        score: score
    }
  end

  def play(%__MODULE__{} = state, frame \\ nil) do
    input = determine_joystick(state.cur_ball, state.cur_paddle)

    case IntCode.Computer.process(state.memory, input) do
      {memory, :hold} ->
        state
        |> Map.put(:memory, memory)
        |> update_state()
        |> tap(&draw(&1, frame))
        |> play(frame)

      {memory, :halt} ->
        state
        |> Map.put(:memory, memory)
        |> update_state()
        |> tap(&draw(&1, frame))
    end
  end

  defp draw(_state, nil), do: :ok

  defp draw(state, frame) do
    Drawer.draw_board(state.board, frame)
    Process.sleep(50)
  end

  defp determine_joystick(nil, nil), do: [0]

  defp determine_joystick({bx, _y} = _cur_ball, {px, _} = _cur_paddle) do
    cond do
      bx == px -> [0]
      bx > px -> [1]
      true -> [-1]
    end
  end

  defp board_info(outputs) do
    outputs
    |> Enum.reverse()
    |> Enum.chunk_every(3)
    |> Enum.reduce({%{}, nil, nil}, fn
      [x, y, 4], {grid, _cur_ball, cur_pad} ->
        {Map.put(grid, {x, y}, 4), {x, y}, cur_pad}

      [x, y, 3], {grid, cur_ball, _cur_pad} ->
        {Map.put(grid, {x, y}, 3), cur_ball, {x, y}}

      [x, y, t], {grid, cur_ball, cur_pad} ->
        {Map.put(grid, {x, y}, t), cur_ball, cur_pad}
    end)
  end
end
defmodule Drawer do
  def draw_board(board, frame \\ Kino.Frame.new()) do
    board
    |> Enum.reject(&match?({{-1, _}, _}, &1))
    |> Enum.sort_by(fn {{x, y}, _t} -> {y, x} end)
    |> Enum.chunk_by(fn {{_x, y}, _t} -> y end)
    |> Enum.map_join(
      "
"
, &amp;Enum.map_join(&amp;1, "", fn {_, 0} -> " " {_, 1} -> "🟫" {_, 2} -> "🟦" {_, 3} -> "🀵" {_, 4} -> "🥎" end) ) |> Kernel.<>("
**score:
#{board[{-1, 0}]}**") |> then(&amp;Kino.Frame.render(frame, Kino.Markdown.new(&amp;1))) end end
state =
  Game.init(init_data)
  |> Game.play()
state.score

Draw

⬛⬛⬛⬛⬛⬛⬛ ⬛⬛⬛

⬛⬛⬛⬛⬛

frame = Kino.Frame.new()
Drawer.draw_board(state.board, frame)
Game.init(init_data) |> Game.play(frame)