Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
using System ;
using System.Buffers ;
2020-12-25 00:36:50 +00:00
using System.Collections.Generic ;
2020-06-27 18:06:28 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
2022-08-21 08:39:16 +00:00
/// <summary>
/// Logic for suggesting a moveset.
/// </summary>
2022-06-18 18:04:24 +00:00
public static class MoveListSuggest
2020-06-27 18:06:28 +00:00
{
2022-08-27 06:43:36 +00:00
private static ushort [ ] GetSuggestedMoves ( PKM pk , EvolutionHistory evoChains , MoveSourceType types , IEncounterTemplate enc )
2020-06-27 18:06:28 +00:00
{
2022-06-18 18:04:24 +00:00
if ( pk . IsEgg & & pk . Format < = 5 ) // pre relearn
2022-08-22 00:34:32 +00:00
{
2022-08-27 06:43:36 +00:00
var moves = new ushort [ 4 ] ;
2022-08-22 00:34:32 +00:00
MoveList . GetCurrentMoves ( pk , pk . Species , 0 , ( GameVersion ) pk . Version , pk . CurrentLevel , moves ) ;
return moves ;
}
2020-06-27 18:06:28 +00:00
2022-06-18 18:04:24 +00:00
if ( types ! = MoveSourceType . None )
2022-08-18 06:48:37 +00:00
return GetValidMoves ( pk , enc , evoChains , types ) ;
2020-06-27 18:06:28 +00:00
2022-06-18 18:04:24 +00:00
// try to give current moves
if ( enc . Generation < = 2 )
2020-06-27 18:06:28 +00:00
{
2022-06-18 18:04:24 +00:00
var lvl = pk . Format > = 7 ? pk . Met_Level : pk . CurrentLevel ;
var ver = enc . Version ;
return MoveLevelUp . GetEncounterMoves ( enc . Species , 0 , lvl , ver ) ;
2020-06-27 18:06:28 +00:00
}
2020-12-25 00:36:50 +00:00
2022-06-18 18:04:24 +00:00
if ( pk . Species = = enc . Species )
2020-12-25 00:36:50 +00:00
{
2022-06-18 18:04:24 +00:00
return MoveLevelUp . GetEncounterMoves ( pk . Species , pk . Form , pk . CurrentLevel , ( GameVersion ) pk . Version ) ;
2020-12-25 00:36:50 +00:00
}
2022-08-18 06:48:37 +00:00
return GetValidMoves ( pk , enc , evoChains , types ) ;
2022-06-18 18:04:24 +00:00
}
2022-08-27 06:43:36 +00:00
private static ushort [ ] GetValidMoves ( PKM pk , IEncounterTemplate enc , EvolutionHistory evoChains , MoveSourceType types = MoveSourceType . ExternalSources )
2022-06-18 18:04:24 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
var length = pk . MaxMoveID + 1 ;
bool [ ] rent = ArrayPool < bool > . Shared . Rent ( length ) ;
2022-08-18 06:48:37 +00:00
var span = rent . AsSpan ( 0 , length ) ;
LearnPossible . Get ( pk , enc , evoChains , span , types ) ;
2022-06-18 18:04:24 +00:00
2022-08-18 06:48:37 +00:00
var count = span [ 1. . ] . Count ( true ) ;
2022-08-27 06:43:36 +00:00
var result = new ushort [ count ] ;
2022-08-18 06:48:37 +00:00
int ctr = 0 ;
2022-08-27 06:43:36 +00:00
for ( ushort i = 1 ; i < span . Length ; i + + )
2020-12-25 00:36:50 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
if ( rent [ i ] )
2022-08-18 06:48:37 +00:00
result [ ctr + + ] = i ;
2020-12-25 00:36:50 +00:00
}
2022-08-18 06:48:37 +00:00
span . Clear ( ) ;
ArrayPool < bool > . Shared . Return ( rent ) ;
return result ;
2022-06-18 18:04:24 +00:00
}
2021-03-31 01:51:53 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Gets four moves which can be learned depending on the input arguments.
/// </summary>
/// <param name="analysis">Parse information to generate a moveset for.</param>
/// <param name="types">Allowed move sources for populating the result array</param>
2022-08-27 06:43:36 +00:00
public static ushort [ ] GetSuggestedCurrentMoves ( this LegalityAnalysis analysis , MoveSourceType types = MoveSourceType . All )
2022-06-18 18:04:24 +00:00
{
if ( ! analysis . Parsed )
2022-08-27 06:43:36 +00:00
return new ushort [ 4 ] ;
2022-06-18 18:04:24 +00:00
var pk = analysis . Entity ;
if ( pk . IsEgg & & pk . Format > = 6 )
return pk . RelearnMoves ;
2021-03-31 01:51:53 +00:00
2022-06-18 18:04:24 +00:00
if ( pk . IsEgg )
types = types . ClearNonEggSources ( ) ;
2021-04-08 22:58:09 +00:00
2022-06-18 18:04:24 +00:00
var info = analysis . Info ;
return GetSuggestedMoves ( pk , info . EvoChainsAllGens , types , info . EncounterOriginal ) ;
}
2021-04-05 01:30:01 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal.
/// </summary>
/// <remarks>Use <see cref="GetSuggestedRelearnMovesFromEncounter"/> instead of calling directly; this method just puts default values in without considering the final moveset.</remarks>
2022-08-27 06:43:36 +00:00
public static IReadOnlyList < ushort > GetSuggestedRelearn ( this IEncounterTemplate enc , PKM pk )
2022-06-18 18:04:24 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
if ( LearnVerifierRelearn . ShouldNotHaveRelearnMoves ( enc , pk ) )
2022-06-18 18:04:24 +00:00
return Empty ;
2021-04-08 22:58:09 +00:00
2022-06-18 18:04:24 +00:00
return GetSuggestedRelearnInternal ( enc , pk ) ;
}
2021-04-08 22:58:09 +00:00
2022-06-18 18:04:24 +00:00
// Invalid encounters won't be recognized as an EncounterEgg; check if it *should* be a bred egg.
2022-08-27 06:43:36 +00:00
private static IReadOnlyList < ushort > GetSuggestedRelearnInternal ( this IEncounterTemplate enc , PKM pk ) = > enc switch
2022-06-18 18:04:24 +00:00
{
2022-08-22 00:34:32 +00:00
IRelearn { Relearn : { HasMoves : true } r } = > r . ToArray ( ) ,
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
EncounterEgg or EncounterInvalid { EggEncounter : true } = > GetSuggestedRelearnEgg ( enc , pk ) ,
2022-06-18 18:04:24 +00:00
_ = > Empty ,
} ;
2021-04-08 22:58:09 +00:00
2022-08-27 06:43:36 +00:00
private static ushort [ ] GetSuggestedRelearnEgg ( IEncounterTemplate enc , PKM pk )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
{
2022-08-27 06:43:36 +00:00
Span < ushort > current = stackalloc ushort [ 4 ] ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
pk . GetRelearnMoves ( current ) ;
2022-08-27 06:43:36 +00:00
Span < ushort > expected = stackalloc ushort [ current . Length ] ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
_ = MoveBreed . GetExpectedMoves ( current , enc , expected ) ;
return expected . ToArray ( ) ;
}
2022-08-27 06:43:36 +00:00
private static readonly IReadOnlyList < ushort > Empty = new ushort [ 4 ] ;
2022-06-18 18:04:24 +00:00
/// <summary>
/// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal.
/// </summary>
2022-08-27 06:43:36 +00:00
public static IReadOnlyList < ushort > GetSuggestedRelearnMovesFromEncounter ( this LegalityAnalysis analysis , IEncounterTemplate ? enc = null )
2022-06-18 18:04:24 +00:00
{
var info = analysis . Info ;
enc ? ? = info . EncounterOriginal ;
var pk = analysis . Entity ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
if ( LearnVerifierRelearn . ShouldNotHaveRelearnMoves ( enc , pk ) )
2022-06-18 18:04:24 +00:00
return Empty ;
if ( enc is EncounterEgg or EncounterInvalid { EggEncounter : true } )
return enc . GetSuggestedRelearnEgg ( info . Moves , pk ) ;
return enc . GetSuggestedRelearnInternal ( pk ) ;
}
2022-08-27 06:43:36 +00:00
private static IReadOnlyList < ushort > GetSuggestedRelearnEgg ( this IEncounterTemplate enc , ReadOnlySpan < MoveResult > parse , PKM pk )
2022-06-18 18:04:24 +00:00
{
var result = enc . GetEggRelearnMoves ( parse , pk ) ;
int generation = enc . Generation ;
if ( generation < = 5 ) // gen2 does not have splitbreed, <=5 do not have relearn moves and shouldn't even be here.
return result ;
// Split-breed species like Budew & Roselia may be legal for one, and not the other.
// If we're not a split-breed or are already legal, return.
var split = Breeding . GetSplitBreedGeneration ( generation ) ;
if ( ! split . Contains ( enc . Species ) )
return result ;
var tmp = pk . Clone ( ) ;
tmp . SetRelearnMoves ( result ) ;
var la = new LegalityAnalysis ( tmp ) ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
var moves = la . Info . Moves ;
if ( MoveResult . AllValid ( moves ) )
2022-06-18 18:04:24 +00:00
return result ;
// Try again with the other split-breed species if possible.
2022-08-18 06:48:37 +00:00
var other = EncounterEggGenerator . GenerateEggs ( tmp , generation ) ;
foreach ( var incense in other )
{
if ( incense . Species ! = enc . Species )
return incense . GetEggRelearnMoves ( parse , pk ) ;
}
return result ;
2022-06-18 18:04:24 +00:00
}
2022-08-27 06:43:36 +00:00
private static ushort [ ] GetEggRelearnMoves ( this IEncounterTemplate enc , ReadOnlySpan < MoveResult > parse , PKM pk )
2022-06-18 18:04:24 +00:00
{
// Extract a list of the moves that should end up in the relearn move list.
2022-08-27 06:43:36 +00:00
Span < ushort > moves = stackalloc ushort [ parse . Length ] ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
LoadRelearnFlagged ( moves , parse , pk ) ;
2021-04-10 18:03:21 +00:00
2022-08-27 06:43:36 +00:00
Span < ushort > expected = stackalloc ushort [ moves . Length ] ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
_ = MoveBreed . GetExpectedMoves ( moves , enc , expected ) ;
return expected . ToArray ( ) ;
}
2022-08-27 06:43:36 +00:00
private static void LoadRelearnFlagged ( Span < ushort > moves , ReadOnlySpan < MoveResult > parse , PKM pk )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
{
// Loads only indexes that are flagged as relearn moves
int count = 0 ;
for ( int index = 0 ; index < parse . Length ; index + + )
2021-04-08 22:58:09 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
var move = parse [ index ] ;
if ( move . ShouldBeInRelearnMoves ( ) )
moves [ count + + ] = pk . GetMove ( index ) ;
2021-04-08 22:58:09 +00:00
}
2020-06-27 18:06:28 +00:00
}
}