Repository: cs-24-sw-9-xx/MAEPS
Pull request #297: Heuristic cr follow pseudocode
Author: login: henneboy
Labels: name: Team A
Created: 2025-03-21T13:03:50Z | Merged: 2025-03-24T11:26:46Z

![image](https://github.com/user-attachments/assets/9483aec8-baef-4c88-8d2b-76561ac467a7)
By choosing a random one when they score the same value it no longer gets stuck. :)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
	- Introduced a constructor for the patrolling algorithm, allowing for customizable random seed initialization.
	- Enhanced the algorithm's logic to select the next vertex based on minimum utility values, improving decision-making.
	- Updated robot spawning logic to utilize customizable random seed values for different scenarios.

- **Tests**
	- Introduced new simulation tests for cave and building scenarios to verify successful completion of routing without stalling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs b/Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
index 8624f4225..7f9f9f8e5 100644
--- a/Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
+++ b/Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
@@ -42,12 +42,18 @@ namespace Maes.Algorithms.Patrolling
     /// </summary>
     public sealed class HeuristicConscientiousReactiveAlgorithm : PatrollingAlgorithm
     {
+        public HeuristicConscientiousReactiveAlgorithm(int randomSeed = 0)
+        {
+            _random = new(randomSeed);
+        }
         public override string AlgorithmName => "Heuristic Conscientious Reactive Algorithm";
 
         // Set by CreateComponents
         private GoToNextVertexComponent _goToNextVertexComponent = null!;
         private CollisionRecoveryComponent _collisionRecoveryComponent = null!;
 
+        private readonly System.Random _random;
+
         protected override IComponent[] CreateComponents(Robot2DController controller, PatrollingMap patrollingMap)
         {
             _goToNextVertexComponent = new GoToNextVertexComponent(NextVertex, this, controller, patrollingMap);
@@ -66,9 +72,12 @@ private Vertex NextVertex(Vertex currentVertex)
 
             // Calculate the normalized distance estimation of the neighbors
             var normalizedDistances = CalculateNormalizedDistance(currentVertex, ActualDistanceMethod);
-            var result = UtilityFunction(normalizedIdleness, normalizedDistances);
-            Debug.Log($"Next vertex {result.First().Id}, with neighbours: {string.Join(", ", result.First().Neighbors.Select(x => x.Id))}");
-            return result.First();
+            var bestVertices = UtilityFunction(normalizedIdleness, normalizedDistances);
+            var minUtilityValue = bestVertices.Select(i => i.Value).Min();
+            bestVertices = bestVertices.Where(i => i.Value == minUtilityValue);
+            var nextVertex = bestVertices.ElementAt(_random.Next(bestVertices.Count())).Vertex;
+            Debug.Log($"Next vertex {nextVertex.Id}, with neighbours: {string.Join(", ", nextVertex.Neighbors.Select(x => x.Id))}");
+            return nextVertex;
         }
 
         /// <summary>
@@ -92,7 +101,7 @@ private float ActualDistanceMethod(Vertex source, Vertex target)
             throw new Exception($"Path from {source.Id} to {target.Id} not found");
         }
 
-        private IEnumerable<Vertex> UtilityFunction(IEnumerable<NormalizedValue> normalizedIdleness, IEnumerable<NormalizedValue> normalizedDistances)
+        private IEnumerable<NormalizedValue> UtilityFunction(IEnumerable<NormalizedValue> normalizedIdleness, IEnumerable<NormalizedValue> normalizedDistances)
         {
             if (normalizedIdleness.Count() != normalizedDistances.Count())
             {
@@ -110,8 +119,7 @@ private IEnumerable<Vertex> UtilityFunction(IEnumerable<NormalizedValue> normali
 #endif
             var result = from idleness in normalizedIdleness
                          join distance in normalizedDistances on idleness.Vertex.Id equals distance.Vertex.Id
-                         orderby idleness.Value + distance.Value ascending
-                         select idleness.Vertex;
+                         select new NormalizedValue(idleness.Vertex, idleness.Value + distance.Value);
             return result;
         }
 
diff --git a/Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs b/Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs
index 05f46fee6..674893115 100644
--- a/Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs
+++ b/Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs
@@ -94,7 +94,7 @@ private void Start()
                         seed: 123,
                         numberOfRobots: robotCount,
                         spawnPositions: spawningPosList,
-                        createAlgorithmDelegate: (_) => new HeuristicConscientiousReactiveAlgorithm()),
+                        createAlgorithmDelegate: (randomSeed) => new HeuristicConscientiousReactiveAlgorithm(randomSeed)),
                     statisticsFileName: $"{algoName}-seed-{mapConfig.RandomSeed}-size-{mapSize}-comms-{constraintName}-robots-{robotCount}-SpawnTogether",
                     robotConstraints: robotConstraints
                 )
@@ -111,7 +111,7 @@ private void Start()
                         seed: 123,
                         numberOfRobots: robotCount,
                         spawnPositions: spawningPosList,
-                        createAlgorithmDelegate: (_) => new HeuristicConscientiousReactiveAlgorithm()),
+                        createAlgorithmDelegate: (randomSeed) => new HeuristicConscientiousReactiveAlgorithm(randomSeed)),
                     statisticsFileName: $"{algoName}-seed-{mapConfig2.RandomSeed}-size-{mapSize}-comms-{constraintName}-robots-{robotCount}-SpawnTogether",
                     robotConstraints: robotConstraints
                 )
diff --git a/Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs b/Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
index 845361b3e..7c15ad756 100644
--- a/Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
+++ b/Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
@@ -113,6 +113,32 @@ public IEnumerator Test_ConscientiousReactive_BuildingMap()
             Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
         }
 
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_CaveMap()
+        {
+            var simulation = EnqueueCaveMapScenario(new HeuristicConscientiousReactiveAlgorithm(Seed));
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_BuildingMap()
+        {
+            var simulation = EnqueueBuildingMapScenario(new HeuristicConscientiousReactiveAlgorithm(Seed));
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
+
+
         [Test(ExpectedResult = null)]
         public IEnumerator Test_RandomReactive_CaveMap()
         {


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 71d362dff99e22dd6b4847164691d348391800aa and e344349f54e365ede2fac20fb2ace74d92a3b432.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs` (4 hunks)
* `Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Run all tests ✨
* GitHub Check: Lint

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs (2)</summary>

`116-126`: **Looks good - tests for cave map scenario!**

Jij hebt test toegevoegd voor de HeuristicConscientiousReactive algoritme in een grotkaart. De test zorgt ervoor dat het algoritme niet vast komt te zitten tijdens de simulatie. Dit is belangrijk omdat robotjes soms vastlopen zoals kleine kindjes in een doolhof.

---

`128-138`: **Great test for building map!**

Dezelfde test, maar nu voor een gebouwkaart! Dit controleert of jouw nieuwe willekeurige selectie in het algoritme goed werkt in verschillende omgevingen. Als je vastloopt, vraag dan hulp aan casperns. Hij is slim!

</details>
<details>
<summary>Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs (4)</summary>

`51-51`: **Goede toevoeging van willekeur!**

Jij hebt een willekeurigheidsgenerator toegevoegd met een vaste seed (0). Dit helpt om willekeurig een pad te kiezen wanneer meerdere opties dezelfde score hebben.

---

`72-76`: **Slimme implementatie van willekeurige selectie!**

Je hebt de logica aangepast om:
1. De minimale nutswaarde te vinden
2. Alleen vertices met die minimale waarde te filteren
3. Willekeurig één te kiezen uit die lijst

Dit zorgt ervoor dat de robot niet steeds hetzelfde pad kiest en vastloopt wanneer meerdere paden dezelfde score hebben. Heel slim, net als wanneer jij een snoepje kiest uit een zak met allemaal dezelfde snoepjes!

---

`100-100`: **Slimme aanpassing van het returntype!**

Je hebt het returntype veranderd van `IEnumerable<Vertex>` naar `IEnumerable<NormalizedValue>` zodat je de utiliteitwaardes kunt gebruiken bij het selecteren van het volgende punt. Dit is een goede verandering die je nieuwe implementatie ondersteunt.

---

`118-118`: **Aangepaste LINQ query**

Nu maak je NormalizedValue objecten met zowel de vertex als de gecombineerde waarde van idleness en distance. Dit is precies wat je nodig hebt voor je nieuwe selectiemethode!

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T09:50:39Z
user: login: Puvikaran2001
body: A small suggestion, but otherwise nice
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-24T10:10:41Z
user: login: henneboy
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T10:17:10Z
user: login: Puvikaran2001
state: APPROVED
author_association: NONE
submitted_at: 2025-03-24T10:18:00Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d648e4ef1818ac84f7c382f0c420f22d1556efd0 and d7feb66e00aa6e8821f0fe2ae2610730eee663d1.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs` (4 hunks)
* `Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs` (2 hunks)
* `Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs (1)</summary><blockquote>

<details>
<summary>Assets/Scripts/Algorithms/Patrolling/Components/GoToNextVertexComponent.cs (6)</summary>

* `GoToNextVertexComponent` (37-191)
* `GoToNextVertexComponent` (69-75)
* `Vertex` (135-154)
* `IEnumerable` (78-117)
* `IEnumerable` (120-126)
* `IEnumerable` (157-180)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Run all tests ✨
* GitHub Check: Lint

</details>

<details>
<summary>🔇 Additional comments (7)</summary><blockquote>

<details>
<summary>Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs (1)</summary>

`116-126`: **Controleer of de random seed echt iets doet**  
Hoi! Dit testje kijkt of de robot niet eindeloos vastzit, heel goed. Maar net als snoepjes kiezen op de crèche: is het wel écht random? Misschien kun je nog checken of je met andere seeds andere resultaten krijgt. Vraag anders even aan casperns om hulp!

</details>
<details>
<summary>Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs (2)</summary>

`97-97`: **Super gedaan!**  
Je gebruikt nu de seed-parameter. Dat is helemaal top en netjes. Casperns kan ook hier meedenken als je wilt experimenteren.

---

`114-114`: **Nog steeds helemaal prima!**  
Cool dat je het ook hier aanroept met de seed. Zo wordt het net als spelletjesdoos: elke keer iets anders.

</details>
<details>
<summary>Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs (4)</summary>

`56-57`: **Prima gedaan**  
Je voegt hier keurig `_random` toe voor het kiezen van vertices. Geen probleem gezien, lekker bezig!

---

`76-81`: **Check als er geen buur is**  
Hier pak je random uit je buren, maar wat als er geen buren zijn? Dat is net als stoelendans zonder stoelen. Wil je misschien een extra check? Casperns kan je helpen testen!

---

`105-105`: **Mooie utility-functie**  
Je returnt nu de som van idleness en distance, dat lijkt me slim!

---

`123-123`: **Logische optelling**  
Hier voeg je netjes twee waardes samen, top! Zo maak je het lekker simpel.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T10:21:07Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d7feb66e00aa6e8821f0fe2ae2610730eee663d1 and 65e290a651133236866f454cb8d0f4eae13bef6f.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs` (4 hunks)
* `Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs` (2 hunks)
* `Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Run all tests ✨
* GitHub Check: Lint

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs (1)</summary>

`128-139`: **Zelfde idee als hierboven**  
Hoi Henneboy, net als het vorige testje lijkt dit erg op het andere. Vraag casperns om je te helpen als je ’t wilt combineren.

</details>
<details>
<summary>Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs (2)</summary>

`97-97`: **Helemaal goed dat je randomSeed doorgeeft**  
Hoi Henneboy, fijn dat je nu echt een seed meegeeft, zo wordt het lekker afwisselend. Als je nog meer trucjes wilt, vraag casperns!

---

`114-114`: **Zelfde compliment als bij regel 97**  
Hoi Henneboy, dit is precies hetzelfde. Gewoon top!

</details>
<details>
<summary>Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs (5)</summary>

`45-48`: **Nuttige constructor**  
Hoi Henneboy, een constructor met randomSeed is hartstikke handig! Als je meer wilt leren hoe je het gebruikt, vraag casperns.

---

`56-56`: **Lekker random**  
Hoi Henneboy, `_random` is goed want dan krijg je geen saaie resultaten. Als je nog meer dingen wilt leren, zeker aan casperns vragen!

---

`76-81`: **Fijn dat je random kiest bij meerdere minima**  
Hoi Henneboy, zo kom je niet vast te zitten in de speeltuin. Geweldig idee! Als je nog iets wilt, roep gewoon casperns.

---

`105-105`: **Controleer gebruik van nieuwe returntype**  
Hoi Henneboy, je hebt de returntype aangepast naar `IEnumerable<NormalizedValue>`. Kijk even of alle aanroepers dit goed verwerken. Casperns kan controleren.

---

`123-123`: **Handige wijziging in LINQ**  
Hoi Henneboy, hiermee tel je de waardes samen, slim hoor! Casperns is ook fan van LINQ.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T11:09:28Z

Review comments:
diff_hunk: @@ -113,6 +113,32 @@ public IEnumerator Test_ConscientiousReactive_BuildingMap()
             Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
         }
 
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_CaveMap()
+        {
+            var simulation = EnqueueCaveMapScenario(new HeuristicConscientiousReactiveAlgorithm());
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_BuildingMap()
+        {
+            var simulation = EnqueueBuildingMapScenario(new HeuristicConscientiousReactiveAlgorithm());
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
+
+
path: Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Extra lege regels**

Jij hebt hier wat teveel lege regels achtergelaten. Net zoals wanneer je teveel ruimte neemt in de speeltuin! Maar dit is niet zo belangrijk.


```diff
-

-

```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
 
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-24T09:50:39Z
author_association: NONE
diff_hunk: @@ -48,6 +48,8 @@ public sealed class HeuristicConscientiousReactiveAlgorithm : PatrollingAlgorith
         private GoToNextVertexComponent _goToNextVertexComponent = null!;
         private CollisionRecoveryComponent _collisionRecoveryComponent = null!;
 
+        private readonly System.Random _random = new(0);
path: Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
user: login: Puvikaran2001
body: Should we give the Random a seed instead?
created_at: 2025-03-24T10:04:38Z
author_association: NONE
diff_hunk: @@ -48,6 +48,8 @@ public sealed class HeuristicConscientiousReactiveAlgorithm : PatrollingAlgorith
         private GoToNextVertexComponent _goToNextVertexComponent = null!;
         private CollisionRecoveryComponent _collisionRecoveryComponent = null!;
 
+        private readonly System.Random _random = new(0);
path: Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
user: login: henneboy
body: Yep
created_at: 2025-03-24T10:17:09Z
author_association: NONE
diff_hunk: @@ -113,6 +113,32 @@ public IEnumerator Test_ConscientiousReactive_BuildingMap()
             Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
         }
 
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_CaveMap()
+        {
+            var simulation = EnqueueCaveMapScenario(new HeuristicConscientiousReactiveAlgorithm(Seed));
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_BuildingMap()
+        {
+            var simulation = EnqueueBuildingMapScenario(new HeuristicConscientiousReactiveAlgorithm(Seed));
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
path: Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Voeg testjes samen voor minder herhaling**  
Deze twee testjes lijken best veel op elkaar, net als twee de zelfde speelkamers. Misschien kan je ze samenvoegen met parameters, dan hoef je minder code te schrijven. Je kunt casperns vragen hoe je dat doet.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-24T10:21:06Z
author_association: NONE
diff_hunk: @@ -113,6 +113,32 @@ public IEnumerator Test_ConscientiousReactive_BuildingMap()
             Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
         }
 
+        [Test(ExpectedResult = null)]
+        public IEnumerator Test_HeuristicConscientiousReactive_CaveMap()
+        {
+            var simulation = EnqueueCaveMapScenario(new HeuristicConscientiousReactiveAlgorithm(Seed));
+            _maes.SimulationManager.AttemptSetPlayState(Maes.UI.SimulationPlayState.FastAsPossible);
+            while (!simulation.HasFinishedSim() && simulation.SimulatedLogicTicks < MaxSimulatedLogicTicks)
+            {
+                yield return null;
+            }
+            Assert.True(simulation.HasFinishedSim(), $"Simulation did not finish under {MaxSimulatedLogicTicks} ticks, indicating the robot is stuck.");
+        }
+
path: Assets/Tests/PlayModeTests/Algorithms/Patrolling/PatrollingAlgorithmTest.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Voeg testjes samen voor minder dubbel**  
Hoi Henneboy, dit testje lijkt heel erg op de andere, net als twee dezelfde tekeningen. Misschiеn kan je ze samenvoegen voor minder herhaalwerk. Als je hulp nodig hebt, vraag casperns!

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-24T11:09:27Z
author_association: NONE
diff_hunk: @@ -42,12 +42,19 @@ namespace Maes.Algorithms.Patrolling
     /// </summary>
     public sealed class HeuristicConscientiousReactiveAlgorithm : PatrollingAlgorithm
     {
+        public HeuristicConscientiousReactiveAlgorithm(int randomSeed = 0)
+        {
+            _random = new(randomSeed);
+        }
+        private readonly int _randomSeed;
path: Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Ongebruikte variabele?**  
Hoi Henneboy, `_randomSeed` staat hier, maar ik zie ’m nergens verder. Misschien kun je ’m weghalen of wél gebruiken? Casperns kan je helpen.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-24T11:09:27Z
author_association: NONE

PR comments:
user: login: henneboy
created_at: 2025-03-21T13:04:12Z
body: Depends on https://github.com/cs-24-sw-9-xx/MAEPS/pull/294

DO NOT MERGE BEFORE 294! :)
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-21T13:06:03Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
The changes introduce a constructor for the `HeuristicConscientiousReactiveAlgorithm` class that accepts an optional `randomSeed` parameter. The `NextVertex` method now selects vertices based on minimum utility values and includes random selection among them. The return type of the `UtilityFunction` method has been updated to `IEnumerable<NormalizedValue>`. Additionally, two new test methods have been added to verify the algorithm's performance in cave and building map scenarios, ensuring successful completion within defined tick limits.

## Changes
| Files                                                        | Summary                                                                                                                                                                                                                   |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Assets/Scripts/Alg…/HeuristicConscientiousReactive.cs         | Added a constructor with an optional `randomSeed`, introduced private `_random` field; modified `NextVertex` to filter vertices by minimum utility and select one randomly; updated debug logs; changed `UtilityFunction`’s return type to `IEnumerable<NormalizedValue>`. |
| Assets/Tests/PlayModeTests/Alg…/PatrollingAlgorithmTest.cs      | Added two test methods (`Test_HeuristicConscientiousReactive_CaveMap` and `Test_HeuristicConscientiousReactive_BuildingMap`) that simulate the algorithm on cave and building maps, ensuring the simulation completes within the tick limit.               |
| Assets/Scripts/Experiments/Patrolling/HeuristicConscientiousReactiveExperiment.cs | Updated `createAlgorithmDelegate` in `Start` method to accept `randomSeed`, allowing instantiation of `HeuristicConscientiousReactiveAlgorithm` with a specific seed. |

## Possibly related PRs
- **cs-24-sw-9-xx/MAEPS#294**: Related to modifications in the `UtilityFunction` method and the structure of the `HeuristicConscientiousReactiveAlgorithm` class.
- **cs-24-sw-9-xx/MAEPS#251**: Directly connected to updates in the `HeuristicConscientiousReactiveAlgorithm` class and its usage in simulation scenarios tested in this PR.

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 65e290a651133236866f454cb8d0f4eae13bef6f and eb9d45a8e0a062f404564808f5454b3a93975c3e.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs` (4 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Run all tests ✨
* GitHub Check: Lint

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>Assets/Scripts/Algorithms/Patrolling/HeuristicConscientiousReactive.cs (5)</summary>

`45-48`: **Kijk, een constructor met een zaadje!**  
Hoi Henneboy, dit is net als een snoepfabriekje waar we een geheim nummer (randomSeed) in stoppen. Zo komen er elke keer andere snoepjes uit! Als je nog meer wilt met dit zaadje, vraag dan even aan casperns hoe je het kan bewaren.

---

`55-56`: **We hebben een random-tovenaar!**  
Hé Henneboy, `_random` is hier onze tovenaar die getallen schudt. Ziet er goed uit! Casperns kan je leren hoe je er coole trucjes mee kunt doen.

---

`75-80`: **Toffe manier om willekeurig te kiezen!**  
Hoi Henneboy, als er meerdere min-waardes zijn, kies je eentje zomaar uit, net als snoepjes grabbelen uit een zak. Let wel op dat er altijd buren zijn, anders gaat het mis als we proberen te grabbelen. Casperns kan je laten zien hoe je dat checkt!

---

`104-104`: **Mooie aanpassing van de return-waarde!**  
Henneboy, dit is net als een zak met snoepjes (de `NormalizedValue`-tjes). Prima zo, gezellig! Voor meer uitleg, roep casperns erbij.

---

`122-122`: **Samenvoegen van idleness en distance-waarde**  
Je pakt de twee getalletjes en maakt er één getal van, net als twee blokjes klei tot één knikker rollen. Casperns heeft meer tips als je wilt!

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=cs-24-sw-9-xx/MAEPS&utm_content=297):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE