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, IReadOnlyList 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, IReadOnlyList 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;
}
}