From ba4f0c4ee9007c52f869cf5eb11f7b19aff5c975 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 16 Feb 2025 10:47:11 -0600 Subject: [PATCH] Implement basic AI player research Right now they just randomly pick techs to research without any particular strategy, but this will get us closer to some niceties, like tech trading and era advancement. #391 --- C7Engine/AI/PlayerAI.cs | 41 +++++++++++++++++++++++++++- C7Engine/EntryPoints/TurnHandling.cs | 2 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/C7Engine/AI/PlayerAI.cs b/C7Engine/AI/PlayerAI.cs index d7fc0273..f0a57126 100644 --- a/C7Engine/AI/PlayerAI.cs +++ b/C7Engine/AI/PlayerAI.cs @@ -13,7 +13,7 @@ namespace C7Engine { public class PlayerAI { private static ILogger log = Log.ForContext(); - public static void PlayTurn(Player player, Random rng) { + public static void PlayTurn(Player player, Random rng, List techs) { if (player.isHuman || player.isBarbarians) { return; } @@ -32,6 +32,17 @@ public static void PlayTurn(Player player, Random rng) { player.turnsUntilPriorityReevaluation--; } + if (player.currentlyResearchedTech == null) { + Tech toResearch = PickTechToResearch(player, techs); + if (toResearch == null) { + log.Information($"Player {player.civilization.name} has no techs available to research."); + player.SetCurrentlyResearchedTech(null); + } else { + log.Information($"Player {player.civilization.name} is researching {toResearch.Name}."); + player.SetCurrentlyResearchedTech(toResearch.id); + } + } + //Do things with units. Copy into an array first to avoid collection-was-modified exception foreach (MapUnit unit in player.units.ToArray()) { //For each unit, if there's already an AI task assigned, it will attempt to complete its goal. @@ -253,5 +264,33 @@ public static UnitAI getAIForUnitStrategy(UnitAIData aiData) { } throw new Exception("AI data not recognized" + aiData); } + + private static Tech PickTechToResearch(Player player, List techs) { + List possibleTechs = new(); + + // Figure out what techs we're allowed to research. + foreach (Tech tech in techs) { + if (tech.EraCivilopediaName != player.eraCivilopediaName) { + continue; + } + bool prereqsKnown = true; + foreach (Tech prereq in tech.Prerequisites) { + if (!player.knownTechs.Contains(prereq.id)) { + prereqsKnown = false; + break; + } + } + if (!prereqsKnown) { + continue; + } + possibleTechs.Add(tech); + } + + if (possibleTechs.Count == 0) { + return null; + } + + return possibleTechs[(int)GameData.rng.NextInt64(possibleTechs.Count)]; + } } } diff --git a/C7Engine/EntryPoints/TurnHandling.cs b/C7Engine/EntryPoints/TurnHandling.cs index 95e7ce15..1918df16 100644 --- a/C7Engine/EntryPoints/TurnHandling.cs +++ b/C7Engine/EntryPoints/TurnHandling.cs @@ -86,7 +86,7 @@ private static bool PlayPlayerTurns(GameData gameData, bool firstTurn) { new BarbarianAI().PlayTurn(player, gameData); player.hasPlayedThisTurn = true; } else if (!player.isHuman) { - PlayerAI.PlayTurn(player, GameData.rng); + PlayerAI.PlayTurn(player, GameData.rng, gameData.techs); player.hasPlayedThisTurn = true; } else if (player.id != EngineStorage.uiControllerID) { player.hasPlayedThisTurn = true;