Misc simplifications

reduce nesting (evo.RequiresLevelUp is checked twice, only check once
and handle path)
compact some methods
seal some classes
add a little xmldoc to exposed members
This commit is contained in:
Kurt
2018-07-01 19:55:23 -07:00
parent c40a284174
commit 7f6f7a7bad
13 changed files with 119 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
namespace PKHeX.Core
{
public class EvoCriteria : DexLevel
public sealed class EvoCriteria : DexLevel
{
public int MinLevel { get; set; }
public bool RequiresLvlUp { get; set; }

View File

@@ -6,7 +6,7 @@ namespace PKHeX.Core
/// <summary>
/// Informatics pertaining to a <see cref="PKM"/>'s evolution lineage.
/// </summary>
public class EvolutionLineage
public sealed class EvolutionLineage
{
public readonly List<EvolutionStage> Chain = new List<EvolutionStage>();
@@ -30,7 +30,8 @@ public void Insert(EvolutionStage evo)
public List<EvoCriteria> GetExplicitLineage(PKM pkm, int maxLevel, bool skipChecks, int maxSpeciesTree, int maxSpeciesOrigin, int minLevel)
{
int lvl = maxLevel;
List<EvoCriteria> dl = new List<EvoCriteria> { new EvoCriteria { Species = pkm.Species, Level = lvl, Form = pkm.AltForm } };
var first = new EvoCriteria {Species = pkm.Species, Level = lvl, Form = pkm.AltForm};
var dl = new List<EvoCriteria> { first };
for (int i = Chain.Count - 1; i >= 0; i--) // reverse evolution!
{
bool oneValid = false;
@@ -73,19 +74,20 @@ public List<EvoCriteria> GetExplicitLineage(PKM pkm, int maxLevel, bool skipChec
private static void UpdateMinValues(IReadOnlyList<EvoCriteria> dl, EvolutionMethod evo)
{
var last = dl[dl.Count - 1];
if (evo.Level == 0 || !evo.RequiresLevelUp) // Evolutions like elemental stones, trade, etc
if (!evo.RequiresLevelUp)
{
if (!evo.RequiresLevelUp)
last.MinLevel = 1;
else
{
// Evolutions like frienship, pichu -> pikachu, eevee -> umbreon, etc
last.MinLevel = 2;
// Evolutions like elemental stones, trade, etc
last.MinLevel = 1;
return;
}
if (evo.Level == 0)
{
// Evolutions like frienship, pichu -> pikachu, eevee -> umbreon, etc
last.MinLevel = 2;
var first = dl[0];
if (dl.Count > 1 && !first.RequiresLvlUp)
first.MinLevel = 2; // Raichu from Pikachu would have minimum level 1, but with Pichu included Raichu minimum level is 2
}
var first = dl[0];
if (dl.Count > 1 && !first.RequiresLvlUp)
first.MinLevel = 2; // Raichu from Pikachu would have minimum level 1, but with Pichu included Raichu minimum level is 2
}
else // level up evolutions
{

View File

@@ -6,7 +6,7 @@ namespace PKHeX.Core
/// <summary>
/// Criteria for evolving to this branch in the <see cref="EvolutionTree"/>
/// </summary>
public class EvolutionMethod
public sealed class EvolutionMethod
{
public int Method;
public int Species;

View File

@@ -5,7 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 1 Evolution Branch Entries
/// </summary>
public class EvolutionSet1 : EvolutionSet
public sealed class EvolutionSet1 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
{

View File

@@ -5,7 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 2 Evolution Branch Entries
/// </summary>
public class EvolutionSet2 : EvolutionSet
public sealed class EvolutionSet2 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, ref int offset)
{

View File

@@ -7,7 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 3 Evolution Branch Entries
/// </summary>
public class EvolutionSet3 : EvolutionSet
public sealed class EvolutionSet3 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{

View File

@@ -7,7 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 4 Evolution Branch Entries
/// </summary>
public class EvolutionSet4 : EvolutionSet
public sealed class EvolutionSet4 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{

View File

@@ -7,7 +7,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 5 Evolution Branch Entries
/// </summary>
public class EvolutionSet5 : EvolutionSet
public sealed class EvolutionSet5 : EvolutionSet
{
private static EvolutionMethod GetMethod(byte[] data, int offset)
{

View File

@@ -6,7 +6,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 6 Evolution Branch Entries
/// </summary>
public class EvolutionSet6 : EvolutionSet
public sealed class EvolutionSet6 : EvolutionSet
{
private static readonly HashSet<int> argEvos = new HashSet<int> {6, 8, 16, 17, 18, 19, 20, 21, 22, 29};
private const int SIZE = 6;

View File

@@ -5,7 +5,7 @@ namespace PKHeX.Core
/// <summary>
/// Generation 7 Evolution Branch Entries
/// </summary>
public class EvolutionSet7 : EvolutionSet
public sealed class EvolutionSet7 : EvolutionSet
{
private const int SIZE = 8;
public EvolutionSet7(byte[] data)

View File

@@ -10,7 +10,7 @@ namespace PKHeX.Core
/// <remarks>
/// Used to determine if a <see cref="PKM.Species"/> can evolve from prior steps in its evolution branch.
/// </remarks>
public class EvolutionTree
public sealed class EvolutionTree
{
private static readonly EvolutionTree Evolves1;
private static readonly EvolutionTree Evolves2;
@@ -26,118 +26,113 @@ static EvolutionTree()
byte[] get(string resource) => Util.GetBinaryResource($"evos_{resource}.pkl");
byte[][] unpack(string resource) => Data.UnpackMini(get(resource), resource);
Evolves1 = new EvolutionTree(new[] { get("rby") }, GameVersion.RBY, PersonalTable.Y, Legal.MaxSpeciesID_1);
Evolves2 = new EvolutionTree(new[] { get("gsc") }, GameVersion.GSC, PersonalTable.C, Legal.MaxSpeciesID_2);
Evolves3 = new EvolutionTree(new[] { get("g3") }, GameVersion.RS, PersonalTable.RS, Legal.MaxSpeciesID_3);
Evolves4 = new EvolutionTree(new[] { get("g4") }, GameVersion.DP, PersonalTable.DP, Legal.MaxSpeciesID_4);
Evolves5 = new EvolutionTree(new[] { get("g5") }, GameVersion.BW, PersonalTable.BW, Legal.MaxSpeciesID_5);
Evolves6 = new EvolutionTree(unpack("ao"), GameVersion.ORAS, PersonalTable.AO, Legal.MaxSpeciesID_6);
Evolves7 = new EvolutionTree(unpack("uu"), GameVersion.USUM, PersonalTable.USUM, Legal.MaxSpeciesID_7_USUM);
Evolves1 = new EvolutionTree(new[] { get("rby") }, GameVersion.Gen1, PersonalTable.Y, Legal.MaxSpeciesID_1);
Evolves2 = new EvolutionTree(new[] { get("gsc") }, GameVersion.Gen2, PersonalTable.C, Legal.MaxSpeciesID_2);
Evolves3 = new EvolutionTree(new[] { get("g3") }, GameVersion.Gen3, PersonalTable.RS, Legal.MaxSpeciesID_3);
Evolves4 = new EvolutionTree(new[] { get("g4") }, GameVersion.Gen4, PersonalTable.DP, Legal.MaxSpeciesID_4);
Evolves5 = new EvolutionTree(new[] { get("g5") }, GameVersion.Gen5, PersonalTable.BW, Legal.MaxSpeciesID_5);
Evolves6 = new EvolutionTree(unpack("ao"), GameVersion.Gen6, PersonalTable.AO, Legal.MaxSpeciesID_6);
Evolves7 = new EvolutionTree(unpack("uu"), GameVersion.Gen7, PersonalTable.USUM, Legal.MaxSpeciesID_7_USUM);
// There's always oddballs.
Evolves7.FixEvoTreeSM();
}
internal static EvolutionTree GetEvolutionTree(int generation)
{
switch (generation)
{
case 1:
return Evolves1;
case 2:
return Evolves2;
case 3:
return Evolves3;
case 4:
return Evolves4;
case 5:
return Evolves5;
case 6:
return Evolves6;
case 1: return Evolves1;
case 2: return Evolves2;
case 3: return Evolves3;
case 4: return Evolves4;
case 5: return Evolves5;
case 6: return Evolves6;
default:
return Evolves7;
}
}
private List<EvolutionSet> Entries { get; } = new List<EvolutionSet>();
private readonly IReadOnlyList<EvolutionSet> Entries;
private readonly EvolutionLineage[] Lineage;
private readonly GameVersion Game;
private readonly PersonalTable Personal;
private readonly int MaxSpeciesTree;
public EvolutionTree(byte[][] data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
private EvolutionTree(IReadOnlyList<byte[]> data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
{
Game = game;
Personal = personal;
MaxSpeciesTree = maxSpeciesTree;
switch (game)
{
case GameVersion.RBY:
Entries = EvolutionSet1.GetArray(data[0], maxSpeciesTree);
break;
case GameVersion.GSC:
Entries = EvolutionSet2.GetArray(data[0], maxSpeciesTree);
break;
case GameVersion.RS:
Entries = EvolutionSet3.GetArray(data[0]);
break;
case GameVersion.DP:
Entries = EvolutionSet4.GetArray(data[0]);
break;
case GameVersion.BW:
Entries = EvolutionSet5.GetArray(data[0]);
break;
case GameVersion.ORAS:
Entries.AddRange(data.Select(d => new EvolutionSet6(d)));
break;
case GameVersion.USUM:
Entries.AddRange(data.Select(d => new EvolutionSet7(d)));
break;
}
Entries = GetEntries(data);
Lineage = CreateTree();
}
// Create Lineages
Lineage = new EvolutionLineage[Entries.Count];
private IReadOnlyList<EvolutionSet> GetEntries(IReadOnlyList<byte[]> data)
{
switch (Game)
{
case GameVersion.Gen1: return EvolutionSet1.GetArray(data[0], MaxSpeciesTree);
case GameVersion.Gen2: return EvolutionSet2.GetArray(data[0], MaxSpeciesTree);
case GameVersion.Gen3: return EvolutionSet3.GetArray(data[0]);
case GameVersion.Gen4: return EvolutionSet4.GetArray(data[0]);
case GameVersion.Gen5: return EvolutionSet5.GetArray(data[0]);
case GameVersion.Gen6: return new List<EvolutionSet>(data.Select(d => new EvolutionSet6(d)));
case GameVersion.Gen7: return new List<EvolutionSet>(data.Select(d => new EvolutionSet7(d)));
default: throw new Exception();
}
}
private EvolutionLineage[] CreateTree()
{
var lineage = new EvolutionLineage[Entries.Count];
for (int i = 0; i < Entries.Count; i++)
Lineage[i] = new EvolutionLineage();
lineage[i] = new EvolutionLineage();
if (Game == GameVersion.ORAS)
Array.Resize(ref Lineage, MaxSpeciesTree + 1);
Array.Resize(ref lineage, MaxSpeciesTree + 1);
// Populate Lineages
for (int i = 1; i < Lineage.Length; i++)
{
// Iterate over all possible evolutions
var s = Entries[i];
foreach (EvolutionMethod evo in s.PossibleEvolutions)
{
int index = GetIndex(evo);
if (index < 0)
continue;
var sourceEvo = evo.Copy(i);
Lineage[index].Insert(sourceEvo);
// If current entries has a pre-evolution, propagate to evolution as well
if (Lineage[i].Chain.Count > 0)
Lineage[index].Insert(Lineage[i].Chain[0]);
if (index >= i) continue;
// If destination species evolves into something (ie a 'baby' Pokemon like Cleffa)
// Add it to the corresponding parent chains
foreach (EvolutionMethod mid in Entries[index].PossibleEvolutions)
{
int newIndex = GetIndex(mid);
if (newIndex < 0)
continue;
Lineage[newIndex].Insert(sourceEvo);
}
}
}
FixEvoTreeManually();
for (int i = 1; i < lineage.Length; i++)
CreateBranch(lineage, i);
return lineage;
}
// There's always oddballs.
private void FixEvoTreeManually()
private void CreateBranch(IReadOnlyList<EvolutionLineage> lineage, int i)
{
if (Game == GameVersion.USUM)
FixEvoTreeSM();
// Iterate over all possible evolutions
foreach (var evo in Entries[i].PossibleEvolutions)
CreateLeaf(lineage, i, evo);
}
private void CreateLeaf(IReadOnlyList<EvolutionLineage> lineage, int i, EvolutionMethod evo)
{
int index = GetIndex(evo);
if (index < 0)
return;
var sourceEvo = evo.Copy(i);
lineage[index].Insert(sourceEvo);
// If current entries has a pre-evolution, propagate to evolution as well
var current = lineage[i].Chain;
if (current.Count > 0)
lineage[index].Insert(current[0]);
if (index >= i)
return;
// If destination species evolves into something (ie a 'baby' Pokemon like Cleffa)
// Add it to the corresponding parent chains
foreach (var method in Entries[index].PossibleEvolutions)
{
int newIndex = GetIndex(method);
if (newIndex < 0)
continue;
lineage[newIndex].Insert(sourceEvo);
}
}
private void FixEvoTreeSM()
{
// Wormadam -- Copy Burmy 0 to Wormadam-1/2
@@ -201,6 +196,16 @@ private int GetIndex(EvolutionMethod evo)
return Personal.GetFormeIndex(evolvesToSpecies, evolvesToForm);
}
/// <summary>
/// Gets a list of evolutions for the input <see cref="PKM"/> by checking each evolution in the chain.
/// </summary>
/// <param name="pkm">Pokémon data to check with.</param>
/// <param name="maxLevel">Maximum level to permit before the chain breaks.</param>
/// <param name="maxSpeciesOrigin">Maximum species ID to permit within the chain.</param>
/// <param name="skipChecks">Ignores an evolution's criteria, causing the returned list to have all possible evolutions.</param>
/// <param name="minLevel">Minimum level to permit before the chain breaks.</param>
/// <returns></returns>
public List<EvoCriteria> GetValidPreEvolutions(PKM pkm, int maxLevel, int maxSpeciesOrigin = -1, bool skipChecks = false, int minLevel = 1)
{
int index = GetIndex(pkm);

View File

@@ -2,7 +2,7 @@
namespace PKHeX.Core
{
public class Learnset1 : Learnset
public sealed class Learnset1 : Learnset
{
private Learnset1(byte[] data, ref int offset)
{

View File

@@ -2,16 +2,17 @@
namespace PKHeX.Core
{
public class Learnset6 : Learnset
public sealed class Learnset6 : Learnset
{
private Learnset6(byte[] data)
{
if (data.Length < 4 || data.Length % 4 != 0)
{ Count = 0; Levels = new int[0]; Moves = new int[0]; return; }
Count = data.Length / 4 - 1;
Count = (data.Length / 4) - 1;
Moves = new int[Count];
Levels = new int[Count];
using (BinaryReader br = new BinaryReader(new MemoryStream(data)))
using (var ms = new MemoryStream(data))
using (var br = new BinaryReader(ms))
for (int i = 0; i < Count; i++)
{
Moves[i] = br.ReadInt16();