Skip to content

Instantly share code, notes, and snippets.

@Aetherus
Last active February 22, 2023 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aetherus/b3cf732049557ec9f1c80aa00c028d91 to your computer and use it in GitHub Desktop.
Save Aetherus/b3cf732049557ec9f1c80aa00c028d91 to your computer and use it in GitHub Desktop.
Valkyrie Profile Max Stats Leveling in the Second Room of Seraphic Gate
defmodule ValkyrieProfile.Leveling do
@enemies %{
left: 7000,
right: 10500,
up: 35000
}
@equipment_boosts %{
[] => 1.0,
[:ring] => 1.3,
[:coin] => 1.6,
[:ring, :coin] => 1.9
}
@crystal_boosts %{
0 => 1.0,
40 => 3.0
}
@possible_battles for {enemy, exp} <- @enemies,
{equipments, boost1} <- @equipment_boosts,
{crystals, boost2} <- @crystal_boosts,
do: {round(exp * boost1 * boost2), equipments, enemy, crystals}
@type exp() :: non_neg_integer()
@type equipment() :: :ring | :coin
@type enemy() :: :left | :right | :up
@type crystals() :: 0 | 40
@type battle() :: {exp(), [equipment()], enemy(), crystals()}
@doc """
找到获取的总经验值为小于 exp 的最大值的战斗组合。
如果有多种方案可以获得相同的总经验值,
则挑选其中战斗次数最少的。
如果仍有多种方案战斗次数也相同,
则挑选其中需要打出的魔晶石总量最少的。
"""
@spec optimal_strategy(exp()) :: [battle()]
def optimal_strategy(exp_needed) do
Task.async(fn ->
find_optimal(exp_needed)
end)
|> Task.await()
|> Enum.group_by(&elem(&1, 1))
|> Map.values()
|> List.flatten()
end
@spec find_optimal(exp()) :: [battle()]
defp find_optimal(exp_needed) do
memoized(exp_needed, fn ->
@possible_battles
|> Enum.filter(&(elem(&1, 0) < exp_needed))
|> Enum.map(&{&1, find_optimal(exp_needed - elem(&1, 0))})
|> Enum.max_by(
fn {{exp, _, _, crystals}, sub_battles} ->
{
exp + Enum.sum(Enum.map(sub_battles, &elem(&1, 0))),
-length(sub_battles),
-crystals - Enum.sum(Enum.map(sub_battles, &elem(&1, 3)))
}
end,
fn -> nil end
)
|> then(fn
nil -> []
{battle, sub_battles} -> [battle | sub_battles]
end)
end)
end
@spec memoized(key :: term(), (() -> result :: term())) :: (result :: term())
defp memoized(key, fun) do
with nil <- Process.get(key) do
tap(fun.(), &Process.put(key, &1))
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment