Implement highest damage AI, further work on AI runner, random fixes
All checks were successful
Build / Build (push) Successful in 51s

This commit is contained in:
2025-07-05 14:56:25 +02:00
parent 32aaa5150a
commit c795f20e54
30 changed files with 261 additions and 26 deletions

View File

@@ -12,7 +12,7 @@ internal static class Program
private static Task<int> Main(string[] args)
{
Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console().CreateLogger();
Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console().CreateLogger();
Log.Information("Starting AI Runner...");
_availableAIs = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes())
.Where(type => type.IsSubclassOf(typeof(PokemonAI)) && !type.IsAbstract).Select(Activator.CreateInstance)

View File

@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using PkmnLib.Dynamic.AI;
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.Models;
@@ -12,32 +13,58 @@ public static class TestCommandRunner
{
internal static async Task RunTestCommand(PokemonAI ai1, PokemonAI ai2, int battles)
{
var t1 = DateTime.UtcNow;
var library = DynamicLibraryImpl.Create([
new Gen7Plugin(),
]);
Log.Information("Running {Battles} battles between {AI1} and {AI2}", battles, ai1.Name, ai2.Name);
var averageTimePerTurnPerBattle = new List<double>(battles);
var results = new List<BattleResult>(battles);
var random = new RandomImpl();
var results = new ConcurrentBag<BattleResult>();
var rootRandom = new RandomImpl();
const int maxTasks = 10;
var battleTasks = new Task[maxTasks];
var randoms = new IRandom[maxTasks];
for (var i = 0; i < maxTasks; i++)
{
randoms[i] = new RandomImpl(rootRandom.GetInt());
battleTasks[i] = Task.CompletedTask; // Initialize tasks to avoid null references
}
// Here you would implement the logic to run the AI scripts against each other.
// This is a placeholder for demonstration purposes.
for (var i = 0; i < battles; i++)
{
Log.Information("Battle {BattleNumber}: {AI1} vs {AI2}", i + 1, ai1.Name, ai2.Name);
var battle = GenerateBattle(library, 3, random);
var timePerTurn = new List<double>(20);
while (!battle.HasEnded)
var taskIndex = i % maxTasks;
var index = i;
var battleTask = Task.Run(async () =>
{
var res = await GetAndSetChoices(battle, ai1, ai2);
timePerTurn.Add(res.MsPerTurn);
Log.Information("Battle {BattleNumber}: {AI1} vs {AI2}", index + 1, ai1.Name, ai2.Name);
var random = randoms[taskIndex];
var battle = GenerateBattle(library, 3, random);
var timePerTurn = new List<double>(20);
while (!battle.HasEnded)
{
var res = await GetAndSetChoices(battle, ai1, ai2);
timePerTurn.Add(res.MsPerTurn);
}
var result = battle.Result;
Log.Information("Battle {BattleNumber} ended with result: {Result}", index + 1, result);
averageTimePerTurnPerBattle.Add(timePerTurn.Average());
results.Add(result.Value);
});
battleTasks[taskIndex] = battleTask;
if (i % maxTasks == maxTasks - 1 || i == battles - 1)
{
Log.Debug("Starting {TaskCount} tasks", maxTasks);
await Task.WhenAll(battleTasks);
Log.Debug("Batch of {TaskCount} tasks completed", maxTasks);
battleTasks = new Task[maxTasks]; // Reset tasks for the next batch
}
var result = battle.Result;
Log.Information("Battle {BattleNumber} ended with result: {Result}", i + 1, result);
averageTimePerTurnPerBattle.Add(timePerTurn.Average());
results.Add(result.Value);
}
Log.Information("All battles completed");
var t2 = DateTime.UtcNow;
Log.Information("{Amount} battles completed in {Duration} ms", battles, (t2 - t1).TotalMilliseconds);
var averageTimePerTurn = averageTimePerTurnPerBattle.Average();
Log.Information("Average time per turn: {AverageTimePerTurn} ms", averageTimePerTurn);
@@ -45,8 +72,11 @@ public static class TestCommandRunner
var winCount2 = results.Count(x => x.WinningSide == 1);
var drawCount = results.Count(x => x.WinningSide == null);
Log.Information("Results: {AI1} wins: {WinCount1}, {AI2} wins: {WinCount2}, Draws: {DrawCount}", ai1.Name,
winCount1, ai2.Name, winCount2, drawCount);
var winRate1 = winCount1 / (double)battles * 100;
var winRate2 = winCount2 / (double)battles * 100;
Log.Information("AI {AI1} win rate: {WinRate1:F3}% ({WinCount1} wins)", ai1.Name, winRate1, winCount1);
Log.Information("AI {AI2} win rate: {WinRate2:F3}% ({WinCount2} wins)", ai2.Name, winRate2, winCount2);
Log.Information("Draw rate: {DrawRate:F3}% ({DrawCount} draws)", drawCount / (double)battles * 100, drawCount);
}
private static PokemonPartyImpl GenerateParty(IDynamicLibrary library, int length, IRandom random)
@@ -64,7 +94,7 @@ public static class TestCommandRunner
IsHidden = false,
Index = abilityIndex,
}, level, 0, species.GetRandomGender(random), 0, nature.Name);
var moves = defaultForm.Moves.GetDistinctLevelMoves().OrderBy(x => random.GetInt()).Take(4);
var moves = defaultForm.Moves.GetDistinctLevelMoves().OrderBy(_ => random.GetInt()).Take(4);
foreach (var move in moves)
mon.LearnMove(move, MoveLearnMethod.LevelUp, 255);