using System.Diagnostics.CodeAnalysis; using PkmnLib.Static.Utils; namespace PkmnLib.Static.Libraries; /// <summary> /// All data related to types and their effectiveness. /// </summary> public interface IReadOnlyTypeLibrary { /// <summary> /// Gets the type identifier for a type with a name. /// </summary> bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier typeIdentifier); /// <summary> /// Gets the type name from the type identifier. /// </summary> bool TryGetTypeName(TypeIdentifier t, [NotNullWhen(true)] out StringKey? stringKey); /// <summary> /// Gets the effectiveness for a single attacking type against a single defending type. /// </summary> float GetSingleEffectiveness(TypeIdentifier attacking, TypeIdentifier defending); /// <summary> /// 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. /// </summary> float GetEffectiveness(TypeIdentifier attacking, IReadOnlyList<TypeIdentifier> defending); } /// <inheritdoc /> public class TypeLibrary : IReadOnlyTypeLibrary { private readonly Dictionary<StringKey, TypeIdentifier> _types = new(); private readonly List<List<float>> _effectiveness = new(); /// <inheritdoc /> public bool TryGetTypeIdentifier(StringKey key, out TypeIdentifier type) => _types.TryGetValue(key, out type); /// <inheritdoc /> 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; } /// <inheritdoc /> 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]; } /// <inheritdoc /> public float GetEffectiveness(TypeIdentifier attacking, IReadOnlyList<TypeIdentifier> defending) => defending.Aggregate<TypeIdentifier, float>(1, (current, type) => current * GetSingleEffectiveness(attacking, type)); /// <summary> /// Registers a new type in the library. /// </summary> 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; } /// <summary> /// Sets the effectiveness for an attacking type against a defending type. /// </summary> 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; } }