Skip to content

Instantly share code, notes, and snippets.

@cinoss
Last active January 24, 2024 03:24
Show Gist options
  • Save cinoss/6377989a12bbecf77fb86d337d3473d2 to your computer and use it in GitHub Desktop.
Save cinoss/6377989a12bbecf77fb86d337d3473d2 to your computer and use it in GitHub Desktop.

Yu-Gi-Oh! Forbidden Memories - Battle Rank

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

Section

import Kino
import Kino.Shorts
nothing()
defmodule FieldScore do
  def calc(field, x) when is_nil(x), do: calc(field, 0)

  def calc(:number_of_turns, x) when x >= 0 and x <= 4, do: +12
  def calc(:number_of_turns, x) when x >= 5 and x <= 8, do: +8
  def calc(:number_of_turns, x) when x >= 9 and x <= 28, do: +0
  def calc(:number_of_turns, x) when x >= 29 and x <= 32, do: -8
  def calc(:number_of_turns, x) when x >= 33, do: -12

  def calc(:effective_attacks, x) when x >= 0 and x <= 1, do: +4
  def calc(:effective_attacks, x) when x >= 2 and x <= 3, do: +2
  def calc(:effective_attacks, x) when x >= 4 and x <= 9, do: +0
  def calc(:effective_attacks, x) when x >= 10 and x <= 19, do: -2
  def calc(:effective_attacks, x) when x >= 20, do: -4

  def calc(:defensive_wins, x) when x >= 0 and x <= 1, do: +0
  def calc(:defensive_wins, x) when x >= 2 and x <= 5, do: -10
  def calc(:defensive_wins, x) when x >= 6 and x <= 9, do: -20
  def calc(:defensive_wins, x) when x >= 10 and x <= 14, do: -30
  def calc(:defensive_wins, x) when x >= 15, do: -40

  def calc(:face_down_plays, x) when x == 0, do: +0
  def calc(:face_down_plays, x) when x >= 1 and x <= 10, do: -2
  def calc(:face_down_plays, x) when x >= 11 and x <= 20, do: -4
  def calc(:face_down_plays, x) when x >= 21 and x <= 30, do: -6
  def calc(:face_down_plays, x) when x >= 31, do: -8

  def calc(:initiate_fusion, x) when x == 0, do: +4
  def calc(:initiate_fusion, x) when x >= 1 and x <= 4, do: +0
  def calc(:initiate_fusion, x) when x >= 5 and x <= 9, do: -4
  def calc(:initiate_fusion, x) when x >= 10 and x <= 14, do: -8
  def calc(:initiate_fusion, x) when x >= 15, do: -12

  def calc(:equip_magic, x) when x == 0, do: +4
  def calc(:equip_magic, x) when x >= 1 and x <= 4, do: +0
  def calc(:equip_magic, x) when x >= 5 and x <= 9, do: -4
  def calc(:equip_magic, x) when x >= 10 and x <= 14, do: -8
  def calc(:equip_magic, x) when x >= 15, do: -12

  def calc(:pure_magic, x) when x == 0, do: +2
  def calc(:pure_magic, x) when x >= 1 and x <= 3, do: -4
  def calc(:pure_magic, x) when x >= 4 and x <= 6, do: -8
  def calc(:pure_magic, x) when x >= 7 and x <= 9, do: -12
  def calc(:pure_magic, x) when x >= 10, do: -16

  def calc(:trigger_trap, x) when x == 0, do: +2
  def calc(:trigger_trap, x) when x >= 1 and x <= 2, do: -8
  def calc(:trigger_trap, x) when x >= 3 and x <= 4, do: -16
  def calc(:trigger_trap, x) when x >= 5 and x <= 6, do: -24
  def calc(:trigger_trap, x) when x >= 7, do: -32

  def calc(:cards_used, x) when x >= 0 and x <= 8, do: +15
  def calc(:cards_used, x) when x >= 9 and x <= 12, do: +12
  def calc(:cards_used, x) when x >= 13 and x <= 32, do: +0
  def calc(:cards_used, x) when x >= 33 and x <= 36, do: -5
  def calc(:cards_used, x) when x >= 37, do: -7

  def calc(:remaining_lp, x) when x >= 0 and x <= 99, do: -7
  def calc(:remaining_lp, x) when x >= 100 and x <= 999, do: -5
  def calc(:remaining_lp, x) when x >= 1000 and x <= 6999, do: +0
  def calc(:remaining_lp, x) when x >= 7000 and x <= 7999, do: +4
  def calc(:remaining_lp, x) when x >= 8000, do: +6
end

nothing()
fields = [
  # {:victory_condition, "Victory condition", 0},
  {:number_of_turns, "Number of turns", 0},
  {:effective_attacks, "Effective attacks", 0},
  {:defensive_wins, "Defensive wins", 0},
  {:face_down_plays, "Face-down plays", 0},
  {:initiate_fusion, "Initiate Fusion", 0},
  {:equip_magic, "Equip Magic", 0},
  {:pure_magic, "Pure Magic", 0},
  {:trigger_trap, "Trigger Trap", 0},
  {:cards_used, "Cards used", 0},
  {:remaining_lp, "Remaining LP", 8000}
]

settings = [debounce: 200]

inputs =
  Enum.map(fields, fn {field, label, default} ->
    {field, Kino.Input.number(label, [{:default, default} | settings])}
  end)

# submit = Kino.Control.button("Calculate")
input_frame = Kino.Frame.new()

Kino.Frame.render(
  input_frame,
  Kino.Layout.grid(
    [
      Kino.Layout.grid(Keyword.values(inputs), columns: 3)
      # submit
    ],
    gap: 16,
    boxed: true
  )
)

input_frame
import FieldScore

frame = Kino.Frame.new()

render = fn state ->
  get_field_value = fn field, default ->
    Map.get(state, field, default)
  end

  score =
    Enum.reduce(fields, 52, fn {field, _, default}, acc ->
      acc + calc(field, get_field_value.(field, default))
    end)

  rank =
    case score do
      x when x <= 9 -> {:technical, "S"}
      x when x >= 10 and x <= 19 -> {:technical, "A"}
      x when x >= 20 and x <= 29 -> {:technical, "B"}
      x when x >= 30 and x <= 39 -> {:technical, "C"}
      x when x >= 40 and x <= 49 -> {:technical, "D"}
      x when x >= 50 and x <= 59 -> {:power, "D"}
      x when x >= 60 and x <= 69 -> {:power, "C"}
      x when x >= 70 and x <= 79 -> {:power, "B"}
      x when x >= 80 and x <= 89 -> {:power, "A"}
      x when x >= 90 -> {:power, "S"}
    end

  rank_cat =
    rank
    |> elem(0)
    |> Atom.to_string()
    |> String.slice(0..2)
    |> String.upcase()

  content =
    """
    # Rank #{rank_cat}-#{elem(rank, 1)}

    Score: **#{score}**

    | Param | Value | Score |
    | ----- | ------ | ----- |
    """ <>
      (fields
       |> Enum.map(fn {field, label, default} ->
         value = get_field_value.(field, default)
         "| #{label} |#{value} | #{calc(field, value)} |"
       end)
       |> Enum.join("\n"))

  Kino.Frame.render(frame, Kino.Markdown.new(content))
end

initial =
  fields
  |> Enum.map(fn {field, _, _} -> {field, Kino.Input.read(inputs[field])} end)
  |> Enum.into(%{})

render.(initial)

inputs
# |> Keyword.put(:submit, submit)
|> Kino.Control.tagged_stream()
|> Kino.listen(initial, fn event, state ->
  case event do
    # {:submit, _} ->
    #   {:cont, state}

    {field, %{value: value}} ->
      state = Map.put(state, field, value)
      render.(state)
      {:cont, state}
  end
end)

frame
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment