AgentThoughtLog.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace MazeGen
  5. {
  6. /// <summary>What kind of decision a thought records - drives its color in the HUD.</summary>
  7. public enum ThoughtKind
  8. {
  9. Move, // "moving to room X"
  10. Peek, // "looked through a door and saw N monsters"
  11. Avoid, // "that room is too dangerous, picking another exit"
  12. Fight, // "engaging / joining a fight"
  13. Sneak, // "trying to slip past a fight"
  14. Combat, // blow-by-blow results the agent was involved in
  15. Outcome, // fight won/lost/fled
  16. Goal // reached the exit room, died
  17. }
  18. public readonly struct Thought
  19. {
  20. public readonly float Time;
  21. public readonly ThoughtKind Kind;
  22. public readonly string Text;
  23. public Thought(float time, ThoughtKind kind, string text)
  24. {
  25. Time = time;
  26. Kind = kind;
  27. Text = text;
  28. }
  29. }
  30. /// <summary>
  31. /// A bounded, newest-wins journal of one agent's decisions, so the observer can follow an
  32. /// agent and read *why* it did what it did. Capped so that thousands of decisions over a
  33. /// long run can't grow without bound - this is a debugging/observation surface, not history
  34. /// the simulation itself ever reads back.
  35. /// </summary>
  36. public class AgentThoughtLog
  37. {
  38. private readonly List<Thought> _entries = new List<Thought>();
  39. private readonly int _capacity;
  40. // Generous, because a single big fight's blow-by-blow gets mirrored in here and would
  41. // otherwise push out all the exploration reasoning that explains how the agent got there.
  42. public AgentThoughtLog(int capacity = 150)
  43. {
  44. _capacity = Mathf.Max(1, capacity);
  45. }
  46. /// <summary>Oldest first. Iterate backwards for a newest-first display.</summary>
  47. public IReadOnlyList<Thought> Entries => _entries;
  48. public event Action<Thought> Added;
  49. public void Add(ThoughtKind kind, string text)
  50. {
  51. if (string.IsNullOrEmpty(text)) return;
  52. var thought = new Thought(Time.time, kind, text);
  53. _entries.Add(thought);
  54. if (_entries.Count > _capacity)
  55. _entries.RemoveAt(0);
  56. Added?.Invoke(thought);
  57. }
  58. public static Color ColorFor(ThoughtKind kind)
  59. {
  60. switch (kind)
  61. {
  62. case ThoughtKind.Peek: return new Color(0.7f, 0.85f, 1f);
  63. case ThoughtKind.Avoid: return new Color(1f, 0.85f, 0.4f);
  64. case ThoughtKind.Fight: return new Color(1f, 0.5f, 0.4f);
  65. case ThoughtKind.Sneak: return new Color(0.8f, 0.7f, 1f);
  66. case ThoughtKind.Combat: return new Color(1f, 0.75f, 0.75f);
  67. case ThoughtKind.Outcome: return new Color(0.6f, 1f, 0.7f);
  68. case ThoughtKind.Goal: return new Color(0.5f, 1f, 1f);
  69. default: return new Color(0.85f, 0.85f, 0.85f);
  70. }
  71. }
  72. }
  73. }