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 name from the type identifier. /// bool TryGetTypeName(TypeIdentifier t, [NotNullWhen(true)] out StringKey? stringKey); /// /// 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 Dictionary _types = new(); private readonly List> _effectiveness = new(); /// public bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier type) => _types.TryGetValue(key, out type); /// public bool TryGetTypeName(TypeIdentifier t, [NotNullWhen(true)] out StringKey? stringKey) { foreach (var (key, value) in _types) { if (value == t) { stringKey = key; return true; } } stringKey = default; return false; } /// 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++) { yield return (new TypeIdentifier((byte)(i + 1)), _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)); _types.Add(name, 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; } }