oecs-sharp/OECS.PlayTest/Agents/GreedyAgent.cs

54 lines
1.6 KiB
C#

using OECS;
namespace OECS.PlayTest;
/// <summary>
/// Abstract agent that picks the action with the highest score.
/// When <see cref="ScoreAction"/> returns 0 for all actions (the default),
/// the agent behaves as a uniform random agent over legal actions.
/// Ties are broken randomly.
/// </summary>
public abstract class GreedyAgent<TDecision> : IAgent<TDecision>
{
private static readonly Random _rng = new();
/// <summary>
/// Returns the list of currently legal actions.
/// </summary>
protected abstract List<TDecision> GetLegalActions(World world);
/// <summary>
/// Scores an action. Defaults to 0 (uniform random).
/// </summary>
protected virtual float ScoreAction(World world, TDecision action) => 0f;
public TDecision Decide(World world)
{
var actions = GetLegalActions(world);
if (actions.Count == 0)
throw new InvalidOperationException(
$"{GetType().Name}: no legal actions available");
if (actions.Count == 1)
return actions[0];
float bestScore = float.MinValue;
var bestActions = new List<TDecision>();
foreach (var action in actions)
{
float score = ScoreAction(world, action);
if (score > bestScore)
{
bestScore = score;
bestActions.Clear();
bestActions.Add(action);
}
else if (score == bestScore)
{
bestActions.Add(action);
}
}
return bestActions[_rng.Next(bestActions.Count)];
}
}