using System.Diagnostics.CodeAnalysis; using PkmnLib.Static.Utils; namespace PkmnLib.Static.Libraries; /// /// All data related to types and their effectiveness. /// public interface IReadOnlyTypeLibrary { /// /// Gets the type identifier for a type with a name. /// bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier typeIdentifier); /// /// Gets the type identifier for a type with an index. /// bool TryGetTypeIdentifierFromIndex(byte index, [MaybeNullWhen(false)] out TypeIdentifier typeIdentifier); /// /// Gets the effectiveness for a single attacking type against a single defending type. /// float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending); /// /// Gets the effectiveness for a single attacking type against an amount of defending types. /// This is equivalent to running get_single_effectiveness on each defending type, and multiplying the results with each other. /// float GetEffectiveness(TypeIdentifier attacking, IEnumerable defending); IEnumerable<(TypeIdentifier type, float effectiveness)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking); } /// public class TypeLibrary : IReadOnlyTypeLibrary { private readonly List _types = new(); private readonly List> _effectiveness = new(); /// public bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier type) { var found = _types.FirstOrDefault(t => t.Name.Equals(key)); if (found.Value is not 0) { type = found; return true; } type = default; return false; } /// public bool TryGetTypeIdentifierFromIndex(byte index, out TypeIdentifier typeIdentifier) { if (index < 1 || index > _types.Count) { typeIdentifier = default; return false; } typeIdentifier = _types[index - 1]; return true; } /// public float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending) { if (attacking.Value < 1 || attacking.Value > _effectiveness.Count) throw new ArgumentOutOfRangeException(nameof(attacking)); if (defending.Value < 1 || defending.Value > _effectiveness.Count) throw new ArgumentOutOfRangeException(nameof(defending)); return _effectiveness[attacking.Value - 1][defending.Value - 1]; } /// public float GetEffectiveness(TypeIdentifier attacking, IEnumerable defending) => defending.Aggregate(1, (current, type) => current * GetSingleEffectiveness(attacking, type)); /// public IEnumerable<(TypeIdentifier, float)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking) { if (attacking.Value < 1 || attacking.Value > _effectiveness.Count) throw new ArgumentOutOfRangeException(nameof(attacking)); for (var i = 0; i < _effectiveness.Count; i++) { var type = _types[i]; yield return (type, _effectiveness[attacking.Value - 1][i]); } } /// /// Registers a new type in the library. /// public TypeIdentifier RegisterType(StringKey name) { var id = new TypeIdentifier((byte)(_types.Count + 1), name); _types.Add(id); _effectiveness.Add(Enumerable.Repeat(1.0f, _effectiveness.Count).ToList()); foreach (var list in _effectiveness) { list.Add(1); } return id; } /// /// Sets the effectiveness for an attacking type against a defending type. /// public void SetEffectiveness(TypeIdentifier attacking, TypeIdentifier defending, float effectiveness) { if (attacking.Value < 1 || attacking.Value > _effectiveness.Count) throw new ArgumentOutOfRangeException(nameof(attacking)); if (defending.Value < 1 || defending.Value > _effectiveness.Count) throw new ArgumentOutOfRangeException(nameof(defending)); _effectiveness[attacking.Value - 1][defending.Value - 1] = effectiveness; } }