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

Day 22: Wizard Simulator 20XX

day_22_wizard_simulator_20xx.livemd

Day 22: Wizard Simulator 20XX

Section

defmodule Game do
  def apply_effects(ph, pa, pm, ps, pp, pr, bh, bd, turn) do
    pa = if ps > 0, do: pa + 7, else: pa
    ps = if ps > 0, do: ps - 1, else: ps

    bh = if pp > 0, do: bh - 3, else: bh
    pp = if pp > 0, do: pp - 1, else: pp

    pm = if pr > 0, do: pm + 101, else: pm
    pr = if pr > 0, do: pr - 1, else: pr

    {ph, pa, pm, ps, pp, pr, bh, bd, turn}
  end

  def play(ph, pa, pm, ps, pp, pr, bh, bd, turn) do
    q = [{ph, pa, pm, ps, pp, pr, bh, bd, turn, 0}]
    min_spent = :infinity

    process_queue(q, min_spent)
  end

  defp process_queue([], min_spent), do: min_spent

  defp process_queue([{ph, _pa, pm, ps, pp, pr, bh, bd, turn, spent} | rest], min_spent) do
    if spent > min_spent do
      process_queue(rest, min_spent)
    else
      pa = 0
      {ph, pa, pm, ps, pp, pr, bh, bd, turn} = apply_effects(ph, pa, pm, ps, pp, pr, bh, bd, turn)

      if ph <= 0 do
        process_queue(rest, min_spent)
      else
        if bh <= 0 do
          process_queue(rest, min(min_spent, spent))
        else
          new_turn = rem(turn + 1, 2)

          new_states =
            if turn == 0 do
              []
              |> add_if(pm >= 53, {ph, pa, pm - 53, ps, pp, pr, bh - 4, bd, new_turn, spent + 53})
              |> add_if(
                pm >= 73,
                {ph + 2, pa, pm - 73, ps, pp, pr, bh - 2, bd, new_turn, spent + 73}
              )
              |> add_if(
                ps == 0 and pm >= 113,
                {ph, pa, pm - 113, ps + 6, pp, pr, bh, bd, new_turn, spent + 113}
              )
              |> add_if(
                pp == 0 and pm >= 173,
                {ph, pa, pm - 173, ps, pp + 6, pr, bh, bd, new_turn, spent + 173}
              )
              |> add_if(
                pr == 0 and pm >= 229,
                {ph, pa, pm - 229, ps, pp, pr + 5, bh, bd, new_turn, spent + 229}
              )
            else
              damage = max(1, bd - pa)

              if ph - damage > 0 do
                [{ph - damage, pa, pm, ps, pp, pr, bh, bd, new_turn, spent}]
              else
                []
              end
            end

          process_queue(Enum.concat(rest, new_states), min_spent)
        end
      end
    end
  end

  defp add_if(list, condition, value) do
    if condition, do: [value | list], else: list
  end
end

Game.play(50, 0, 500, 0, 0, 0, 55, 8, 0)
953
defmodule Game2 do
  def apply_effects(ph, pa, pm, ps, pp, pr, bh, bd, turn) do
    pa = if ps > 0, do: pa + 7, else: pa
    ps = if ps > 0, do: ps - 1, else: ps

    bh = if pp > 0, do: bh - 3, else: bh
    pp = if pp > 0, do: pp - 1, else: pp

    pm = if pr > 0, do: pm + 101, else: pm
    pr = if pr > 0, do: pr - 1, else: pr

    {ph, pa, pm, ps, pp, pr, bh, bd, turn}
  end

  def play2(ph, pa, pm, ps, pp, pr, bh, bd, turn) do
    q = [{ph, pa, pm, ps, pp, pr, bh, bd, turn, 0}]
    min_spent = :infinity

    process_queue(q, min_spent)
  end

  defp process_queue([], min_spent), do: min_spent

  defp process_queue([{ph, _pa, pm, ps, pp, pr, bh, bd, turn, spent} | rest], min_spent) do
    if spent > min_spent do
      process_queue(rest, min_spent)
    else
      ph = if turn == 0, do: ph - 1, else: ph
      pa = 0
      {ph, pa, pm, ps, pp, pr, bh, bd, turn} = apply_effects(ph, pa, pm, ps, pp, pr, bh, bd, turn)

      if ph <= 0 do
        process_queue(rest, min_spent)
      else
        if bh <= 0 do
          process_queue(rest, min(min_spent, spent))
        else
          new_turn = rem(turn + 1, 2)

          new_states =
            if turn == 0 do
              []
              |> add_if(pm >= 53, {ph, pa, pm - 53, ps, pp, pr, bh - 4, bd, new_turn, spent + 53})
              |> add_if(
                pm >= 73,
                {ph + 2, pa, pm - 73, ps, pp, pr, bh - 2, bd, new_turn, spent + 73}
              )
              |> add_if(
                ps == 0 and pm >= 113,
                {ph, pa, pm - 113, ps + 6, pp, pr, bh, bd, new_turn, spent + 113}
              )
              |> add_if(
                pp == 0 and pm >= 173,
                {ph, pa, pm - 173, ps, pp + 6, pr, bh, bd, new_turn, spent + 173}
              )
              |> add_if(
                pr == 0 and pm >= 229,
                {ph, pa, pm - 229, ps, pp, pr + 5, bh, bd, new_turn, spent + 229}
              )
            else
              damage = max(1, bd - pa)

              if ph - damage > 0 do
                [{ph - damage, pa, pm, ps, pp, pr, bh, bd, new_turn, spent}]
              else
                []
              end
            end

          process_queue(Enum.concat(rest, new_states), min_spent)
        end
      end
    end
  end

  defp add_if(list, condition, value) do
    if condition, do: [value | list], else: list
  end
end

Game2.play2(50, 0, 500, 0, 0, 0, 55, 8, 0)
1289