From e90f701bd5a139f35d0e9bb0a0f8abcbcb9f4f81 Mon Sep 17 00:00:00 2001 From: hzhang Date: Thu, 27 Feb 2025 15:39:28 +0000 Subject: [PATCH] redesign: Agents --- Polonium.csproj | 1 + src/Agents/ActionSet.cs | 13 ++++++ src/Agents/Agent.cs | 66 ++++++++++++------------------ src/Agents/AgentAction.cs | 60 --------------------------- src/Agents/AgentDecisionMaker.cs | 17 -------- src/Agents/AgentKnowledge.cs | 18 -------- src/Agents/DecisionMakerType.cs | 9 ---- src/Agents/Knowledge.cs | 8 ++++ src/Agents/World.cs | 45 ++++++++++++++++++++ src/Agents/WorldModel.cs | 22 ++++++++++ src/Interfaces/IPoloniumFactory.cs | 8 ++++ src/PoloniumRegistry.cs | 8 +++- src/Resources/ActionBody.cs | 9 ++++ src/Resources/KnowledgePatch.cs | 11 +++++ src/Resources/SignalHeader.cs | 15 +++++++ 15 files changed, 166 insertions(+), 144 deletions(-) create mode 100644 src/Agents/ActionSet.cs delete mode 100644 src/Agents/AgentAction.cs delete mode 100644 src/Agents/AgentDecisionMaker.cs delete mode 100644 src/Agents/AgentKnowledge.cs delete mode 100644 src/Agents/DecisionMakerType.cs create mode 100644 src/Agents/Knowledge.cs create mode 100644 src/Agents/World.cs create mode 100644 src/Agents/WorldModel.cs create mode 100644 src/Interfaces/IPoloniumFactory.cs create mode 100644 src/Resources/ActionBody.cs create mode 100644 src/Resources/KnowledgePatch.cs create mode 100644 src/Resources/SignalHeader.cs diff --git a/Polonium.csproj b/Polonium.csproj index cd3342f..4fb5015 100644 --- a/Polonium.csproj +++ b/Polonium.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Agents/ActionSet.cs b/src/Agents/ActionSet.cs new file mode 100644 index 0000000..2efbbda --- /dev/null +++ b/src/Agents/ActionSet.cs @@ -0,0 +1,13 @@ +using Godot; +using Polonium.Resources; + +namespace Polonium.Agents; + +public abstract partial class ActionSet : Node +{ + [Signal] + public delegate void ActionSubmittedEventHandler(ActionBody action); + + +} + diff --git a/src/Agents/Agent.cs b/src/Agents/Agent.cs index dca77e7..471f87a 100644 --- a/src/Agents/Agent.cs +++ b/src/Agents/Agent.cs @@ -1,51 +1,39 @@ +using Godot; +using Polonium.Resources; + namespace Polonium.Agents; -public abstract class Agent +public abstract partial class Agent : Node { - protected static int ComputerCount = 0; + [Signal] + public delegate void ActionExecutedEventHandler(SignalHeader header, ActionBody actionBody); + protected Knowledge Knowledge { get; set; } + public ActionSet ActionSet { get; set; } - public string Name { get; init; } - - public Agent(string name) + public virtual void __Ready() { - Name = name; - PoloniumRegistry.Instance.Agents[name] = this; + Knowledge = GetNode("Knowledge"); + ActionSet = GetNode("ActionSet"); + ActionSet.ActionSubmitted += ExecuteAction; } - public int Level { get; private set; } - public abstract int MaxLevel { get; } - - public virtual void LevelUp() + public sealed override void _Ready() { - if(Level < MaxLevel) - Level++; + Knowledge = GetNode("Knowledge"); + ActionSet = GetNode("ActionSet"); + __Ready(); + base._Ready(); } -} - -public abstract class Agent : Agent - where TAgent : Agent, new() - where TAgentDecisionMaker : AgentDecisionMaker, new() - where TAgentKnowledge : AgentKnowledge, new() - where TAgentAction : AgentAction, new() -{ - - public Dictionary Actions { get; } = new(); - - public TAgentDecisionMaker DecisionMaker { get; init; } - public TAgentKnowledge Knowledge { get; init; } - - - public Agent() : base($"Computer {ComputerCount++}") - { - DecisionMaker = new TAgentDecisionMaker(); - Knowledge = new TAgentKnowledge(); - } - - public Agent(string name, TAgentDecisionMaker decisionMaker, TAgentKnowledge knowledge) : base(name) - { - DecisionMaker = decisionMaker; - Knowledge = knowledge; - } + public void UpdateKnowledge(KnowledgePatch update) => update.Patch(Knowledge); + + public virtual void ExecuteAction(ActionBody actionBody) + { + SignalHeader header = PoloniumRegistry.Instance.PoloniumFactory.CreateSignalHeader(); + header.SetSender(this); + EmitSignalActionExecuted(header, actionBody); + } + + } diff --git a/src/Agents/AgentAction.cs b/src/Agents/AgentAction.cs deleted file mode 100644 index 328832e..0000000 --- a/src/Agents/AgentAction.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Polonium.Interfaces; - -namespace Polonium.Agents; - -public abstract class AgentAction -{ -} - -public abstract class AgentAction : AgentAction, ITimeConsumer - where TAgent : Agent, new() - where TAgentDecisionMaker : AgentDecisionMaker, new() - where TAgentKnowledge : AgentKnowledge, new() - where TAgentAction : AgentAction, new() -{ - - public int Level { get; private set; } - - public abstract int MaxLevel { get; } - - public virtual void LevelUp() - { - if(Level < MaxLevel) - Level++; - } - - public AgentAction(double coolDown) - { - CoolDown = coolDown; - PoloniumRegistry.Instance.TimeConsumers.Add(this); - } - - public abstract class ActionParameter - { - } - - public virtual bool Execute(ActionParameter parameter) - { - if (Disabled || CoolDown > 0) - return false; - CoolDownTime = CoolDown; - return true; - } - - - private double CoolDownTime { get; set; } - public bool Disabled { get; set; } - - private double CoolDown { get; } - - public void Process(double delta) - { - - if (Disabled || CoolDownTime <= 0) - return; - CoolDownTime -= delta; - if (CoolDownTime <= 0) - CoolDownTime = 0; - - } -} diff --git a/src/Agents/AgentDecisionMaker.cs b/src/Agents/AgentDecisionMaker.cs deleted file mode 100644 index 4c20980..0000000 --- a/src/Agents/AgentDecisionMaker.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Polonium.Agents; - -public abstract class AgentDecisionMaker(DecisionMakerType type) - where TAgent : Agent, new() - where TAgentDecisionMaker : AgentDecisionMaker, new() - where TAgentKnowledge : AgentKnowledge, new() - where TAgentAction : AgentAction, new() -{ - - - - public DecisionMakerType Type { get; init; } = type; - - public AgentDecisionMaker() : this(DecisionMakerType.Computer) - { - } -} \ No newline at end of file diff --git a/src/Agents/AgentKnowledge.cs b/src/Agents/AgentKnowledge.cs deleted file mode 100644 index 4b07676..0000000 --- a/src/Agents/AgentKnowledge.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Polonium.Agents; - -public abstract class AgentKnowledge -{ -} - -public abstract class AgentKnowledge : AgentKnowledge - where TAgent : Agent, new() - where TAgentDecisionMaker : AgentDecisionMaker, new() - where TAgentKnowledge : AgentKnowledge, new() - where TAgentAction : AgentAction, new() -{ - public AgentKnowledge() - { - } - - public abstract void Update(TAgentKnowledge newKnowledge); -} diff --git a/src/Agents/DecisionMakerType.cs b/src/Agents/DecisionMakerType.cs deleted file mode 100644 index f721983..0000000 --- a/src/Agents/DecisionMakerType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Polonium.Agents; - -public enum DecisionMakerType -{ - None = 0, - Player = 1, - Computer = 2, - Global = 3, -} \ No newline at end of file diff --git a/src/Agents/Knowledge.cs b/src/Agents/Knowledge.cs new file mode 100644 index 0000000..6a51d94 --- /dev/null +++ b/src/Agents/Knowledge.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace Polonium.Agents; + +public abstract partial class Knowledge : Node +{ + +} \ No newline at end of file diff --git a/src/Agents/World.cs b/src/Agents/World.cs new file mode 100644 index 0000000..e3fa191 --- /dev/null +++ b/src/Agents/World.cs @@ -0,0 +1,45 @@ +using Godot; +using Polonium.Resources; + +namespace Polonium.Agents; + +public abstract partial class World : Node +{ + private WorldModel Model { get; set; } + public HashSet Agents { get; } = new(); + public Knowledge CommonKnowledge { get; set; } + + public override void _Ready() + { + Model = GetNode("WorldModel"); + CommonKnowledge = GetNode("CommonKnowledge"); + Model.CommonKnowledgeUpdated += CommonKnowledgeUpdated; + Model.PrivateKnowledgeUpdated += ForwardPrivateKnowledgeUpdated; + base._Ready(); + } + + public void RegisterAgent(Agent agent) + { + Agents.Add(agent); + agent.ActionExecuted += Model.ActionExecuted; + } + + public virtual void Enter() + { + PoloniumRegistry.Instance.CurrentWorld = this; + } + + public virtual void Exit() + { + PoloniumRegistry.Instance.CurrentWorld = null; + } + + public void CommonKnowledgeUpdated(KnowledgePatch update) => update.Patch(CommonKnowledge); + + public void ForwardPrivateKnowledgeUpdated(SignalHeader header, KnowledgePatch update) + { + foreach (Agent receiver in header.ResolveReceivers()) + receiver.UpdateKnowledge(update); + } + +} \ No newline at end of file diff --git a/src/Agents/WorldModel.cs b/src/Agents/WorldModel.cs new file mode 100644 index 0000000..b5a7794 --- /dev/null +++ b/src/Agents/WorldModel.cs @@ -0,0 +1,22 @@ +using Godot; +using Polonium.Resources; + +namespace Polonium.Agents; + +public abstract partial class WorldModel : Node +{ + + [Signal] + public delegate void CommonKnowledgeUpdatedEventHandler(KnowledgePatch update); + [Signal] + public delegate void PrivateKnowledgeUpdatedEventHandler(SignalHeader header, KnowledgePatch update); + + private Knowledge WorldKnowledge { get; set; } + + public override void _Ready() + { + WorldKnowledge = GetNode("WorldKnowledge"); + base._Ready(); + } + public abstract void ActionExecuted(SignalHeader header, ActionBody actionBody); +} diff --git a/src/Interfaces/IPoloniumFactory.cs b/src/Interfaces/IPoloniumFactory.cs new file mode 100644 index 0000000..f3c5e24 --- /dev/null +++ b/src/Interfaces/IPoloniumFactory.cs @@ -0,0 +1,8 @@ +using Polonium.Resources; + +namespace Polonium.Interfaces; + +public interface IPoloniumFactory +{ + public SignalHeader CreateSignalHeader(); +} \ No newline at end of file diff --git a/src/PoloniumRegistry.cs b/src/PoloniumRegistry.cs index d3dd4d3..04bbd43 100644 --- a/src/PoloniumRegistry.cs +++ b/src/PoloniumRegistry.cs @@ -14,6 +14,12 @@ public class PoloniumRegistry public Config Config { get; set; } [RegistryPassThrough] public Save Save { get; set; } + [RegistryPassThrough] + public World CurrentWorld { get; set; } + + [RegistryPassThrough] + public IPoloniumFactory PoloniumFactory { get; set; } + public static void Prepare() { @@ -28,4 +34,4 @@ public class PoloniumRegistry public HashSet TimeConsumers { get; } = new(); -} \ No newline at end of file +} diff --git a/src/Resources/ActionBody.cs b/src/Resources/ActionBody.cs new file mode 100644 index 0000000..1bc28d9 --- /dev/null +++ b/src/Resources/ActionBody.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace Polonium.Resources; + +public abstract partial class ActionBody : Resource +{ + public StringName ActionName { get; set; } + +} diff --git a/src/Resources/KnowledgePatch.cs b/src/Resources/KnowledgePatch.cs new file mode 100644 index 0000000..b8b20a3 --- /dev/null +++ b/src/Resources/KnowledgePatch.cs @@ -0,0 +1,11 @@ +using Godot; +using Polonium.Agents; + +namespace Polonium.Resources; + +public abstract partial class KnowledgePatch : Resource +{ + public SignalHeader Header { get; set; } + public abstract void Patch(Knowledge knowledge); + +} \ No newline at end of file diff --git a/src/Resources/SignalHeader.cs b/src/Resources/SignalHeader.cs new file mode 100644 index 0000000..468d298 --- /dev/null +++ b/src/Resources/SignalHeader.cs @@ -0,0 +1,15 @@ +using Godot; +using Polonium.Agents; + +namespace Polonium.Resources; + +public abstract partial class SignalHeader : Resource +{ + + public abstract Agent[] ResolveReceivers(); + public abstract Agent ResolveSender(); + + public abstract void SetSender(Agent agent); + public abstract void AddReceiver(Agent agent); + +}