From a21e5f7c9fd13370a99be8166918f288d257c3b7 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 4 Oct 2024 16:03:17 +0200 Subject: [PATCH 01/48] Try adding subpages to the website --- docs/Tutorial.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/Tutorial.md diff --git a/docs/Tutorial.md b/docs/Tutorial.md new file mode 100644 index 00000000..ef2956a7 --- /dev/null +++ b/docs/Tutorial.md @@ -0,0 +1,4 @@ +# Arbitration Graphs Tutorial + +Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ + From 7cab87ac4f2fd03cf84610edfd745f0ad97e8869 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 8 Oct 2024 16:37:35 +0200 Subject: [PATCH 02/48] Add a first outline for the tutorial website --- docs/Tutorial.md | 21 ++++++++++++++++++++ docs/tasks/1_implement_behavior_component.md | 12 +++++++++++ docs/tasks/2_extend_arbitration_graph.md | 15 ++++++++++++++ docs/tasks/3_add_more_behaviors.md | 15 ++++++++++++++ docs/tasks/4_nested_arbitrators.md | 15 ++++++++++++++ docs/tasks/5_cost_arbitration.md | 12 +++++++++++ 6 files changed, 90 insertions(+) create mode 100644 docs/tasks/1_implement_behavior_component.md create mode 100644 docs/tasks/2_extend_arbitration_graph.md create mode 100644 docs/tasks/3_add_more_behaviors.md create mode 100644 docs/tasks/4_nested_arbitrators.md create mode 100644 docs/tasks/5_cost_arbitration.md diff --git a/docs/Tutorial.md b/docs/Tutorial.md index ef2956a7..7769ead3 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -2,3 +2,24 @@ Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ +## Introduction +- [ ] What to find where in the repo? +- [ ] What is the goal of the tutorial? + +## Tasks + +1. [Implement your first behavior component](./tasks/1_implement_behavior_component.md) +2. [Extend the arbitration graph with that behavior](./tasks/2_extend_arbitration_graph.md) +3. [Add even more behavior components](./tasks/3_add_more_behaviors.md) +4. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) +5. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) + + +- [ ] Finish chase ghost finish so that is passes unit tests by re-implementing some removed part, e.g. getCommand +- [ ] Integrate chase ghost into priority arbitrator +- [ ] Integrate eat closest dot behavior +- [ ] Integrate eat dot arbitrator as random arbitrator +- [ ] Replace arbitrator from previous step with cost arbitrator, finish cost estimator + +## General TODOs +- [ ] Add a bit of an explanation about arbitration graphs to top-level readme \ No newline at end of file diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md new file mode 100644 index 00000000..15c8eb61 --- /dev/null +++ b/docs/tasks/1_implement_behavior_component.md @@ -0,0 +1,12 @@ +--- +title: "Task 1: Implement a Behavior Component" +description: Implement your first getCommand function, such that the ChaseGhost behavior component passes its unit tests. +--- + +# Chase Ghost + + +--- +[Tutorial Home](../Tutorial.md) +| +[Next task →](2_extend_arbitration_graph.md) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md new file mode 100644 index 00000000..0234078e --- /dev/null +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -0,0 +1,15 @@ +--- +title: "Task 2: Extend the Arbitration Graph" +description: Extend the arbitration graph with the ChaseGhost behavior component. +--- + +# Chase Ghost + + + +--- +[← Previous task](1_implement_behavior_component.md) +| +[Tutorial Home](../Tutorial.md) +| +[Next task →](3_add_more_behaviors.md) \ No newline at end of file diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md new file mode 100644 index 00000000..5412b5c8 --- /dev/null +++ b/docs/tasks/3_add_more_behaviors.md @@ -0,0 +1,15 @@ +--- +title: "Task 3: Even more behavior components" +description: Integrate the EatClosestDot behavior component into the arbitration graph. +--- + +# Eat Closest Dot + + + +--- +[← Previous task](2_extend_arbitration_graph.md) +| +[Tutorial Home](../Tutorial.md) +| +[Next task →](4_nested_arbitrators.md) \ No newline at end of file diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md new file mode 100644 index 00000000..faf625ea --- /dev/null +++ b/docs/tasks/4_nested_arbitrators.md @@ -0,0 +1,15 @@ +--- +title: "Task 4: Nested arbitration graphs" +description: Integrate a long-term behavior and add another layer to the arbitration graph +--- + +# Nesting + + + +--- +[← Previous task](3_add_more_behaviors.md) +| +[Tutorial Home](../Tutorial.md) +| +[Next task →](5_cost_arbitration.md) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md new file mode 100644 index 00000000..d50951d8 --- /dev/null +++ b/docs/tasks/5_cost_arbitration.md @@ -0,0 +1,12 @@ +--- +title: "Task 5: Arbitrate based on predicted utility" +description: Learn how the cost arbitrator can help you to arbitrate between behaviors based on their expected cost/utility. +--- + +# Cost Arbitrator + + +--- +[← Previous task](4_nested_arbitrators.md) +| +[Tutorial Home](../Tutorial.md) \ No newline at end of file From f351c8d281b917396c7f03884acb258e91165730 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Fri, 18 Oct 2024 20:28:16 +0200 Subject: [PATCH 03/48] Write the main landing page of the tutorial . --- docs/Tutorial.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 7769ead3..49608215 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -2,12 +2,90 @@ Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ +**TL;DR**: Find links to the individual tasks at the bottom of this page. + ## Introduction -- [ ] What to find where in the repo? -- [ ] What is the goal of the tutorial? + + +### Goal + +The goal of this tutorial is to help you understand how to use the Arbitration Graphs library. +To keep things interesting, we will re-implement some parts of our PacMan demo. + +We'll start by looking into the implementation of a single behavior component + and then learn how to integrate it into an arbitration graph using a simple priority arbitrator. + +Next, we'll start adding more and more behavior components to the graph and learn about other aspects of the library + such as cost arbitrators, nested structures and verification. + +The tutorial is structured into several tasks that are meant to be completed in order. + +### What to find where + +Let's take a look at the structure and content of the `arbitration_graphs/demo` directory. +All header files can be found in the `include/demo/` directory with corresponding implementation files in the `src/` directory. +The entire demo is thoroughly tested using the unit tests you'll find in the `test/` directory. + +Each behavior component is implemented in a separate `_behavior.hpp` file as a class inheriting from the abstract `Behavior` class. + +Next, there is `environment_model.hpp`. +You guessed it, it contains the environment model for the arbitration graph. +In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions + and other things required by the behavior components. + +Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. +It's also where you'll spend most of your time during this tutorial. + +If you are interested in how the demo works in detail, + you'll find additional code not directly relevant to the tutorial in the `include/utils/` directory + +### Development Environment + +The easiest way to get started is to use the provided docker setup. + +Start by checking out the `tutorial` branch where we have removed some parts + of the demo implementation for the purpose of this tutorial. +```bash +git checkout tutorial +``` + +To be dropped into an interactive shell with all required dependencies installed + and the current directory mounted, run +```bash +cd arbitration_graphs/demo +docker compose run --rm tutorial +``` + +You can then create a build directory and run CMake to build the project. +You should enable the `BUILD_TESTS` option to build the unit tests as well. + +```bash +cd /home/blinky/demo +mkdir -p arbitration_graphs/demo/build +cd arbitration_graphs/demo/build +cmake -DBUILD_TESTS=true .. +cmake --build . +``` + +You can then run the demo with +```bash +./arbitration_graphs_pacman_demo_exe +``` + +You'll also find the individual unit executables in this directory. +To execute them all at once, run +```bash +find -executable -type f -name '*-gtest-*' -exec {} \; +``` + +We'll leave the setup of your favorite IDE up to you + though most modern IDEs should support attaching to a running docker container. + ## Tasks +With the basics out of the way, let's work through the tasks. + 1. [Implement your first behavior component](./tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./tasks/2_extend_arbitration_graph.md) 3. [Add even more behavior components](./tasks/3_add_more_behaviors.md) @@ -22,4 +100,4 @@ Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ - [ ] Replace arbitrator from previous step with cost arbitrator, finish cost estimator ## General TODOs -- [ ] Add a bit of an explanation about arbitration graphs to top-level readme \ No newline at end of file +- [ ] Add a bit of an explanation about arbitration graphs to top-level readme From 354d79a21ea2f39b23d3edcd8dc1a89a7f7967a3 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Fri, 18 Oct 2024 20:28:38 +0200 Subject: [PATCH 04/48] Add the description for the first task of the tutorial --- docs/tasks/1_implement_behavior_component.md | 35 +++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 15c8eb61..82ea1e34 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -1,10 +1,43 @@ --- title: "Task 1: Implement a Behavior Component" -description: Implement your first getCommand function, such that the ChaseGhost behavior component passes its unit tests. +description: Implement your first checkInvocationCondition and getCommand function, such that the ChaseGhost behavior component passes its unit tests. --- # Chase Ghost +## Context + +Before we start building our arbitration graph, we want to take a closer look into behavior components. +Don't worry, most of the behavior components are already implemented for you + but we want to make sure you have an idea of how they work. + +With the current state of the arbitration graph, PacMan will just move around randomly until a ghost gets too close. +That's great and all but if we ate a power pellet, we want to chase the ghosts to eat them for extra points. + +To do this, we need to implement the `ChaseGhost` behavior component. +It essentially does the exact opposite of the `AvoidGhost` behavior component + but is only applicable when PacMan ate a power pellet. +We can ensure that's always the case using the behavior's invocation condition. + +But wait - the current implementation of the invocation condition is not complete. +It should only be applicable if there is one of these tasty ghosts close by. + +Once that's out of the way, we'll take a closer look at the `getCommand` function which is missing some core logic right now. + +## Goal + +Finish the implementation of the `checkInvocationCondition` and `getCommand` functions + of the `ChaseGhost` behavior component such that it passes its unit tests. + +## Instructions + +- Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. +- The `checkInvocationCondition` function is already implemented but does not check for the presence of a ghost. +- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::checkInvocationCondition` if you need inspiration. +- The `getCommand` function is partially implemented but the core logic is missing. +- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::getCommand` if you need inspiration. +- Compile and run the unit tests for the `ChaseGhost` behavior component to verify that your implementation is correct. + --- [Tutorial Home](../Tutorial.md) From 72585c3f1e1d6895e914e646e8e9e33065921272 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Tue, 22 Oct 2024 16:33:50 +0200 Subject: [PATCH 05/48] Add the second task --- docs/tasks/2_extend_arbitration_graph.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 0234078e..84b09546 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -5,6 +5,26 @@ description: Extend the arbitration graph with the ChaseGhost behavior component # Chase Ghost +## Context + +With our next behavior component ready to go, we need to think about integrating it into our arbitration graph. + +For this purpose, we need to modify the `PacmanAgent` class to include the `ChaseGhost` behavior component we implemented in the previous task. +Integrating a new behavior component into the arbitration graph is as simple as instantiating it and adding it as a new option to one of the arbitrators. +Since right now there is just one arbitrator - a priority arbitrator - the choice is simple. +We just need to worry about the order in which the options are assigned to the arbitrator. +Should chasing a ghost have a higher priority than avoiding a ghost or vice versa? + +## Goal + +Integrate the `ChaseGhost` behavior component into the arbitration graph defined in the `PacmanAgent` class. + +## Instructions + +- Take a look at how the other behavior components are defined in `include/demo/pacman_agent.hpp`. +- Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class and initialize it in the constructor. +- Add a new option to the priority arbitrator. +- Run the game, take a look at the new arbitration graph and observe how PacMan behaves. --- @@ -12,4 +32,4 @@ description: Extend the arbitration graph with the ChaseGhost behavior component | [Tutorial Home](../Tutorial.md) | -[Next task →](3_add_more_behaviors.md) \ No newline at end of file +[Next task →](3_add_more_behaviors.md) From bc034231837d7d0a80e61bae80e12b7cd4d354e2 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Tue, 22 Oct 2024 16:40:17 +0200 Subject: [PATCH 06/48] Add the third task --- docs/tasks/3_add_more_behaviors.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index 5412b5c8..08b829a0 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -5,6 +5,26 @@ description: Integrate the EatClosestDot behavior component into the arbitration # Eat Closest Dot +## Context + +So far, we have not looked into a behavior component that handles the most important aspect of the game: eating dots. +So now is a good a time as any to further extend our arbitration graph with the `EatClosestDot` behavior component. + +We don't want to bore you with the details of planning a path through a PacMan maze, so we have already implemented that for you. +You just need to integrate it into the arbitration graph, very similarly to the last task. + +We'll keep it simple and just add it as another option to the priority arbitrator. +Arbitration graphs can be nested of course, but we'll save that for the next task. + +## Goal + +Integrate the `EatClosestDot` behavior component into the arbitration graph defined in the `PacmanAgent` class. + +## Instructions + +- Integrate the new component just like you did in the last task. +- Start the game and see how PacMan stop wandering around aimlessly and starts eating dots. + --- @@ -12,4 +32,4 @@ description: Integrate the EatClosestDot behavior component into the arbitration | [Tutorial Home](../Tutorial.md) | -[Next task →](4_nested_arbitrators.md) \ No newline at end of file +[Next task →](4_nested_arbitrators.md) From 777ff67a2e776e77ae0a2e639e4fde114b029f6d Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Tue, 22 Oct 2024 16:47:43 +0200 Subject: [PATCH 07/48] Add the fourth task --- docs/tasks/4_nested_arbitrators.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index faf625ea..42577cd2 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -5,6 +5,30 @@ description: Integrate a long-term behavior and add another layer to the arbitra # Nesting +## Context + +We have now implemented a few behavior components and integrated them into the arbitration graph. +So far, all behavior components are children of the root arbitrator. + +Let's make things a bit more interesting by adding a long-term behavior component that's also about eating dots. +The `ChangeDotCluster` behavior will move to an area in the maze where there is a higher density of dots. + +For now, we'll just decide between the two dot eating strategies using chance. +We can achieve that by adding them to a random arbitrator which is then added as an option to the root arbitrator. + +There are more sophisticated ways to decide between behavior components, we'll cover those in the next task. + +## Goal + +Add the `EatClosestDot` and `ChangeDotCluster` behavior components to a random arbitrator nested within the root arbitrator. + +## Instructions + +- Add the `ChangeDotCluster` behavior component as a new member of the `PacmanAgent` class and initialize it in the constructor. +- Add a random arbitrator as a new member of the `PacmanAgent` class, analogous to the priority arbitrator. +- Add the `EatClosestDot` and `ChangeDotCluster` behavior components as options to the random arbitrator. +- Add the random arbitrator as an option to the root arbitrator. +- Run the game and observe how PacMan behaves. --- From 7736b5148b1025fe262e08eba211c293c23dd878 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Thu, 24 Oct 2024 10:19:57 +0200 Subject: [PATCH 08/48] Add the fifth task --- docs/Tutorial.md | 2 ++ docs/tasks/5_cost_arbitration.md | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 49608215..ef5f14e5 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -33,6 +33,8 @@ You guessed it, it contains the environment model for the arbitration graph. In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions and other things required by the behavior components. +The `cost_estimator.hpp` file will be relevant for a later task when we cover cost arbitrators. + Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. It's also where you'll spend most of your time during this tutorial. diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index d50951d8..8c95ee59 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -5,8 +5,35 @@ description: Learn how the cost arbitrator can help you to arbitrate between beh # Cost Arbitrator +## Context + +The `EatDot` arbitrator we added in the previous task decides between the two dot eating strategies randomly. +That's obviously not the greatest idea. +There must be a better way. + +Turns out, there is! +There is another type of arbitrator that might be more suitable for this task: the cost arbitrator. + +As the name suggests, the cost arbitrator computes a cost for each command received from its children and selects the one with the lowest cost. +We need some kind of cost function for this, which we will implement in the `CostEstimator` class. + +The idea is to reward a planned path that contains lots of dots while also moving into an area with a high dot density. +We prepared the general structure of the `CostEstimator` class for you, you just need to fill in the blanks. + +Let's get started! + +## Goal + +Finish the implementation of the `CostEstimator` and replace the random arbitrator with a cost arbitrator. + +## Instructions + +- In `cost_estimator.cpp`, fill in the blanks to compute `nDots` and `nCells`. +- Add an instance of the `CostEstimator` to the `PacmanAgent` class and initialize it in the constructor. +- Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption` method. + --- [← Previous task](4_nested_arbitrators.md) | -[Tutorial Home](../Tutorial.md) \ No newline at end of file +[Tutorial Home](../Tutorial.md) From 9d45ee38a1561e9cdb1da6be030abc0e9bf77220 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Thu, 24 Oct 2024 14:21:21 +0200 Subject: [PATCH 09/48] Add the sixth task --- docs/Tutorial.md | 2 + docs/tasks/5_cost_arbitration.md | 2 + docs/tasks/6_verification.md | 67 ++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 docs/tasks/6_verification.md diff --git a/docs/Tutorial.md b/docs/Tutorial.md index ef5f14e5..c7d42ac4 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -35,6 +35,8 @@ In it, we store things like current positions of PacMan and the ghosts, the maze The `cost_estimator.hpp` file will be relevant for a later task when we cover cost arbitrators. +Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph near the end of the tutorial. + Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. It's also where you'll spend most of your time during this tutorial. diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index 8c95ee59..ecc70201 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -37,3 +37,5 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat [← Previous task](4_nested_arbitrators.md) | [Tutorial Home](../Tutorial.md) +| +[Next task →](6_verification.md) diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md new file mode 100644 index 00000000..0fc10efa --- /dev/null +++ b/docs/tasks/6_verification.md @@ -0,0 +1,67 @@ +--- +title: "Task 6: Better safe than sorry" +description: Execute only safe commands and add a fallback strategy. +--- + +# Verification and Fallback Layers + +## Context + +The arbitration graph is now complete and PacMan is eating dots like a pro. +But there is one last topic we want to talk about: safety and robustness. + +Depending on your application, you might be interested in only executing commands that you know fulfill certain criteria. +The concrete requirements depend on your application and could be anything from physical constraints to safety requirements. +In our case, we only want to execute commands where PacMan does not run into walls. + +We can ensure that commands obey these requirements by adding a verifier to the arbitrators. +The arbitrator will then run the verification step and only choose commands that pass this step. + +The leads us to another issue. +What to do if the command we wanted to execute does not pass the verification step? + +Glad you asked! +The first and thing that will happen without us doing anything is that the arbitrator will just choose the next best option. +E.g., if the `EatClosestDot` is not safe, the `EatDot` arbitrator could just pass the `ChangeDotCluster` command to the root arbitrator + assuming the latter is both applicable and does itself pass verification. + +If that's not the case, we can think about adding additional behavior components as fallback layers to enable graceful degradation of the system. +The first one is already there: `MoveRandomly` is something we probably don't really want to do under normal circumstances. +But if we run out of ideas, it is still a valid option. +It might also give our main behavior components a chance to recover or to solve deadlock situations. + +Finally, it is a good idea to add a last resort fallback layer. +This behavior component should be a simple implementation that is always applicable and does not require a lot of context knowledge. +If the system is in a failing state, the latter might not be available. +We can mark behavior components as last resort fallback layers which will lead to these components not having to pass verification. +After all, they are our last straw and it's better to execute that than to do nothing. + +In our case, we will add a `StayInPlace` behavior component. +PacMan is not actually able to stop, so he will just keep moving back and forth. +Probably not an ideal strategy to win the game but we can be sure to have a comprehensible command at all times. +Also, PacMan will never run into a wall with this behavior component. + +Phew, that was long read. Time to get our hands dirty! + + +## Goal + +Finish the implementation of the `Verifier` class and have the existing arbitrators use it. +Add the `MoveRandomly` behavior component as a last resort fallback layer. + +## Instructions + +- In `verifier.cpp`, finish the implementation of the `Verifier::analyze` method. +- Add an instance of the `Verifier` to the `PacmanAgent` class and initialize it in the constructor. +- Pass the `Verifier` instance to the constructors of the arbitrators. + (Hint: You'll need to adjust the template parameters of the arbitrators.) +- Add the `MoveRandomly` behavior component analogously to the other behavior components. +- Mark the `MoveRandomly` behavior component as a last resort fallback layer. +- Try breaking a behavior component on purpose and see how the system reacts. + (Try throwing an exception in the `getCommand` method of a behavior component or returning a command that will lead to a collision with a wall.) + + +--- +[← Previous task](5_cost_arbitration.md) +| +[Tutorial Home](../Tutorial.md) From d0d4047c8091256ddfe56ec0c9cc7c1ceefe583f Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Thu, 24 Oct 2024 15:46:00 +0200 Subject: [PATCH 10/48] Add solutions to all tasks --- docs/tasks/1_implement_behavior_component.md | 56 +++++++++++++ docs/tasks/2_extend_arbitration_graph.md | 35 +++++++++ docs/tasks/3_add_more_behaviors.md | 37 +++++++++ docs/tasks/4_nested_arbitrators.md | 56 +++++++++++++ docs/tasks/5_cost_arbitration.md | 83 ++++++++++++++++++++ docs/tasks/6_verification.md | 80 +++++++++++++++++++ 6 files changed, 347 insertions(+) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 82ea1e34..6ba2c9e0 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -38,6 +38,62 @@ Finish the implementation of the `checkInvocationCondition` and `getCommand` fun - Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::getCommand` if you need inspiration. - Compile and run the unit tests for the `ChaseGhost` behavior component to verify that your implementation is correct. +## Solution + +
+Click here to expand the solution + +Fix the invocation condition in `src/chase_ghost_behavior.cpp`: +```cpp +bool ChaseGhostBehavior::checkInvocationCondition(const Time& time) const { + return environmentModel_->closestScaredGhost(time).has_value() && + environmentModel_->closestScaredGhost(time)->ghost.scaredCountdown > parameters_.minScaredTicksLeft && + environmentModel_->closestScaredGhost(time)->distance < parameters_.invocationMinDistance; // Only applicable if a ghost is close by +} +``` + +Add the missing pice of the getCommand function in `src/chase_ghost_behavior.cpp`: +```cpp +Command ChaseGhostBehavior::getCommand(const Time& time) { + auto pacmanPosition = environmentModel_->pacmanPosition(); + + auto closestScaredGhost = environmentModel_->closestScaredGhost(time); + if (!closestScaredGhost) { + throw std::runtime_error("Can not compute command to chase ghost because there are no scared ghosts."); + } + + auto ghostPosition = closestScaredGhost->ghost.position; + + std::optional direction; + + // Add this part: + // Chose the direction moving pacman towards the closest scared ghost + double minDistance = std::numeric_limits::max(); + for (const auto& move : Move::possibleMoves()) { + auto nextPosition = environmentModel_->positionConsideringTunnel(pacmanPosition + move.deltaPosition); + + if (environmentModel_->isWall(nextPosition)) { + continue; + } + + // Chose the direction moving pacman towards the closest scared ghost (considering ghost movement) + auto nextDistance = environmentModel_->mazeDistance(nextPosition, ghostPosition); + if (nextDistance < minDistance) { + direction = move.direction; + minDistance = nextDistance; + } + } + + if (!direction) { + throw std::runtime_error("Failed to compute direction to chase the closest ghost."); + } + + return Command{direction.value()}; +} + +``` +
+ --- [Tutorial Home](../Tutorial.md) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 84b09546..99c28ff8 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -26,6 +26,41 @@ Integrate the `ChaseGhost` behavior component into the arbitration graph defined - Add a new option to the priority arbitrator. - Run the game, take a look at the new arbitration graph and observe how PacMan behaves. +## Solution + +
+Click here to expand the solution + +Include the header of the `ChaseGhost` behavior component in `include/demo/pacman_agent.hpp`: +```cpp +#include "chase_ghost_behavior.hpp" +``` + +Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class: +```cpp +private: + ChaseGhostBehavior::Ptr chaseGhostBehavior_; +``` + +In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator: +```cpp +explicit PacmanAgent(const entt::Game& game) + : parameters_{}, environmentModel_{std::make_shared(game)} { + + avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); + // Initialize the ChaseGhost behavior component + chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); + moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); + + rootArbitrator_ = std::make_shared("Pacman"); + // Add the ChaseGhost behavior component to the priority arbitrator (before the AvoidGhost behavior component!) + rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); +} +``` +
+ --- [← Previous task](1_implement_behavior_component.md) diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index 08b829a0..6e5d8d88 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -25,6 +25,43 @@ Integrate the `EatClosestDot` behavior component into the arbitration graph defi - Integrate the new component just like you did in the last task. - Start the game and see how PacMan stop wandering around aimlessly and starts eating dots. +## Solution + +
+Click here to expand the solution + +Include the header of the `EatClosestDot` behavior component in `include/demo/pacman_agent.hpp`: +```cpp +#include "eat_closest_dot_behavior.hpp" +``` + +Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class: +```cpp +private: + EatClosestDotBehavior::Ptr eatClosestDotBehavior_; +``` + +In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator: +```cpp +explicit PacmanAgent(const entt::Game& game) + : parameters_{}, environmentModel_{std::make_shared(game)} { + + avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); + chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); + // Initialize the EatClosestDot behavior component + eatClosestDotBehavior_ = std::make_shared(environmentModel_); + moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); + + rootArbitrator_ = std::make_shared("Pacman"); + rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + // Add the EatClosestDot behavior component to the priority arbitrator (after the ghost behavior components!) + rootArbitrator_->addOption(eatClosestDotBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); +} +``` +
+ --- diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index 42577cd2..d4d114e8 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -30,6 +30,62 @@ Add the `EatClosestDot` and `ChangeDotCluster` behavior components to a random a - Add the random arbitrator as an option to the root arbitrator. - Run the game and observe how PacMan behaves. +## Solution + +
+Click here to expand the solution + +Include the header of the `ChangeDotCluster` behavior component and the random arbitrator in `include/demo/pacman_agent.hpp`: +```cpp +#include + +#include "change_dot_cluster_behavior.hpp" +``` + +For easier to read code, add the following alias near the top of the class definition: +```cpp +using RandomArbitrator = arbitration_graphs::RandomArbitrator; +``` + +Add the `ChangeDotCluster` behavior component and the `RandomArbitrator` as a new members of the `PacmanAgent` class: +```cpp +private: + ChangeDotClusterBehavior::Ptr changeDotClusterBehavior_; + + RandomArbitrator::Ptr eatDotsArbitrator_; +``` + +In the constructor of the `PacmanAgent` class, initialize the `ChangeDotCluster` behavior component and the `RandomArbitrator`: +Add the `EatClosestDot` and `ChangeDotCluster` behavior components as options to the random arbitrator. +Finally, add the random arbitrator as an option to the root arbitrator: +```cpp +explicit PacmanAgent(const entt::Game& game) + : parameters_{}, environmentModel_{std::make_shared(game)} { + + avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); + // Initialize the ChangeDotCluster behavior component + changeDotClusterBehavior_ = std::make_shared(environmentModel_); + chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); + eatClosestDotBehavior_ = std::make_shared(environmentModel_); + moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); + + // Initialize the random arbitrator and add the EatClosestDot and ChangeDotCluster behavior components as options + eatDotsArbitrator_ = std::make_shared("EatDots"); + eatDotsArbitrator_->addOption( changeDotClusterBehavior_, RandomArbitrator::Option::Flags::INTERRUPTABLE); + eatDotsArbitrator_->addOption( eatClosestDotBehavior_, RandomArbitrator::Option::Flags::INTERRUPTABLE); + + rootArbitrator_ = std::make_shared("Pacman"); + rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + // The EatDot arbitrator is itself an option of the root arbitrator + rootArbitrator_->addOption(eatDotsArbitrator_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); +} +``` + + +
+ --- [← Previous task](3_add_more_behaviors.md) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index ecc70201..65dc7438 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -32,6 +32,89 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat - Add an instance of the `CostEstimator` to the `PacmanAgent` class and initialize it in the constructor. - Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption` method. +## Solution + +
+Click here to expand the solution + +Finish the implementation of the `CostEstimator` class in `cost_estimator.cpp`: +```cpp +double CostEstimator::estimateCost(const Command& command, bool /*isActive*/) { + Positions absolutePath = utils::toAbsolutePath(command.path, environmentModel_); + + // Compute the number of dots along the path and in the neighborhood of the path end using helper functions + const int nDotsAlongPath = utils::dotsAlongPath(absolutePath, environmentModel_); + const int nDotsInRadius = + utils::dotsInRadius(absolutePath.back(), environmentModel_, parameters_.pathEndNeighborhoodRadius); + const int nDots = nDotsAlongPath + nDotsInRadius; + + if (nDots == 0) { + return std::numeric_limits::max(); + } + + // Compute the size of the path and the neighborhood of the path end + const int pathLength = static_cast(absolutePath.size()); + const int neighborhoodSize = static_cast(std::pow(2 * parameters_.pathEndNeighborhoodRadius + 1, 2)); + const int nCells = pathLength + neighborhoodSize; + + // We can define a cost as the inverse of a benefit. + // Our benefit is a dot density (number of dots / number of examined cells) + return static_cast(nCells) / nDots; +} +``` + +Replace the include of the random arbitrator with the cost arbitrator in `include/demo/pacman_agent.hpp`. +Also, include `cost_estimator.hpp`: +```cpp +#include + +#include "cost_estimator.hpp" +``` + +Change the type of the `eatDotsArbitrator_` member in the `PacmanAgent` class to `CostArbitrator` and add an instance of the `CostEstimator`: +```cpp +private: + CostArbitrator::Ptr eatDotsArbitrator_; + + CostEstimator::Ptr costEstimator_; +``` + +As always, the magic happens in the constructor of the `PacmanAgent` class. +Instantiate the cost estimator and pass it in the `addOption` calls: +```cpp +explicit PacmanAgent(const entt::Game& game) + : parameters_{}, environmentModel_{std::make_shared(game)} { + + avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); + changeDotClusterBehavior_ = std::make_shared(environmentModel_); + chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); + eatClosestDotBehavior_ = std::make_shared(environmentModel_); + moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); + + // This is now a cost arbitrator + eatDotsArbitrator_ = std::make_shared("EatDots"); + // Construct the cost estimator + costEstimator_ = std::make_shared(environmentModel_, parameters_.costEstimator); + // Add the ChangeDotCluster and EatClosestDot behavior components as options to the + // cost arbitrator while also passing the cost estimator + eatDotsArbitrator_->addOption( + changeDotClusterBehavior_, CostArbitrator::Option::Flags::INTERRUPTABLE, costEstimator_); + eatDotsArbitrator_->addOption( + eatClosestDotBehavior_, CostArbitrator::Option::Flags::INTERRUPTABLE, costEstimator_); + + rootArbitrator_ = std::make_shared("Pacman"); + rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(eatDotsArbitrator_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(stayInPlaceBehavior_, + PriorityArbitrator::Option::Flags::INTERRUPTABLE | + PriorityArbitrator::Option::FALLBACK); +} +``` + +
+ --- [← Previous task](4_nested_arbitrators.md) diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 0fc10efa..432a9f0b 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -60,6 +60,86 @@ Add the `MoveRandomly` behavior component as a last resort fallback layer. - Try breaking a behavior component on purpose and see how the system reacts. (Try throwing an exception in the `getCommand` method of a behavior component or returning a command that will lead to a collision with a wall.) +## Solution + +
+Click here to expand the solution + +In the `Verifier::analyze` method (in `include/demo/verifier.hpp`), we simply check if the command would lead to an invalid position: +```cpp +VerificationResult analyze(const Time /*time*/, const Command& command) const { + Move nextMove = Move{command.path.front()}; + Position nextPosition = environmentModel_->pacmanPosition() + nextMove.deltaPosition; + + // The command is considered safe if the next position is in bounds and not a wall + if (environmentModel_->isPassableCell(nextPosition)) { + return VerificationResult{true}; + } + + return VerificationResult{false}; +} +``` + +Include the verifier header you just implemented, in `include/demo/pacman_agent.hpp`. +Also, include `stay_in_place_behavior.hpp`. +```cpp +#include "stay_in_place_behavior.hpp" +#include "verifier.hpp" +``` + +Adjust the template parameters in the alias definitions to contain the verifier types: +```cpp +public: + using CostArbitrator = arbitration_graphs::CostArbitrator; + using PriorityArbitrator = arbitration_graphs::PriorityArbitrator; +``` + +Add the verifier and the fallback behavior component as members of the `PacmanAgent` class: +```cpp +private: + StayInPlaceBehavior::Ptr stayInPlaceBehavior_; + + Verifier verifier_; +``` + +In the constructor of the `PacmanAgent` class, initialize the verifier and the `StayInPlace` behavior component. +Make sure to also pass the verifier to the arbitrator constructors: +```cpp + explicit PacmanAgent(const entt::Game& game) + : parameters_{}, + environmentModel_{std::make_shared(game)}, + verifier_{environmentModel_} // We can initialize the verifier in the member initializer list { + + avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); + changeDotClusterBehavior_ = std::make_shared(environmentModel_); + chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); + eatClosestDotBehavior_ = std::make_shared(environmentModel_); + moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); + // Initialize the StayInPlace behavior component + stayInPlaceBehavior_ = std::make_shared(environmentModel_); + + // Pass the verifier instance to the cost arbitrator + eatDotsArbitrator_ = std::make_shared("EatDots", verifier_); + costEstimator_ = std::make_shared(environmentModel_, parameters_.costEstimator); + eatDotsArbitrator_->addOption( + changeDotClusterBehavior_, CostArbitrator::Option::Flags::INTERRUPTABLE, costEstimator_); + eatDotsArbitrator_->addOption( + eatClosestDotBehavior_, CostArbitrator::Option::Flags::INTERRUPTABLE, costEstimator_); + + // Pass the verifier instance to the priority arbitrator + rootArbitrator_ = std::make_shared("Pacman", verifier_); + rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(eatDotsArbitrator_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); + // Add the StayInPlace behavior component. Mark it as a last resort fallback layer using the FALLBACK flag. + rootArbitrator_->addOption(stayInPlaceBehavior_, + PriorityArbitrator::Option::Flags::INTERRUPTABLE | + PriorityArbitrator::Option::FALLBACK); + } +``` +
+ --- [← Previous task](5_cost_arbitration.md) From f168d1ea9a7ea1187e5201a3b322367edf5f75ec Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Thu, 24 Oct 2024 15:54:03 +0200 Subject: [PATCH 11/48] Add hint about adding parameters to the main parameter struct --- docs/tasks/2_extend_arbitration_graph.md | 11 +++++++++++ docs/tasks/5_cost_arbitration.md | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 99c28ff8..4d7b6e38 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -23,6 +23,7 @@ Integrate the `ChaseGhost` behavior component into the arbitration graph defined - Take a look at how the other behavior components are defined in `include/demo/pacman_agent.hpp`. - Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class and initialize it in the constructor. +- Extend the `PacmanAgent` parameter struct to include the parameters for the `ChaseGhost` behavior component. - Add a new option to the priority arbitrator. - Run the game, take a look at the new arbitration graph and observe how PacMan behaves. @@ -42,6 +43,16 @@ private: ChaseGhostBehavior::Ptr chaseGhostBehavior_; ``` +Extend the `PacmanAgent` parameter struct to include the parameters for the `ChaseGhost` behavior component: +```cpp +struct Parameters { + AvoidGhostBehavior::Parameters avoidGhostBehavior; + // Add the parameters for the ChaseGhost behavior component + ChaseGhostBehavior::Parameters chaseGhostBehavior; + MoveRandomlyBehavior::Parameters moveRandomlyBehavior; +}; +``` + In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator: ```cpp explicit PacmanAgent(const entt::Game& game) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index 65dc7438..28debff1 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -30,6 +30,7 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat - In `cost_estimator.cpp`, fill in the blanks to compute `nDots` and `nCells`. - Add an instance of the `CostEstimator` to the `PacmanAgent` class and initialize it in the constructor. + Don't forget to include the necessary headers and extend the parameter struct with the parameters for the `CostEstimator`. - Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption` method. ## Solution @@ -79,6 +80,18 @@ private: CostEstimator::Ptr costEstimator_; ``` +Extend the `Parameters` struct to contain the parameters for the `CostEstimator`: +```cpp +struct Parameters { + AvoidGhostBehavior::Parameters avoidGhostBehavior; + ChaseGhostBehavior::Parameters chaseGhostBehavior; + MoveRandomlyBehavior::Parameters moveRandomlyBehavior; + + // Add the parameters for the CostEstimator + CostEstimator::Parameters costEstimator; +}; +``` + As always, the magic happens in the constructor of the `PacmanAgent` class. Instantiate the cost estimator and pass it in the `addOption` calls: ```cpp From efcd1b4179dfa67b4bbb09780a28417d583570e5 Mon Sep 17 00:00:00 2001 From: Nick Le Large Date: Thu, 24 Oct 2024 16:08:37 +0200 Subject: [PATCH 12/48] Remove todos from the tutorial landing page --- docs/Tutorial.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index c7d42ac4..a836d604 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -96,12 +96,3 @@ With the basics out of the way, let's work through the tasks. 4. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) 5. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) - -- [ ] Finish chase ghost finish so that is passes unit tests by re-implementing some removed part, e.g. getCommand -- [ ] Integrate chase ghost into priority arbitrator -- [ ] Integrate eat closest dot behavior -- [ ] Integrate eat dot arbitrator as random arbitrator -- [ ] Replace arbitrator from previous step with cost arbitrator, finish cost estimator - -## General TODOs -- [ ] Add a bit of an explanation about arbitration graphs to top-level readme From 42b8f3cda18bc27708ad4bb89a581b663db97b10 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Sun, 10 Nov 2024 08:20:02 +0100 Subject: [PATCH 13/48] Link to the tutorial from main Readme --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 73fcdd57..96128e58 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,18 @@ In this scene,

-We will shortly add a [tutorial](https://github.com/KIT-MRT/arbitration_graphs/pull/51) based on this demo – stay tuned! +## Tutorial + +Follow our [Tutorial](./docs/Tutorial.md) and learn how to use the Arbitration Graphs library! +It's based on this demo and guides you through all important concepts: + +0. [Introduction – start here!](./docs/Tutorial.md) +1. [Implement your first behavior component](./docs/tasks/1_implement_behavior_component.md) +2. [Extend the arbitration graph with that behavior](./docs/tasks/2_extend_arbitration_graph.md) +3. [Add even more behavior components](./docs/tasks/3_add_more_behaviors.md) +4. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) +5. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) +6. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) ## Installation From 339468f2c6a9e1ea8f26b3c23d42b2d8767f572c Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Sun, 10 Nov 2024 08:26:48 +0100 Subject: [PATCH 14/48] Rename demo executable to arbitration_graphs_pacman_demo --- demo/CMakeLists.txt | 16 ++++++++-------- demo/Dockerfile | 2 +- demo/test/CMakeLists.txt | 2 +- docs/Tutorial.md | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index bbdc0040..f409eb7a 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -59,7 +59,7 @@ find_package(Yaml-cpp REQUIRED) ## Build ## ########### -add_library(${PROJECT_NAME} SHARED +add_library(${PROJECT_NAME}_lib SHARED src/astar.cpp src/avoid_ghost_behavior.cpp src/change_dot_cluster_behavior.cpp @@ -71,11 +71,11 @@ add_library(${PROJECT_NAME} SHARED src/move_randomly_behavior.cpp src/utils.cpp ) -target_include_directories(${PROJECT_NAME} PRIVATE +target_include_directories(${PROJECT_NAME}_lib PRIVATE include ${SDL2_INCLUDE_DIR} ) -target_link_libraries(${PROJECT_NAME} PUBLIC +target_link_libraries(${PROJECT_NAME}_lib PUBLIC arbitration_graphs glog::glog @@ -86,16 +86,16 @@ target_link_libraries(${PROJECT_NAME} PUBLIC ${SDL2_LIBRARY} ) -add_executable(${PROJECT_NAME}_exe +add_executable(${PROJECT_NAME} src/main.cpp src/pacman_wrapper.cpp ) -target_include_directories(${PROJECT_NAME}_exe PRIVATE +target_include_directories(${PROJECT_NAME} PRIVATE include ${SDL2_INCLUDE_DIR} ) -target_link_libraries(${PROJECT_NAME}_exe PRIVATE - ${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE + ${PROJECT_NAME}_lib ) @@ -133,7 +133,7 @@ endif() ## Install ## ############# -install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_exe +install(TARGETS ${PROJECT_NAME}_lib ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets COMPONENT demo LIBRARY DESTINATION lib COMPONENT Runtime diff --git a/demo/Dockerfile b/demo/Dockerfile index 2f9e68ba..89018980 100644 --- a/demo/Dockerfile +++ b/demo/Dockerfile @@ -61,5 +61,5 @@ WORKDIR /home/blinky/demo/build RUN cmake -DCMAKE_BUILD_TYPE=Release .. && \ cmake --build . -j8 -CMD ["bash", "-c", "/home/blinky/.motd && /home/blinky/demo/build/arbitration_graphs_pacman_demo_exe"] +CMD ["bash", "-c", "/home/blinky/.motd && /home/blinky/demo/build/arbitration_graphs_pacman_demo"] diff --git a/demo/test/CMakeLists.txt b/demo/test/CMakeLists.txt index 14e4cece..30f3ee05 100644 --- a/demo/test/CMakeLists.txt +++ b/demo/test/CMakeLists.txt @@ -88,7 +88,7 @@ if(GTEST_FOUND) target_link_libraries(${TEST_TARGET_NAME} PUBLIC ${GTEST_BOTH_LIBRARIES} pthread - arbitration_graphs_pacman_demo + arbitration_graphs_pacman_demo_lib arbitration_graphs EnTT_Pacman util_caching diff --git a/docs/Tutorial.md b/docs/Tutorial.md index a836d604..c2fbf9e1 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -73,7 +73,7 @@ cmake --build . You can then run the demo with ```bash -./arbitration_graphs_pacman_demo_exe +./arbitration_graphs_pacman_demo ``` You'll also find the individual unit executables in this directory. From f2f775abbaa684a0c8b5e7e0abe0ac08ee0b86f2 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Sun, 10 Nov 2024 08:51:37 +0100 Subject: [PATCH 15/48] Tune tutorial introduction --- docs/Tutorial.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index c2fbf9e1..6c00087d 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -2,7 +2,7 @@ Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ -**TL;DR**: Find links to the individual tasks at the bottom of this page. +**TL;DR:** Find links to the individual tasks at the bottom of this page. ## Introduction @@ -22,11 +22,20 @@ The tutorial is structured into several tasks that are meant to be completed in ### What to find where -Let's take a look at the structure and content of the `arbitration_graphs/demo` directory. -All header files can be found in the `include/demo/` directory with corresponding implementation files in the `src/` directory. +Let's take a look at the structure and content of the `arbitration_graphs/demo/` directory. + +``` +demo +├── include +├── src +├── test +└── â€Ļ +``` + +All header files can be found in the `include/` directory with corresponding implementation files in the `src/` directory. The entire demo is thoroughly tested using the unit tests you'll find in the `test/` directory. -Each behavior component is implemented in a separate `_behavior.hpp` file as a class inheriting from the abstract `Behavior` class. +Each behavior component is implemented in a separate `_behavior.hpp` file as a class inheriting from the abstract `Behavior` class. Next, there is `environment_model.hpp`. You guessed it, it contains the environment model for the arbitration graph. @@ -50,10 +59,10 @@ The easiest way to get started is to use the provided docker setup. Start by checking out the `tutorial` branch where we have removed some parts of the demo implementation for the purpose of this tutorial. ```bash -git checkout tutorial +git clone --branch tutorial https://github.com/KIT-MRT/arbitration_graphs.git ``` -To be dropped into an interactive shell with all required dependencies installed +To start an interactive shell in the docker container with all required dependencies installed and the current directory mounted, run ```bash cd arbitration_graphs/demo From 6e150df9d883452eefd1c59faf731e27029f6f11 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Sun, 10 Nov 2024 08:51:53 +0100 Subject: [PATCH 16/48] Add crosslinks and missing link to tutorial introduction --- docs/Tutorial.md | 6 +++--- docs/tasks/2_extend_arbitration_graph.md | 2 +- docs/tasks/3_add_more_behaviors.md | 6 +++--- docs/tasks/4_nested_arbitrators.md | 2 +- docs/tasks/5_cost_arbitration.md | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 6c00087d..9fb742e1 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -42,9 +42,9 @@ You guessed it, it contains the environment model for the arbitration graph. In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions and other things required by the behavior components. -The `cost_estimator.hpp` file will be relevant for a later task when we cover cost arbitrators. +The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/5_cost_arbitration.md). -Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph near the end of the tutorial. +Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph [near the end](./tasks/6_verification.md) of the tutorial. Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. It's also where you'll spend most of your time during this tutorial. @@ -104,4 +104,4 @@ With the basics out of the way, let's work through the tasks. 3. [Add even more behavior components](./tasks/3_add_more_behaviors.md) 4. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) 5. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) - +6. [Verify commands and add a fallback strategy](./tasks/6_verification.md) \ No newline at end of file diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 4d7b6e38..d700472c 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -9,7 +9,7 @@ description: Extend the arbitration graph with the ChaseGhost behavior component With our next behavior component ready to go, we need to think about integrating it into our arbitration graph. -For this purpose, we need to modify the `PacmanAgent` class to include the `ChaseGhost` behavior component we implemented in the previous task. +For this purpose, we need to modify the `PacmanAgent` class to include the `ChaseGhost` behavior component we implemented in the [previous task](1_implement_behavior_component.md). Integrating a new behavior component into the arbitration graph is as simple as instantiating it and adding it as a new option to one of the arbitrators. Since right now there is just one arbitrator - a priority arbitrator - the choice is simple. We just need to worry about the order in which the options are assigned to the arbitrator. diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index 6e5d8d88..1e886589 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -11,10 +11,10 @@ So far, we have not looked into a behavior component that handles the most impor So now is a good a time as any to further extend our arbitration graph with the `EatClosestDot` behavior component. We don't want to bore you with the details of planning a path through a PacMan maze, so we have already implemented that for you. -You just need to integrate it into the arbitration graph, very similarly to the last task. +You just need to integrate it into the arbitration graph, very similarly to the [previous task](2_extend_arbitration_graph.md). We'll keep it simple and just add it as another option to the priority arbitrator. -Arbitration graphs can be nested of course, but we'll save that for the next task. +Arbitration graphs can be nested of course, but we'll save that for the [next task](4_nested_arbitrators.md). ## Goal @@ -22,7 +22,7 @@ Integrate the `EatClosestDot` behavior component into the arbitration graph defi ## Instructions -- Integrate the new component just like you did in the last task. +- Integrate the new component just like you did in the [previous task](2_extend_arbitration_graph.md). - Start the game and see how PacMan stop wandering around aimlessly and starts eating dots. ## Solution diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index d4d114e8..39e8b81b 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -16,7 +16,7 @@ The `ChangeDotCluster` behavior will move to an area in the maze where there is For now, we'll just decide between the two dot eating strategies using chance. We can achieve that by adding them to a random arbitrator which is then added as an option to the root arbitrator. -There are more sophisticated ways to decide between behavior components, we'll cover those in the next task. +There are more sophisticated ways to decide between behavior components, we'll cover those in the [next task](5_cost_arbitration.md). ## Goal diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index 28debff1..b846cdd1 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -7,7 +7,7 @@ description: Learn how the cost arbitrator can help you to arbitrate between beh ## Context -The `EatDot` arbitrator we added in the previous task decides between the two dot eating strategies randomly. +The `EatDot` arbitrator we added in the [previous task](4_nested_arbitrators.md) decides between the two dot eating strategies randomly. That's obviously not the greatest idea. There must be a better way. From b01eb3d53af5131c258e80cb9a37f2e86dbde3c5 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Sun, 10 Nov 2024 08:52:12 +0100 Subject: [PATCH 17/48] Improve compile and run commands in tutorial introduction --- docs/Tutorial.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 9fb742e1..47566fd5 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -74,10 +74,10 @@ You should enable the `BUILD_TESTS` option to build the unit tests as well. ```bash cd /home/blinky/demo -mkdir -p arbitration_graphs/demo/build -cd arbitration_graphs/demo/build +mkdir build +cd build cmake -DBUILD_TESTS=true .. -cmake --build . +cmake --build . -j9 ``` You can then run the demo with @@ -88,7 +88,7 @@ You can then run the demo with You'll also find the individual unit executables in this directory. To execute them all at once, run ```bash -find -executable -type f -name '*-gtest-*' -exec {} \; +cmake --build . --target test ``` We'll leave the setup of your favorite IDE up to you From 72edc1eda809a7e67b5b1d54df7e1a032f3b4059 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 17:05:32 +0100 Subject: [PATCH 18/48] Add a short Readme for the Demo (in case it's opened as top-level dir in an IDE) --- demo/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 demo/README.md diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 00000000..834175e3 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,20 @@ +# Arbitration Graphs Demo and Tutorial + +This is a demo of the [arbitration_graphs](https://github.com/KIT-MRT/arbitration_graphs) library using Pac-Man as an example application. +The arbitration graph controls Pac-Man on its journey to collect tasty dots đŸŦ + +Run the demo with: + +```bash +git clone https://github.com/KIT-MRT/arbitration_graphs.git +cd arbitration_graphs/demo +docker compose up +``` + +Open the GUI with your favorite browser: +[http://0.0.0.0:8080](http://0.0.0.0:8080) + + +## Tutorial + +If you're here for the tutorial, follow the instructions on our [Tutorial GitHub Page](https://kit-mrt.github.io/arbitration_graphs/docs/Tutorial.md). \ No newline at end of file From 92d524517225c82e2a532f697434429ec0f71219 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 16:22:18 +0100 Subject: [PATCH 19/48] Move tutorial Docker service to own compose file again This is due to VSCode not supporting docker profiles (yet?). Thus we have issues setting up a nice DevContainer that doesn't start the demo as well. --- demo/docker-compose.tutorial.yaml | 13 +++++++++++++ demo/docker-compose.yaml | 13 +++---------- 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 demo/docker-compose.tutorial.yaml diff --git a/demo/docker-compose.tutorial.yaml b/demo/docker-compose.tutorial.yaml new file mode 100644 index 00000000..8bf2b966 --- /dev/null +++ b/demo/docker-compose.tutorial.yaml @@ -0,0 +1,13 @@ +services: + tutorial: + image: ghcr.io/kit-mrt/arbitration_graphs_pacman_tutorial:$VERSION + env_file: .env + ports: + - "8080:8080" + volumes: + - .:/home/blinky/demo + - $HOME/.Xauthority:/home/blinky/.Xauthority + - /tmp/.X11-unix:/tmp/.X11-unix + environment: + - DISPLAY=$DISPLAY + diff --git a/demo/docker-compose.yaml b/demo/docker-compose.yaml index f18bde66..f7193356 100644 --- a/demo/docker-compose.yaml +++ b/demo/docker-compose.yaml @@ -1,15 +1,8 @@ services: tutorial: - image: ghcr.io/kit-mrt/arbitration_graphs_pacman_tutorial:$VERSION - env_file: .env - ports: - - "8080:8080" - volumes: - - .:/home/blinky/demo - - $HOME/.Xauthority:/home/blinky/.Xauthority - - /tmp/.X11-unix:/tmp/.X11-unix - environment: - - DISPLAY=$DISPLAY + extends: + file: docker-compose.tutorial.yaml + service: tutorial # # This makes sure `docker compose up` only runs the demo service # Use `docker compose run --rm --service-ports tutorial` to run the tutorial From 0d13c078803f33a49626b7b35be94ebb9c6bd6df Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 16:29:43 +0100 Subject: [PATCH 20/48] Add a VSCode DevContainer for the tutorial --- demo/.devcontainer/.zshrc | 89 +++++++++++++++++++++++++++ demo/.devcontainer/Dockerfile | 25 ++++++++ demo/.devcontainer/devcontainer.json | 44 +++++++++++++ demo/.devcontainer/docker-compose.yml | 13 ++++ demo/.vscode/launch.json | 18 ++++++ demo/.vscode/tasks.json | 39 ++++++++++++ demo/README.md | 13 +++- 7 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 demo/.devcontainer/.zshrc create mode 100644 demo/.devcontainer/Dockerfile create mode 100644 demo/.devcontainer/devcontainer.json create mode 100644 demo/.devcontainer/docker-compose.yml create mode 100644 demo/.vscode/launch.json create mode 100644 demo/.vscode/tasks.json diff --git a/demo/.devcontainer/.zshrc b/demo/.devcontainer/.zshrc new file mode 100644 index 00000000..5875b839 --- /dev/null +++ b/demo/.devcontainer/.zshrc @@ -0,0 +1,89 @@ +# >>> reference: https://carlosneto.dev/blog/2024/2024-02-08-starship-zsh/ + +# list files with details +alias ll="ls -larht" + + +# set the locale of the shell +export LANG="en_US.UTF-8" + +# define VSCode as the default text editor +export EDITOR="code -w" + +# specify characters considered as word boundaries for command line navigation +export WORDCHARS="" + +# set the location and filename of the history file +export HISTFILE="$HOME/.zsh_history" + +# set the maximum number of lines to be saved in the history file +export HISTSIZE="100000" +export SAVEHIST="$HISTSIZE" + +# disable CTRL + S and CTRL + Q +stty -ixon + +# enable comments "#" expressions in the prompt shell +setopt INTERACTIVE_COMMENTS + +# append new history entries to the history file +setopt APPEND_HISTORY + +# save each command to the history file as soon as it is executed +setopt INC_APPEND_HISTORY + +# ignore recording duplicate consecutive commands in the history +setopt HIST_IGNORE_DUPS + +# ignore commands that start with a space in the history +setopt HIST_IGNORE_SPACE + +# >>> bindkey tip: to discovery the code of your keys, execute "$ cat -v" and press the key, the code will be printed in your shell. + +# use the ZLE (zsh line editor) in emacs mode. Useful to move the cursor in large commands +bindkey -e + +# navigate words using Ctrl + arrow keys +# >>> CRTL + right arrow | CRTL + left arrow +bindkey "^[[1;5C" forward-word +bindkey "^[[1;5D" backward-word + +# macosx override +if [[ "$OSTYPE" == "darwin"* ]]; then + # >>> OPT + right arrow | OPT + left arrow + bindkey "^[^[[C" forward-word + bindkey "^[^[[D" backward-word +fi + +# search history using Up and Down keys +# >>> up arrow | down arrow +bindkey "^[[A" history-beginning-search-backward +bindkey "^[[B" history-beginning-search-forward + +# jump to the start and end of the command line +# >>> CTRL + A | CTRL + E +bindkey "^A" beginning-of-line +bindkey "^E" end-of-line +# >>> Home | End +bindkey "^[[H" beginning-of-line +bindkey "^[[F" end-of-line + +# navigate menu for command output +zstyle ':completion:*:*:*:*:*' menu select +bindkey '^[[Z' reverse-menu-complete + +# delete characters using the "delete" key +bindkey "^[[3~" delete-char + + +# >>> load ZSH plugin + +# enable kubectl plugin autocompletion +autoload -Uz compinit +compinit + + +# start Starship prompt +eval "$(starship init zsh)" + +source /home/blinky/.motd \ No newline at end of file diff --git a/demo/.devcontainer/Dockerfile b/demo/.devcontainer/Dockerfile new file mode 100644 index 00000000..72ca2e1a --- /dev/null +++ b/demo/.devcontainer/Dockerfile @@ -0,0 +1,25 @@ +ARG VERSION=latest + +FROM ghcr.io/kit-mrt/arbitration_graphs_pacman_tutorial:$VERSION + +USER root + +# Install clangd for the VSCode extension to work out of the box +# Install zsh and tig as modern dev tools +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + clangd \ + curl \ + tig \ + zsh && \ + apt-get clean + +# Install and use starship terminal prompt +RUN curl https://starship.rs/install.sh > /tmp/starship_install.sh && \ + chmod +x /tmp/starship_install.sh && \ + /tmp/starship_install.sh -y && \ + rm /tmp/starship_install.sh + +COPY .devcontainer/.zshrc /home/blinky/.zshrc + +USER blinky diff --git a/demo/.devcontainer/devcontainer.json b/demo/.devcontainer/devcontainer.json new file mode 100644 index 00000000..d83ac6f0 --- /dev/null +++ b/demo/.devcontainer/devcontainer.json @@ -0,0 +1,44 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose +{ + "name": "Arbitration Graphs Tutorial", + + // Update the 'dockerComposeFile' list if you have more compose files or use different names. + // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. + "dockerComposeFile": [ + "../docker-compose.tutorial.yaml", + "docker-compose.yml" + ], + + // The 'service' property is the name of the service for the container that VS Code should + // use. Update this value and .devcontainer/docker-compose.yml to the real service name. + "service": "tutorial", + + // The optional 'workspaceFolder' property is the path VS Code should open by default when + // connected. This is typically a file mount in .devcontainer/docker-compose.yml + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "customizations": { + "vscode": { + // Install some useful VSCode C++ extensions + "extensions": [ + "llvm-vs-code-extensions.vscode-clangd", + "vadimcn.vscode-lldb", + "matepek.vscode-catch2-test-adapter", + "twxs.cmake" + ], + "settings": { + // Use zsh as default terminal + "terminal.integrated.profiles.linux": { + "zsh": { + "path": "/bin/zsh", + "args": ["-l", "-i"] + } + }, + "terminal.integrated.defaultProfile.linux": "zsh", + + // Use system installation of clangd + "clangd.path": "clangd" + } + } + } +} diff --git a/demo/.devcontainer/docker-compose.yml b/demo/.devcontainer/docker-compose.yml new file mode 100644 index 00000000..77fba341 --- /dev/null +++ b/demo/.devcontainer/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.8' +services: + tutorial: + build: + context: . + dockerfile: .devcontainer/Dockerfile + + volumes: + - ..:/workspaces:cached + + # Overrides default command so things don't shut down after the process ends. + command: sleep infinity + diff --git a/demo/.vscode/launch.json b/demo/.vscode/launch.json new file mode 100644 index 00000000..df67280a --- /dev/null +++ b/demo/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug Pacman Demo", + "program": "${workspaceFolder}/build/arbitration_graphs_pacman_demo", + "args": [], + "cwd": "${workspaceFolder}", + "initCommands":["settings set target.disable-aslr false"], + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/demo/.vscode/tasks.json b/demo/.vscode/tasks.json new file mode 100644 index 00000000..d1bb4811 --- /dev/null +++ b/demo/.vscode/tasks.json @@ -0,0 +1,39 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Create build folder", + "type": "shell", + "command": "mkdir -p ${workspaceFolder}/build" + }, + { + "label": "Configure debug build", + "type": "shell", + "command": "cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=true -S ${workspaceFolder} -B ${workspaceFolder}/build" + }, + { + "label": "CMake build for debug", + "dependsOn": ["Create build folder", "Configure debug build"], + "type": "shell", + "command": "cmake --build ${workspaceFolder}/build -j9", + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Configure release build", + "dependsOn": ["Create build folder"], + "type": "shell", + "command": "cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=true -S ${workspaceFolder} -B ${workspaceFolder}/build" + }, + { + "label": "CMake build for release", + "dependsOn": ["Create build folder", "Configure release build"], + "type": "shell", + "command": "cmake --build ${workspaceFolder}/build -j9" + } + ] +} \ No newline at end of file diff --git a/demo/README.md b/demo/README.md index 834175e3..03a3f39b 100644 --- a/demo/README.md +++ b/demo/README.md @@ -17,4 +17,15 @@ Open the GUI with your favorite browser: ## Tutorial -If you're here for the tutorial, follow the instructions on our [Tutorial GitHub Page](https://kit-mrt.github.io/arbitration_graphs/docs/Tutorial.md). \ No newline at end of file +If you're here for the tutorial, follow the instructions on our [Tutorial GitHub Page](https://kit-mrt.github.io/arbitration_graphs/docs/Tutorial.md). + +For a smooth out-of-the-box experience, we recommend using [Visual Studio Code](https://code.visualstudio.com/) with our DevContainer setup. + +- Open this folder in VSCode +- Build and open the Dev Container by running this [command](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) (use `Ctrl+Shift+P`): + `Dev Containers: Reopen in Container` +- Enjoy a full-blown IDE with code-completion, code-navigation etc. + - Compile via `Ctrl+Shift+B` + - View, run and debug unit tests via [Testing](https://code.visualstudio.com/docs/editor/testing) sidebar + - Debug the PacMan Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar + - Debug with breakpoints etc. \ No newline at end of file From a6034beb14337c39e771626bb6c83aa6eea2b548 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 17:50:28 +0100 Subject: [PATCH 21/48] Use subtitles as short site introduction text --- docs/tasks/1_implement_behavior_component.md | 4 +++- docs/tasks/2_extend_arbitration_graph.md | 2 ++ docs/tasks/3_add_more_behaviors.md | 2 ++ docs/tasks/4_nested_arbitrators.md | 2 ++ docs/tasks/5_cost_arbitration.md | 2 ++ docs/tasks/6_verification.md | 2 ++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 6ba2c9e0..df1bb0d6 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -1,10 +1,12 @@ --- title: "Task 1: Implement a Behavior Component" -description: Implement your first checkInvocationCondition and getCommand function, such that the ChaseGhost behavior component passes its unit tests. +description: Implement your first invocation condition and command function, such that the ChaseGhost behavior component passes its unit tests. --- # Chase Ghost +Implement your first `checkInvocationCondition` and `getCommand` function, such that the ChaseGhost behavior component passes its unit tests. + ## Context Before we start building our arbitration graph, we want to take a closer look into behavior components. diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index d700472c..81527783 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -5,6 +5,8 @@ description: Extend the arbitration graph with the ChaseGhost behavior component # Chase Ghost +Extend the arbitration graph with the ChaseGhost behavior component + ## Context With our next behavior component ready to go, we need to think about integrating it into our arbitration graph. diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index 1e886589..bfdcc9fe 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -5,6 +5,8 @@ description: Integrate the EatClosestDot behavior component into the arbitration # Eat Closest Dot +Integrate the EatClosestDot behavior component into the arbitration graph. + ## Context So far, we have not looked into a behavior component that handles the most important aspect of the game: eating dots. diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index 39e8b81b..cae0402e 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -5,6 +5,8 @@ description: Integrate a long-term behavior and add another layer to the arbitra # Nesting +Integrate a long-term behavior and add another layer to the arbitration graph. + ## Context We have now implemented a few behavior components and integrated them into the arbitration graph. diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index b846cdd1..d87b4fe1 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -5,6 +5,8 @@ description: Learn how the cost arbitrator can help you to arbitrate between beh # Cost Arbitrator +Learn how the cost arbitrator can help you to arbitrate between behaviors based on their expected cost/utility. + ## Context The `EatDot` arbitrator we added in the [previous task](4_nested_arbitrators.md) decides between the two dot eating strategies randomly. diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 432a9f0b..6c871fcc 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -5,6 +5,8 @@ description: Execute only safe commands and add a fallback strategy. # Verification and Fallback Layers +Execute only safe commands and add a fallback strategy. + ## Context The arbitration graph is now complete and PacMan is eating dots like a pro. From 87eaf07ac29048ef09fcf643a10897dc5dd84f27 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 17:53:14 +0100 Subject: [PATCH 22/48] Add brackets to all function names for better readability --- docs/tasks/1_implement_behavior_component.md | 16 ++++++++-------- docs/tasks/5_cost_arbitration.md | 2 +- docs/tasks/6_verification.md | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index df1bb0d6..a674beda 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -5,7 +5,7 @@ description: Implement your first invocation condition and command function, suc # Chase Ghost -Implement your first `checkInvocationCondition` and `getCommand` function, such that the ChaseGhost behavior component passes its unit tests. +Implement your first `checkInvocationCondition()` and `getCommand()` function, such that the ChaseGhost behavior component passes its unit tests. ## Context @@ -24,20 +24,20 @@ We can ensure that's always the case using the behavior's invocation condition. But wait - the current implementation of the invocation condition is not complete. It should only be applicable if there is one of these tasty ghosts close by. -Once that's out of the way, we'll take a closer look at the `getCommand` function which is missing some core logic right now. +Once that's out of the way, we'll take a closer look at the `getCommand()` function which is missing some core logic right now. ## Goal -Finish the implementation of the `checkInvocationCondition` and `getCommand` functions +Finish the implementation of the `checkInvocationCondition()` and `getCommand()` functions of the `ChaseGhost` behavior component such that it passes its unit tests. ## Instructions - Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. -- The `checkInvocationCondition` function is already implemented but does not check for the presence of a ghost. -- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::checkInvocationCondition` if you need inspiration. -- The `getCommand` function is partially implemented but the core logic is missing. -- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::getCommand` if you need inspiration. +- The `checkInvocationCondition()` function is already implemented but does not check for the presence of a ghost. +- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::checkInvocationCondition()` if you need inspiration. +- The `getCommand()` function is partially implemented but the core logic is missing. +- Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::getCommand()` if you need inspiration. - Compile and run the unit tests for the `ChaseGhost` behavior component to verify that your implementation is correct. ## Solution @@ -54,7 +54,7 @@ bool ChaseGhostBehavior::checkInvocationCondition(const Time& time) const { } ``` -Add the missing pice of the getCommand function in `src/chase_ghost_behavior.cpp`: +Add the missing piece of the `getCommand()` function in `src/chase_ghost_behavior.cpp`: ```cpp Command ChaseGhostBehavior::getCommand(const Time& time) { auto pacmanPosition = environmentModel_->pacmanPosition(); diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index d87b4fe1..cbd77978 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -33,7 +33,7 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat - In `cost_estimator.cpp`, fill in the blanks to compute `nDots` and `nCells`. - Add an instance of the `CostEstimator` to the `PacmanAgent` class and initialize it in the constructor. Don't forget to include the necessary headers and extend the parameter struct with the parameters for the `CostEstimator`. -- Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption` method. +- Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption()` method. ## Solution diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 6c871fcc..76960b1c 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -53,21 +53,21 @@ Add the `MoveRandomly` behavior component as a last resort fallback layer. ## Instructions -- In `verifier.cpp`, finish the implementation of the `Verifier::analyze` method. +- In `verifier.cpp`, finish the implementation of the `Verifier::analyze()` method. - Add an instance of the `Verifier` to the `PacmanAgent` class and initialize it in the constructor. - Pass the `Verifier` instance to the constructors of the arbitrators. (Hint: You'll need to adjust the template parameters of the arbitrators.) - Add the `MoveRandomly` behavior component analogously to the other behavior components. - Mark the `MoveRandomly` behavior component as a last resort fallback layer. - Try breaking a behavior component on purpose and see how the system reacts. - (Try throwing an exception in the `getCommand` method of a behavior component or returning a command that will lead to a collision with a wall.) + (Try throwing an exception in the `getCommand()` method of a behavior component or returning a command that will lead to a collision with a wall.) ## Solution
Click here to expand the solution -In the `Verifier::analyze` method (in `include/demo/verifier.hpp`), we simply check if the command would lead to an invalid position: +In the `Verifier::analyze()` method (in `include/demo/verifier.hpp`), we simply check if the command would lead to an invalid position: ```cpp VerificationResult analyze(const Time /*time*/, const Command& command) const { Move nextMove = Move{command.path.front()}; From 7741a909800b1109fd52bfed2bd6c5e6173575b2 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 18:07:06 +0100 Subject: [PATCH 23/48] Use title for task heading and keep tutorial page banner consistent --- docs/tasks/1_implement_behavior_component.md | 5 ++--- docs/tasks/2_extend_arbitration_graph.md | 7 +++---- docs/tasks/3_add_more_behaviors.md | 7 +++---- docs/tasks/4_nested_arbitrators.md | 5 ++--- docs/tasks/5_cost_arbitration.md | 5 ++--- docs/tasks/6_verification.md | 5 ++--- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index a674beda..dcd4e0ba 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -1,9 +1,8 @@ --- -title: "Task 1: Implement a Behavior Component" -description: Implement your first invocation condition and command function, such that the ChaseGhost behavior component passes its unit tests. +title: "Arbitration Graphs Tutorial" --- -# Chase Ghost +# Task 1: Implement a Behavior Component Implement your first `checkInvocationCondition()` and `getCommand()` function, such that the ChaseGhost behavior component passes its unit tests. diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 81527783..9f8d99cc 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -1,11 +1,10 @@ --- -title: "Task 2: Extend the Arbitration Graph" -description: Extend the arbitration graph with the ChaseGhost behavior component. +title: "Arbitration Graphs Tutorial" --- -# Chase Ghost +# Task 2: Extend the Arbitration Graph -Extend the arbitration graph with the ChaseGhost behavior component +Extend the arbitration graph with the `ChaseGhost` behavior component. ## Context diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index bfdcc9fe..5f9e4686 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -1,11 +1,10 @@ --- -title: "Task 3: Even more behavior components" -description: Integrate the EatClosestDot behavior component into the arbitration graph. +title: "Arbitration Graphs Tutorial" --- -# Eat Closest Dot +# Task 3: Even more behavior components -Integrate the EatClosestDot behavior component into the arbitration graph. +Integrate the `EatClosestDot` behavior component into the arbitration graph. ## Context diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index cae0402e..8bc0cf18 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -1,9 +1,8 @@ --- -title: "Task 4: Nested arbitration graphs" -description: Integrate a long-term behavior and add another layer to the arbitration graph +title: "Arbitration Graphs Tutorial" --- -# Nesting +# Task 4: Nested arbitration graphs Integrate a long-term behavior and add another layer to the arbitration graph. diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index cbd77978..a0e9bd91 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -1,9 +1,8 @@ --- -title: "Task 5: Arbitrate based on predicted utility" -description: Learn how the cost arbitrator can help you to arbitrate between behaviors based on their expected cost/utility. +title: "Arbitration Graphs Tutorial" --- -# Cost Arbitrator +# Task 5: Arbitrate based on predicted utility Learn how the cost arbitrator can help you to arbitrate between behaviors based on their expected cost/utility. diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 76960b1c..debbab4a 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -1,9 +1,8 @@ --- -title: "Task 6: Better safe than sorry" -description: Execute only safe commands and add a fallback strategy. +title: "Arbitration Graphs Tutorial" --- -# Verification and Fallback Layers +# Task 6: Better safe than sorry Execute only safe commands and add a fallback strategy. From d5bd4e8f452995f2dcccc0054adec9fde0877e5d Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 18:43:04 +0100 Subject: [PATCH 24/48] Add a auto-generated sitemap.xml --- docs/_layouts/default.html | 5 +++- docs/sitemap.xml | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 docs/sitemap.xml diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index fcd768c7..0774783d 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -44,8 +44,11 @@

{{ page.description | default: site.description | de Cayman theme, using allejo/jekyll-toc and +
snippets from - Bram.us + Bram.us + as well as + David Ensinger ❤ī¸ diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 00000000..82c99f38 --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,59 @@ +--- +layout: null +sitemap: + exclude: 'yes' +permalink: /sitemap.xml +--- + + + {% for post in site.posts %} + {% assign file_ext = post.url | split: '.' | last %} + {% if post.published != false and file_ext != 'css' %} + + {{ site.url }}{{ post.url }} + {% if post.sitemap.lastmod %} + {{ post.sitemap.lastmod | date: "%Y-%m-%d" }} + {% elsif post.date %} + {{ post.date | date_to_xmlschema }} + {% else %} + {{ site.time | date_to_xmlschema }} + {% endif %} + {% if post.sitemap.changefreq %} + {{ post.sitemap.changefreq }} + {% else %} + monthly + {% endif %} + {% if post.sitemap.priority %} + {{ post.sitemap.priority }} + {% else %} + 0.5 + {% endif %} + + {% endif %} + {% endfor %} + {% for page in site.pages %} + {% assign file_ext = page.url | split: '.' | last %} + {% if page.sitemap.exclude != "yes" and file_ext != 'css' %} + + {{ site.url }}{{ page.url | remove: "index.html" }} + {% if page.sitemap.lastmod %} + {{ page.sitemap.lastmod | date: "%Y-%m-%d" }} + {% elsif page.date %} + {{ page.date | date_to_xmlschema }} + {% else %} + {{ site.time | date_to_xmlschema }} + {% endif %} + {% if page.sitemap.changefreq %} + {{ page.sitemap.changefreq }} + {% else %} + monthly + {% endif %} + {% if page.sitemap.priority %} + {{ page.sitemap.priority }} + {% else %} + 0.3 + {% endif %} + + {% endif %} + {% endfor %} + \ No newline at end of file From a439b3c8efa427fbb784b6d55b5239e833293ced Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 19:24:13 +0100 Subject: [PATCH 25/48] Fix warning about missing toc.css file (it's compiled into the main style.css) --- docs/_includes/head-custom.html | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/_includes/head-custom.html b/docs/_includes/head-custom.html index 4a2e9169..7f8b0918 100644 --- a/docs/_includes/head-custom.html +++ b/docs/_includes/head-custom.html @@ -1,4 +1,3 @@ - \ No newline at end of file From a4caac8fdfdfa64a684ae2b14b3d0a1bda64e88e Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 12:09:12 +0100 Subject: [PATCH 26/48] Tune font size of inline code --- docs/assets/_sass/fonts.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/assets/_sass/fonts.scss b/docs/assets/_sass/fonts.scss index 57d04fb5..f05e8f4f 100644 --- a/docs/assets/_sass/fonts.scss +++ b/docs/assets/_sass/fonts.scss @@ -28,6 +28,7 @@ body { code { font-family: "Source Code Pro", Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 0.85rem; } pre { From 3375912f74ae0ea4644d65b9b2d2eb948a4ffd27 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 12:09:29 +0100 Subject: [PATCH 27/48] Define navigation text colors in variables.scss --- docs/assets/_sass/toc.scss | 6 +++--- docs/assets/_sass/variables.scss | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/assets/_sass/toc.scss b/docs/assets/_sass/toc.scss index 0eb87b26..1ee23572 100644 --- a/docs/assets/_sass/toc.scss +++ b/docs/assets/_sass/toc.scss @@ -43,7 +43,7 @@ html { // ScrollSpy active styles (see toc.js tab for activation) .section-nav li.active>a { - color: #333; + color: $nav-text-active-color; font-weight: 500; } @@ -56,13 +56,13 @@ html { text-decoration: none; display: block; padding: .125rem 0; - color: #ccc; + color: $nav-text-color; transition: all 50ms ease-in-out; /* 💡 This small transition makes setting of the active state smooth */ } .section-nav a:hover, .section-nav a:focus { - color: #666; + color: $nav-text-focus-color; } } \ No newline at end of file diff --git a/docs/assets/_sass/variables.scss b/docs/assets/_sass/variables.scss index 1f12ce6b..cc625fe8 100644 --- a/docs/assets/_sass/variables.scss +++ b/docs/assets/_sass/variables.scss @@ -2,6 +2,11 @@ $large-breakpoint: 64em !default; $medium-breakpoint: 42em !default; +// Navigation +$nav-text-color: #ccc !default; +$nav-text-active-color: #333 !default; +$nav-text-focus-color: #666 !default; + // Headers $header-heading-color: #fff !default; $header-bg-color: #008383 !default; From eb3be89c8161e6ad95bb46abdd82178eed02b1e4 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Fri, 15 Nov 2024 19:27:17 +0100 Subject: [PATCH 28/48] Add menu to tutorial pages --- docs/_layouts/default.html | 34 ++++++++++++++ docs/assets/_sass/toc.scss | 49 +++++++++++++++----- docs/assets/_sass/variables.scss | 2 + docs/assets/css/style.scss | 4 ++ docs/tasks/1_implement_behavior_component.md | 1 + docs/tasks/2_extend_arbitration_graph.md | 1 + docs/tasks/3_add_more_behaviors.md | 1 + docs/tasks/4_nested_arbitrators.md | 1 + docs/tasks/5_cost_arbitration.md | 1 + docs/tasks/6_verification.md | 1 + 10 files changed, 84 insertions(+), 11 deletions(-) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 0774783d..e52daeb1 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -32,6 +32,40 @@

{{ page.description | default: site.description | de
+ + + {{ content }}
diff --git a/docs/assets/_sass/toc.scss b/docs/assets/_sass/toc.scss index 1ee23572..1c6a0bda 100644 --- a/docs/assets/_sass/toc.scss +++ b/docs/assets/_sass/toc.scss @@ -4,7 +4,7 @@ html { } // Hide navbar on small/medium screens -#page-container>nav { +#page-container nav { display: none; } @@ -13,6 +13,7 @@ html { // Style table of content /** page layout **/ #page-container { + background-color: $section-bg-color; display: grid; grid-template-columns: 1fr 15em; max-width: 100em; @@ -20,14 +21,18 @@ html { margin: 0 auto; } + #page-container .main-content { + padding-top: 0; + } + // Make nav sticky - #page-container>nav { + #page-container nav { display: block; position: sticky; - top: 2rem; - margin-top: 2rem; + top: 0; + padding-bottom: .4rem; align-self: start; - + background-color: $section-bg-color; ul, ol { @@ -41,18 +46,40 @@ html { } } + .pages-nav { + padding: .4rem 0; + } + // ScrollSpy active styles (see toc.js tab for activation) - .section-nav li.active>a { + nav li.active>a { color: $nav-text-active-color; font-weight: 500; } - .section-nav { + #page-container .pages-nav > ul { + display: flex; + width: 100%; + } + + #page-container .pages-nav li { + margin-left: 1.5rem; + text-wrap: nowrap; + } + + #page-container .pages-nav li:first-of-type { + margin-left: .5rem; + } + + #page-container .section-nav > ul { + margin-top: 4rem; + } + + #page-container .section-nav>ul { padding-left: 0; - border-left: 1px solid #efefef; + border-left: 1px solid $nav-border-color; } - .section-nav a { + nav a { text-decoration: none; display: block; padding: .125rem 0; @@ -61,8 +88,8 @@ html { /* 💡 This small transition makes setting of the active state smooth */ } - .section-nav a:hover, - .section-nav a:focus { + nav a:hover, + nav a:focus { color: $nav-text-focus-color; } } \ No newline at end of file diff --git a/docs/assets/_sass/variables.scss b/docs/assets/_sass/variables.scss index cc625fe8..8d8da1c4 100644 --- a/docs/assets/_sass/variables.scss +++ b/docs/assets/_sass/variables.scss @@ -14,6 +14,7 @@ $header-bg-color-secondary: #00001D !default; // Text $section-headings-color: #257180 !default; +$section-bg-color: #fff !default; $body-text-color: #606c71 !default; $body-link-color: #008383 !default; $blockquote-text-color: #819198 !default; @@ -26,3 +27,4 @@ $code-text-color: #f8f8f2 !default; $border-color: #dce6f0 !default; $table-border-color: #e9ebec !default; $hr-border-color: #eff0f1 !default; +$nav-border-color: #efefef !default; diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss index b5e8a4b7..46d302c0 100644 --- a/docs/assets/css/style.scss +++ b/docs/assets/css/style.scss @@ -14,6 +14,10 @@ // Add table of contents navbar @import 'toc'; +#page-container { + background-color: $section-bg-color; +} + // Switch to light theme logo img.github-logo { content: url({{ "/docs/assets/img/github-mark.svg" | relative_url }}); diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index dcd4e0ba..44d7dd0b 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "First Behavior" --- # Task 1: Implement a Behavior Component diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 9f8d99cc..dc65835d 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "Extending the Graph" --- # Task 2: Extend the Arbitration Graph diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md index 5f9e4686..ea5cb470 100644 --- a/docs/tasks/3_add_more_behaviors.md +++ b/docs/tasks/3_add_more_behaviors.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "More Behaviors" --- # Task 3: Even more behavior components diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index 8bc0cf18..e454c6db 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "Nesting" --- # Task 4: Nested arbitration graphs diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index a0e9bd91..f0768fd6 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "Cost Arbitrator" --- # Task 5: Arbitrate based on predicted utility diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index debbab4a..7b007f62 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -1,5 +1,6 @@ --- title: "Arbitration Graphs Tutorial" +menu_title: "Verification and Fallbacks" --- # Task 6: Better safe than sorry From 94be0c877a451b2855ebc8bcfa1f1223522f3573 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 17:50:27 +0100 Subject: [PATCH 29/48] Start with the dev setup before "What to find where" --- docs/Tutorial.md | 67 +++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 47566fd5..03778272 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -20,41 +20,11 @@ Next, we'll start adding more and more behavior components to the graph and lear The tutorial is structured into several tasks that are meant to be completed in order. -### What to find where - -Let's take a look at the structure and content of the `arbitration_graphs/demo/` directory. - -``` -demo -├── include -├── src -├── test -└── â€Ļ -``` - -All header files can be found in the `include/` directory with corresponding implementation files in the `src/` directory. -The entire demo is thoroughly tested using the unit tests you'll find in the `test/` directory. - -Each behavior component is implemented in a separate `_behavior.hpp` file as a class inheriting from the abstract `Behavior` class. - -Next, there is `environment_model.hpp`. -You guessed it, it contains the environment model for the arbitration graph. -In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions - and other things required by the behavior components. - -The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/5_cost_arbitration.md). - -Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph [near the end](./tasks/6_verification.md) of the tutorial. - -Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. -It's also where you'll spend most of your time during this tutorial. - -If you are interested in how the demo works in detail, - you'll find additional code not directly relevant to the tutorial in the `include/utils/` directory ### Development Environment -The easiest way to get started is to use the provided docker setup. +The easiest way to get started is to use the provided [Visual Studio Code](https://code.visualstudio.com/) [Dev Container](https://code.visualstudio.com/docs/devcontainers/containers). +Using the docker setup via terminal is great as well and works with any IDE. Start by checking out the `tutorial` branch where we have removed some parts of the demo implementation for the purpose of this tutorial. @@ -95,6 +65,39 @@ We'll leave the setup of your favorite IDE up to you though most modern IDEs should support attaching to a running docker container. +### What to find where + +Let's take a look at the structure and content of the `arbitration_graphs/demo/` directory. + +``` +demo +├── include +├── src +├── test +└── â€Ļ +``` + +All header files can be found in the `include/` directory with corresponding implementation files in the `src/` directory. +The entire demo is thoroughly tested using the unit tests you'll find in the `test/` directory. + +Each behavior component is implemented in a separate `_behavior.hpp` file as a class inheriting from the abstract `Behavior` class. + +Next, there is `environment_model.hpp`. +You guessed it, it contains the environment model for the arbitration graph. +In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions + and other things required by the behavior components. + +The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/5_cost_arbitration.md). + +Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph [near the end](./tasks/6_verification.md) of the tutorial. + +Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. +It's also where you'll spend most of your time during this tutorial. + +If you are interested in how the demo works in detail, + you'll find additional code not directly relevant to the tutorial in the `include/utils/` directory + + ## Tasks With the basics out of the way, let's work through the tasks. From 91eca71ab85dfc406004da1957ab2088d4834d65 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 17:55:54 +0100 Subject: [PATCH 30/48] Add setup section for VSCode DevContainer --- docs/Tutorial.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 03778272..cefdb410 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -32,6 +32,31 @@ Start by checking out the `tutorial` branch where we have removed some parts git clone --branch tutorial https://github.com/KIT-MRT/arbitration_graphs.git ``` +
+Go here for the VSCode Dev Container + +Open the `demo` folder of your fresh `arbitration_graphs` clone in VSCode, e.g. via terminal: +```bash +cd arbitration_graphs/demo +code . +``` + +Build and open the Dev Container by running this [command](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) (use `Ctrl+Shift+P`): +`Dev Containers: Reopen in Container` (this might take a while) + +Enjoy a full-blown IDE with code-completion, code-navigation etc. +- Explore the repo in the Explorer sidebar +- Compile via `Ctrl+Shift+B` +- View, run and debug unit tests via [Testing](https://code.visualstudio.com/docs/editor/testing) sidebar +- Debug the PacMan Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar +- Debug with breakpoints etc. + +
+ + +
+Unfold this for the Docker setup via terminal + To start an interactive shell in the docker container with all required dependencies installed and the current directory mounted, run ```bash @@ -64,6 +89,8 @@ cmake --build . --target test We'll leave the setup of your favorite IDE up to you though most modern IDEs should support attaching to a running docker container. +
+ ### What to find where From 4608892eb251019a1d3eba1a1c11173eda6dbcd7 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 19:03:54 +0100 Subject: [PATCH 31/48] Shorten demo test executable names --- demo/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/test/CMakeLists.txt b/demo/test/CMakeLists.txt index 30f3ee05..a3412783 100644 --- a/demo/test/CMakeLists.txt +++ b/demo/test/CMakeLists.txt @@ -71,7 +71,7 @@ if(GTEST_FOUND) get_filename_component(_test_name ${_test} NAME_WE) # make sure we add only one -test to the target string(REGEX REPLACE "-test" "" TEST_TARGET_NAME ${_test_name}) - set(TEST_TARGET_NAME arbitration_graphs_pacman_demo-gtest-${TEST_TARGET_NAME}) + set(TEST_TARGET_NAME test_${TEST_TARGET_NAME}) message(STATUS "Adding gtest unittest \"${TEST_TARGET_NAME}\" with working dir ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_FOLDER} \n _test: ${_test}" From 4ae9783bc9c6b584ba79e816670080488ebf6eab Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 19:10:52 +0100 Subject: [PATCH 32/48] Fix ChaseGhostBehavior inv/com condition tests --- demo/test/chase_ghost_behavior.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo/test/chase_ghost_behavior.cpp b/demo/test/chase_ghost_behavior.cpp index ab67a60d..d4891f2a 100644 --- a/demo/test/chase_ghost_behavior.cpp +++ b/demo/test/chase_ghost_behavior.cpp @@ -39,6 +39,7 @@ TEST_F(ChaseGhostBehaviorTest, checkInvocationConditionFalse) { // We don't want to chase ghosts when they are far away environmentModel_->setGhostMode(GhostMode::SCARED); + environmentModel_->setScaredCountdown(40); environmentModel_->setPacmanPosition({1, 1}); environmentModel_->setGhostPositions({8, 8}); ASSERT_FALSE(chaseGhostBehavior_.checkInvocationCondition(time)); @@ -67,6 +68,7 @@ TEST_F(ChaseGhostBehaviorTest, checkCommitmentConditionFalse) { // We don't want to chase ghosts when they are far away environmentModel_->setGhostMode(GhostMode::SCARED); + environmentModel_->setScaredCountdown(40); environmentModel_->setPacmanPosition({1, 1}); environmentModel_->setGhostPositions({8, 8}); ASSERT_FALSE(chaseGhostBehavior_.checkInvocationCondition(time)); From 4e8c8eef03f7b2a98365fcb124b5b213fbcca309 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Mon, 18 Nov 2024 19:29:37 +0100 Subject: [PATCH 33/48] Tune Task 1: Implement a Behavior Component --- docs/tasks/1_implement_behavior_component.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 44d7dd0b..6386c566 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -33,6 +33,7 @@ Finish the implementation of the `checkInvocationCondition()` and `getCommand()` ## Instructions +- Run the unit tests and note that the `ChaseGhost` `scheckInvocationConditionFalse` test is failing - Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. - The `checkInvocationCondition()` function is already implemented but does not check for the presence of a ghost. - Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::checkInvocationCondition()` if you need inspiration. From 0de77f21ea9e4b2995690ce9c6768b64d6f6c52d Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 15:23:34 +0100 Subject: [PATCH 34/48] Print link to GUI in demo --- demo/src/pacman_wrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo/src/pacman_wrapper.cpp b/demo/src/pacman_wrapper.cpp index 7ff832e0..3428afce 100644 --- a/demo/src/pacman_wrapper.cpp +++ b/demo/src/pacman_wrapper.cpp @@ -119,6 +119,8 @@ void PacmanWrapper::printKeybindings() { << " \033[1;32mSpace\033[0m - Pause the demo\n" << " \033[1;32mP\033[0m - Toggle path visualization\n" << "\033[1;36m=====================================\033[0m\n" + << " \033[1;32mGUI\033[0m - Open http://localhost:8080\n" + << "\033[1;36m=====================================\033[0m\n" << std::endl; } From 18f0f0fbafb4b0339c883a3d68c4439c3c3dd35a Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 16:05:09 +0100 Subject: [PATCH 35/48] =?UTF-8?q?Cleanup=20demo=20behaviors=20for=20consis?= =?UTF-8?q?tency=20(use=20of=20explicit,=20implementation=20in=20cpp=20fil?= =?UTF-8?q?e,=20=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/CMakeLists.txt | 2 ++ demo/include/demo/avoid_ghost_behavior.hpp | 6 ++--- demo/include/demo/chase_ghost_behavior.hpp | 6 ++--- .../include/demo/eat_closest_dot_behavior.hpp | 23 +++------------- demo/include/demo/move_randomly_behavior.hpp | 15 ++--------- demo/include/demo/stay_in_place_behavior.hpp | 18 +++---------- demo/src/eat_closest_dot_behavior.cpp | 27 +++++++++++++++++++ demo/src/move_randomly_behavior.cpp | 7 +++++ demo/src/stay_in_place_behavior.cpp | 17 ++++++++++++ 9 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 demo/src/eat_closest_dot_behavior.cpp create mode 100644 demo/src/stay_in_place_behavior.cpp diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index f409eb7a..87c3100d 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -66,9 +66,11 @@ add_library(${PROJECT_NAME}_lib SHARED src/chase_ghost_behavior.cpp src/cost_estimator.cpp src/cluster.cpp + src/eat_closest_dot_behavior.cpp src/entities.cpp src/environment_model.cpp src/move_randomly_behavior.cpp + src/stay_in_place_behavior.cpp src/utils.cpp ) target_include_directories(${PROJECT_NAME}_lib PRIVATE diff --git a/demo/include/demo/avoid_ghost_behavior.hpp b/demo/include/demo/avoid_ghost_behavior.hpp index 23c68548..0d083af5 100644 --- a/demo/include/demo/avoid_ghost_behavior.hpp +++ b/demo/include/demo/avoid_ghost_behavior.hpp @@ -24,9 +24,9 @@ class AvoidGhostBehavior : public arbitration_graphs::Behavior { double commitmentMinDistance{7}; }; - AvoidGhostBehavior(EnvironmentModel::Ptr environmentModel, - const Parameters& parameters, - const std::string& name = "AvoidGhost") + explicit AvoidGhostBehavior(EnvironmentModel::Ptr environmentModel, + const Parameters& parameters, + const std::string& name = "AvoidGhost") : Behavior(name), environmentModel_{std::move(environmentModel)}, parameters_{parameters} { } diff --git a/demo/include/demo/chase_ghost_behavior.hpp b/demo/include/demo/chase_ghost_behavior.hpp index f1fde928..ce11321e 100644 --- a/demo/include/demo/chase_ghost_behavior.hpp +++ b/demo/include/demo/chase_ghost_behavior.hpp @@ -25,9 +25,9 @@ class ChaseGhostBehavior : public arbitration_graphs::Behavior { int minScaredTicksLeft{5}; }; - ChaseGhostBehavior(EnvironmentModel::Ptr environmentModel, - const Parameters& parameters, - const std::string& name = "ChaseGhost") + explicit ChaseGhostBehavior(EnvironmentModel::Ptr environmentModel, + const Parameters& parameters, + const std::string& name = "ChaseGhost") : Behavior(name), environmentModel_{std::move(environmentModel)}, parameters_{parameters} { } diff --git a/demo/include/demo/eat_closest_dot_behavior.hpp b/demo/include/demo/eat_closest_dot_behavior.hpp index 41884012..6d8a5ee1 100644 --- a/demo/include/demo/eat_closest_dot_behavior.hpp +++ b/demo/include/demo/eat_closest_dot_behavior.hpp @@ -19,27 +19,10 @@ class EatClosestDotBehavior : public arbitration_graphs::Behavior { : Behavior(name), environmentModel_{std::move(environmentModel)} { } - Command getCommand(const Time& /*time*/) override { - auto pacmanPosition = environmentModel_->pacmanPosition(); - std::optional pathToClosestDot = environmentModel_->pathToClosestDot(pacmanPosition); + Command getCommand(const Time& /*time*/) override; - if (!pathToClosestDot) { - throw std::runtime_error("Failed to compute path to closest dot. Can not provide a sensible command."); - } - - return Command{pathToClosestDot.value()}; - } - - bool checkInvocationCondition(const Time& /*time*/) const override { - // This behavior is only applicable if there is at least one dot. We should check for the presence of a dot - // here, but since the game is won when all dots are collected, we assume at least one dot exists when this - // behavior is invoked. - return true; - } - - bool checkCommitmentCondition(const Time& /*time*/) const override { - return false; - } + bool checkInvocationCondition(const Time& /*time*/) const override; + bool checkCommitmentCondition(const Time& /*time*/) const override; private: EnvironmentModel::Ptr environmentModel_; diff --git a/demo/include/demo/move_randomly_behavior.hpp b/demo/include/demo/move_randomly_behavior.hpp index 7510de6c..a8e40eb4 100644 --- a/demo/include/demo/move_randomly_behavior.hpp +++ b/demo/include/demo/move_randomly_behavior.hpp @@ -29,24 +29,13 @@ class MoveRandomlyBehavior : public arbitration_graphs::Behavior { Command getCommand(const Time& time) override; - bool checkInvocationCondition(const Time& time) const override { - return true; - } - bool checkCommitmentCondition(const Time& time) const override { - return false; - } - - void gainControl(const Time& time) override { - gainedControlAt_ = time; - } - void loseControl(const Time& time) override { - } + bool checkInvocationCondition(const Time& /*time*/) const override; + bool checkCommitmentCondition(const Time& /*time*/) const override; private: Direction selectRandomDirection(); util_caching::Cache directionCache_; - Time gainedControlAt_; Parameters parameters_; std::random_device randomDevice_; diff --git a/demo/include/demo/stay_in_place_behavior.hpp b/demo/include/demo/stay_in_place_behavior.hpp index b0e492e6..8d66d9b1 100644 --- a/demo/include/demo/stay_in_place_behavior.hpp +++ b/demo/include/demo/stay_in_place_behavior.hpp @@ -24,22 +24,10 @@ class StayInPlaceBehavior : public arbitration_graphs::Behavior { : Behavior(name), environmentModel_{std::move(environmentModel)} { } - Command getCommand(const Time& time) override { - Direction currentDirection = environmentModel_->pacmanDirection(); - return Command{oppositeDirection(currentDirection)}; - } - - bool checkInvocationCondition(const Time& time) const override { - return true; - } - bool checkCommitmentCondition(const Time& time) const override { - return false; - } + Command getCommand(const Time& /*time*/) override; - void gainControl(const Time& time) override { - } - void loseControl(const Time& time) override { - } + bool checkInvocationCondition(const Time& /*time*/) const override; + bool checkCommitmentCondition(const Time& /*time*/) const override; private: EnvironmentModel::Ptr environmentModel_; diff --git a/demo/src/eat_closest_dot_behavior.cpp b/demo/src/eat_closest_dot_behavior.cpp new file mode 100644 index 00000000..861977e3 --- /dev/null +++ b/demo/src/eat_closest_dot_behavior.cpp @@ -0,0 +1,27 @@ +#include "demo/eat_closest_dot_behavior.hpp" + +namespace demo { + +Command EatClosestDotBehavior::getCommand(const Time& /*time*/) { + auto pacmanPosition = environmentModel_->pacmanPosition(); + std::optional pathToClosestDot = environmentModel_->pathToClosestDot(pacmanPosition); + + if (!pathToClosestDot) { + throw std::runtime_error("Failed to compute path to closest dot. Can not provide a sensible command."); + } + + return Command{pathToClosestDot.value()}; +} + +bool EatClosestDotBehavior::checkInvocationCondition(const Time& /*time*/) const { + // This behavior is only applicable if there is at least one dot. We should check for the presence of a dot + // here, but since the game is won when all dots are collected, we assume at least one dot exists when this + // behavior is invoked. + return true; +} + +bool EatClosestDotBehavior::checkCommitmentCondition(const Time& /*time*/) const { + return false; +} + +} // namespace demo \ No newline at end of file diff --git a/demo/src/move_randomly_behavior.cpp b/demo/src/move_randomly_behavior.cpp index 25dfb08f..ffd89c24 100644 --- a/demo/src/move_randomly_behavior.cpp +++ b/demo/src/move_randomly_behavior.cpp @@ -22,4 +22,11 @@ Direction MoveRandomlyBehavior::selectRandomDirection() { return randomMove.direction; } +bool MoveRandomlyBehavior::checkInvocationCondition(const Time& /*time*/) const { + return true; +} +bool MoveRandomlyBehavior::checkCommitmentCondition(const Time& /*time*/) const { + return false; +} + } // namespace demo diff --git a/demo/src/stay_in_place_behavior.cpp b/demo/src/stay_in_place_behavior.cpp new file mode 100644 index 00000000..4693b5b8 --- /dev/null +++ b/demo/src/stay_in_place_behavior.cpp @@ -0,0 +1,17 @@ +#include "demo/stay_in_place_behavior.hpp" + +namespace demo { + +Command StayInPlaceBehavior::getCommand(const Time& /*time*/) { + Direction currentDirection = environmentModel_->pacmanDirection(); + return Command{oppositeDirection(currentDirection)}; +} + +bool StayInPlaceBehavior::checkInvocationCondition(const Time& /*time*/) const { + return true; +} +bool StayInPlaceBehavior::checkCommitmentCondition(const Time& /*time*/) const { + return false; +} + +} // namespace demo \ No newline at end of file From 3f0d89a5058c2d2d92e3ccb56f721c0deb9a3bdc Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 17:07:12 +0100 Subject: [PATCH 36/48] Explicitly ignore demo/build folder for tutorial setup --- demo/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 demo/.gitignore diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1 @@ +build From a624a56501ea7fe1c194be232796fe70c764ef5e Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 17:27:54 +0100 Subject: [PATCH 37/48] Tune Task 2: Extend the Arbitration Graph --- docs/tasks/2_extend_arbitration_graph.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index dc65835d..20d45a0d 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -13,7 +13,7 @@ With our next behavior component ready to go, we need to think about integrating For this purpose, we need to modify the `PacmanAgent` class to include the `ChaseGhost` behavior component we implemented in the [previous task](1_implement_behavior_component.md). Integrating a new behavior component into the arbitration graph is as simple as instantiating it and adding it as a new option to one of the arbitrators. -Since right now there is just one arbitrator - a priority arbitrator - the choice is simple. +Since right now there is just one arbitrator – a priority arbitrator – the choice is simple. We just need to worry about the order in which the options are assigned to the arbitrator. Should chasing a ghost have a higher priority than avoiding a ghost or vice versa? @@ -55,7 +55,9 @@ struct Parameters { }; ``` -In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator: +In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator. + +The invocation condition of `ChaseGhost` is a subset of the `AvoidGhost` invocation condition. Therefore, it only makes sense to add `ChaseGhost` with higher priority than (i.e. before) the `AvoidGhost` behavior component: ```cpp explicit PacmanAgent(const entt::Game& game) : parameters_{}, environmentModel_{std::make_shared(game)} { From 8f66e6e215aaf6116fc934ebd72cdd3811e04aea Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 21:29:29 +0100 Subject: [PATCH 38/48] Tune Task 5: Arbitrate based on predicted utility --- docs/tasks/5_cost_arbitration.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index f0768fd6..bcbb6c58 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -30,7 +30,9 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat ## Instructions +- Run the unit tests and note that some of the `CostEstimator` tests are failing - In `cost_estimator.cpp`, fill in the blanks to compute `nDots` and `nCells`. +- Compile and run the unit tests for the `CostEstimator` to verify that your implementation is correct. - Add an instance of the `CostEstimator` to the `PacmanAgent` class and initialize it in the constructor. Don't forget to include the necessary headers and extend the parameter struct with the parameters for the `CostEstimator`. - Replace the random arbitrator with a cost arbitrator in the `PacmanAgent` class. Pass the `CostEstimator` instance to the `addOption()` method. From 1d4cc21cadf69bb2003bbbcd2be0e64e76d41871 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 23:50:15 +0100 Subject: [PATCH 39/48] Tune Task 4: Nested arbitration graphs --- docs/tasks/4_nested_arbitrators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index e454c6db..6f12bb57 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -44,7 +44,7 @@ Include the header of the `ChangeDotCluster` behavior component and the random a #include "change_dot_cluster_behavior.hpp" ``` -For easier to read code, add the following alias near the top of the class definition: +For better code readability, add the following alias near the top of the class definition: ```cpp using RandomArbitrator = arbitration_graphs::RandomArbitrator; ``` From ca48dff6ddd31451ba025c3d20928fed949e2069 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 19 Nov 2024 23:50:47 +0100 Subject: [PATCH 40/48] Tune Task 6: Better safe than sorry --- docs/tasks/6_verification.md | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 7b007f62..853a6698 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -10,37 +10,37 @@ Execute only safe commands and add a fallback strategy. ## Context The arbitration graph is now complete and PacMan is eating dots like a pro. -But there is one last topic we want to talk about: safety and robustness. +But there is one last topic we want to talk about: **safety and robustness**. -Depending on your application, you might be interested in only executing commands that you know fulfill certain criteria. -The concrete requirements depend on your application and could be anything from physical constraints to safety requirements. +Depending on your application, you might only want to execute commands that you know meet certain criteria. +The specific requirements will depend on your application and could be anything from physical constraints to safety requirements. In our case, we only want to execute commands where PacMan does not run into walls. We can ensure that commands obey these requirements by adding a verifier to the arbitrators. -The arbitrator will then run the verification step and only choose commands that pass this step. +The arbitrator will then run the **verification step** and only choose commands that pass this step. The leads us to another issue. What to do if the command we wanted to execute does not pass the verification step? Glad you asked! -The first and thing that will happen without us doing anything is that the arbitrator will just choose the next best option. -E.g., if the `EatClosestDot` is not safe, the `EatDot` arbitrator could just pass the `ChangeDotCluster` command to the root arbitrator - assuming the latter is both applicable and does itself pass verification. +The first thing that happens out-of-the-box: the arbitrator will just choose the next best option passing verification. +E.g., if the `EatClosestDot` is not safe, the `EatDot` arbitrator will just return the `ChangeDotCluster` command to the root arbitrator + in case `ChangeDotCluster` is both applicable and does itself pass verification. -If that's not the case, we can think about adding additional behavior components as fallback layers to enable graceful degradation of the system. +If that's not the case though, we can think about adding additional behavior components as fallback layers to enable **graceful degradation** of the system. The first one is already there: `MoveRandomly` is something we probably don't really want to do under normal circumstances. But if we run out of ideas, it is still a valid option. It might also give our main behavior components a chance to recover or to solve deadlock situations. -Finally, it is a good idea to add a last resort fallback layer. +Finally, it is a good idea to add a **last resort** fallback layer. This behavior component should be a simple implementation that is always applicable and does not require a lot of context knowledge. If the system is in a failing state, the latter might not be available. -We can mark behavior components as last resort fallback layers which will lead to these components not having to pass verification. -After all, they are our last straw and it's better to execute that than to do nothing. +We can mark a behavior component as last resort fallback layer in order to exclude it from verification. +After all, it's our last straw and it's better to execute that than to do nothing. In our case, we will add a `StayInPlace` behavior component. PacMan is not actually able to stop, so he will just keep moving back and forth. -Probably not an ideal strategy to win the game but we can be sure to have a comprehensible command at all times. +Probably not an ideal strategy to win the game, but we can be sure to have a comprehensible command at all times. Also, PacMan will never run into a wall with this behavior component. Phew, that was long read. Time to get our hands dirty! @@ -57,8 +57,8 @@ Add the `MoveRandomly` behavior component as a last resort fallback layer. - Add an instance of the `Verifier` to the `PacmanAgent` class and initialize it in the constructor. - Pass the `Verifier` instance to the constructors of the arbitrators. (Hint: You'll need to adjust the template parameters of the arbitrators.) -- Add the `MoveRandomly` behavior component analogously to the other behavior components. -- Mark the `MoveRandomly` behavior component as a last resort fallback layer. +- Add the `StayInPlace` behavior component analogously to the other behavior components. +- Mark the `StayInPlace` behavior component as a last resort fallback layer. - Try breaking a behavior component on purpose and see how the system reacts. (Try throwing an exception in the `getCommand()` method of a behavior component or returning a command that will lead to a collision with a wall.) @@ -74,11 +74,7 @@ VerificationResult analyze(const Time /*time*/, const Command& command) const { Position nextPosition = environmentModel_->pacmanPosition() + nextMove.deltaPosition; // The command is considered safe if the next position is in bounds and not a wall - if (environmentModel_->isPassableCell(nextPosition)) { - return VerificationResult{true}; - } - - return VerificationResult{false}; + return VerificationResult{environmentModel_->isPassableCell(nextPosition)}; } ``` From ea97846f8fe964b250dba1be8196ec993885096d Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Wed, 20 Nov 2024 00:08:47 +0100 Subject: [PATCH 41/48] Remove Task 3: Even more behavior components --- README.md | 7 +- docs/Tutorial.md | 7 +- docs/tasks/1_implement_behavior_component.md | 5 +- docs/tasks/2_extend_arbitration_graph.md | 2 +- docs/tasks/3_add_more_behaviors.md | 74 -------------------- docs/tasks/4_nested_arbitrators.md | 2 +- 6 files changed, 11 insertions(+), 86 deletions(-) delete mode 100644 docs/tasks/3_add_more_behaviors.md diff --git a/README.md b/README.md index 96128e58..682539a2 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,9 @@ It's based on this demo and guides you through all important concepts: 0. [Introduction – start here!](./docs/Tutorial.md) 1. [Implement your first behavior component](./docs/tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./docs/tasks/2_extend_arbitration_graph.md) -3. [Add even more behavior components](./docs/tasks/3_add_more_behaviors.md) -4. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) -5. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) -6. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) +3. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) +4. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) +5. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) ## Installation diff --git a/docs/Tutorial.md b/docs/Tutorial.md index cefdb410..51e8ca29 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -131,7 +131,6 @@ With the basics out of the way, let's work through the tasks. 1. [Implement your first behavior component](./tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./tasks/2_extend_arbitration_graph.md) -3. [Add even more behavior components](./tasks/3_add_more_behaviors.md) -4. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) -5. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) -6. [Verify commands and add a fallback strategy](./tasks/6_verification.md) \ No newline at end of file +3. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) +4. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) +5. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 6386c566..dde4812f 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -13,8 +13,8 @@ Before we start building our arbitration graph, we want to take a closer look in Don't worry, most of the behavior components are already implemented for you but we want to make sure you have an idea of how they work. -With the current state of the arbitration graph, PacMan will just move around randomly until a ghost gets too close. -That's great and all but if we ate a power pellet, we want to chase the ghosts to eat them for extra points. +With the current state of the arbitration graph, PacMan will just move around and eat dots until a ghost gets too close. +That's great and all but if we ate a power pellet, we want to take advantage and chase the ghosts to eat them for extra points! To do this, we need to implement the `ChaseGhost` behavior component. It essentially does the exact opposite of the `AvoidGhost` behavior component @@ -33,6 +33,7 @@ Finish the implementation of the `checkInvocationCondition()` and `getCommand()` ## Instructions +- Build and run the game, take a look at the arbitration graph and observe how PacMan behaves. - Run the unit tests and note that the `ChaseGhost` `scheckInvocationConditionFalse` test is failing - Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. - The `checkInvocationCondition()` function is already implemented but does not check for the presence of a ghost. diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 20d45a0d..891cb4fa 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -82,4 +82,4 @@ explicit PacmanAgent(const entt::Game& game) | [Tutorial Home](../Tutorial.md) | -[Next task →](3_add_more_behaviors.md) +[Next task →](4_nested_arbitrators.md) diff --git a/docs/tasks/3_add_more_behaviors.md b/docs/tasks/3_add_more_behaviors.md deleted file mode 100644 index ea5cb470..00000000 --- a/docs/tasks/3_add_more_behaviors.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: "Arbitration Graphs Tutorial" -menu_title: "More Behaviors" ---- - -# Task 3: Even more behavior components - -Integrate the `EatClosestDot` behavior component into the arbitration graph. - -## Context - -So far, we have not looked into a behavior component that handles the most important aspect of the game: eating dots. -So now is a good a time as any to further extend our arbitration graph with the `EatClosestDot` behavior component. - -We don't want to bore you with the details of planning a path through a PacMan maze, so we have already implemented that for you. -You just need to integrate it into the arbitration graph, very similarly to the [previous task](2_extend_arbitration_graph.md). - -We'll keep it simple and just add it as another option to the priority arbitrator. -Arbitration graphs can be nested of course, but we'll save that for the [next task](4_nested_arbitrators.md). - -## Goal - -Integrate the `EatClosestDot` behavior component into the arbitration graph defined in the `PacmanAgent` class. - -## Instructions - -- Integrate the new component just like you did in the [previous task](2_extend_arbitration_graph.md). -- Start the game and see how PacMan stop wandering around aimlessly and starts eating dots. - -## Solution - -
-Click here to expand the solution - -Include the header of the `EatClosestDot` behavior component in `include/demo/pacman_agent.hpp`: -```cpp -#include "eat_closest_dot_behavior.hpp" -``` - -Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class: -```cpp -private: - EatClosestDotBehavior::Ptr eatClosestDotBehavior_; -``` - -In the constructor of the `PacmanAgent` class, initialize the `ChaseGhost` behavior component and add it to the priority arbitrator: -```cpp -explicit PacmanAgent(const entt::Game& game) - : parameters_{}, environmentModel_{std::make_shared(game)} { - - avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); - chaseGhostBehavior_ = std::make_shared(environmentModel_, parameters_.chaseGhostBehavior); - // Initialize the EatClosestDot behavior component - eatClosestDotBehavior_ = std::make_shared(environmentModel_); - moveRandomlyBehavior_ = std::make_shared(parameters_.moveRandomlyBehavior); - - rootArbitrator_ = std::make_shared("Pacman"); - rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); - rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); - // Add the EatClosestDot behavior component to the priority arbitrator (after the ghost behavior components!) - rootArbitrator_->addOption(eatClosestDotBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); - rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::INTERRUPTABLE); -} -``` -
- - - ---- -[← Previous task](2_extend_arbitration_graph.md) -| -[Tutorial Home](../Tutorial.md) -| -[Next task →](4_nested_arbitrators.md) diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index 6f12bb57..f4129b8c 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -90,7 +90,7 @@ explicit PacmanAgent(const entt::Game& game) --- -[← Previous task](3_add_more_behaviors.md) +[← Previous task](2_extend_arbitration_graph.md) | [Tutorial Home](../Tutorial.md) | From 8e60c3212d8f6363ca694919e1f4872ce3c9c04d Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 17:49:36 +0100 Subject: [PATCH 42/48] Add a .bashrc to the DevContainer similar to the .zshrc --- demo/.devcontainer/.bashrc | 4 ++++ demo/.devcontainer/Dockerfile | 1 + 2 files changed, 5 insertions(+) create mode 100644 demo/.devcontainer/.bashrc diff --git a/demo/.devcontainer/.bashrc b/demo/.devcontainer/.bashrc new file mode 100644 index 00000000..b8752c22 --- /dev/null +++ b/demo/.devcontainer/.bashrc @@ -0,0 +1,4 @@ +# start Starship prompt +eval "$(starship init bash)" + +source /home/blinky/.motd \ No newline at end of file diff --git a/demo/.devcontainer/Dockerfile b/demo/.devcontainer/Dockerfile index 72ca2e1a..13eef83e 100644 --- a/demo/.devcontainer/Dockerfile +++ b/demo/.devcontainer/Dockerfile @@ -20,6 +20,7 @@ RUN curl https://starship.rs/install.sh > /tmp/starship_install.sh && \ /tmp/starship_install.sh -y && \ rm /tmp/starship_install.sh +COPY .devcontainer/.bashrc /home/blinky/.bashrc COPY .devcontainer/.zshrc /home/blinky/.zshrc USER blinky From 00f843e9243886db8b658ece6a33ee709ba5d56e Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 18:20:08 +0100 Subject: [PATCH 43/48] Apply suggestions from code review Spell Pac-Man properly Co-authored-by: ll-nick <68419636+ll-nick@users.noreply.github.com> --- demo/README.md | 2 +- docs/Tutorial.md | 8 ++++---- docs/tasks/1_implement_behavior_component.md | 6 +++--- docs/tasks/2_extend_arbitration_graph.md | 2 +- docs/tasks/4_nested_arbitrators.md | 4 ++-- docs/tasks/6_verification.md | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/demo/README.md b/demo/README.md index 03a3f39b..ff88224c 100644 --- a/demo/README.md +++ b/demo/README.md @@ -27,5 +27,5 @@ For a smooth out-of-the-box experience, we recommend using [Visual Studio Code]( - Enjoy a full-blown IDE with code-completion, code-navigation etc. - Compile via `Ctrl+Shift+B` - View, run and debug unit tests via [Testing](https://code.visualstudio.com/docs/editor/testing) sidebar - - Debug the PacMan Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar + - Debug the Pac-Man Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar - Debug with breakpoints etc. \ No newline at end of file diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 51e8ca29..b81a2806 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -1,6 +1,6 @@ # Arbitration Graphs Tutorial -Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ +Let's write an agent for the famous Pac-Man game using Arbitration Graphs 🕹ī¸ **TL;DR:** Find links to the individual tasks at the bottom of this page. @@ -10,7 +10,7 @@ Let's write an agent for the famous PacMan game using Arbitration Graphs 🕹ī¸ ### Goal The goal of this tutorial is to help you understand how to use the Arbitration Graphs library. -To keep things interesting, we will re-implement some parts of our PacMan demo. +To keep things interesting, we will re-implement some parts of our Pac-Man demo. We'll start by looking into the implementation of a single behavior component and then learn how to integrate it into an arbitration graph using a simple priority arbitrator. @@ -48,7 +48,7 @@ Enjoy a full-blown IDE with code-completion, code-navigation etc. - Explore the repo in the Explorer sidebar - Compile via `Ctrl+Shift+B` - View, run and debug unit tests via [Testing](https://code.visualstudio.com/docs/editor/testing) sidebar -- Debug the PacMan Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar +- Debug the Pac-Man Demo via [Run and Debug](https://code.visualstudio.com/docs/editor/debugging) sidebar - Debug with breakpoints etc.

@@ -111,7 +111,7 @@ Each behavior component is implemented in a separate `_behavior.hpp` file Next, there is `environment_model.hpp`. You guessed it, it contains the environment model for the arbitration graph. -In it, we store things like current positions of PacMan and the ghosts, the maze, several utility functions +In it, we store things like current positions of Pac-Man and the ghosts, the maze, several utility functions and other things required by the behavior components. The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/5_cost_arbitration.md). diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index dde4812f..3afa421d 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -13,12 +13,12 @@ Before we start building our arbitration graph, we want to take a closer look in Don't worry, most of the behavior components are already implemented for you but we want to make sure you have an idea of how they work. -With the current state of the arbitration graph, PacMan will just move around and eat dots until a ghost gets too close. +With the current state of the arbitration graph, Pac-Man will just move around and eat dots until a ghost gets too close. That's great and all but if we ate a power pellet, we want to take advantage and chase the ghosts to eat them for extra points! To do this, we need to implement the `ChaseGhost` behavior component. It essentially does the exact opposite of the `AvoidGhost` behavior component - but is only applicable when PacMan ate a power pellet. + but is only applicable when Pac-Man ate a power pellet. We can ensure that's always the case using the behavior's invocation condition. But wait - the current implementation of the invocation condition is not complete. @@ -33,7 +33,7 @@ Finish the implementation of the `checkInvocationCondition()` and `getCommand()` ## Instructions -- Build and run the game, take a look at the arbitration graph and observe how PacMan behaves. +- Build and run the game, take a look at the arbitration graph and observe how Pac-Man behaves. - Run the unit tests and note that the `ChaseGhost` `scheckInvocationConditionFalse` test is failing - Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. - The `checkInvocationCondition()` function is already implemented but does not check for the presence of a ghost. diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 891cb4fa..a2ba773f 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -27,7 +27,7 @@ Integrate the `ChaseGhost` behavior component into the arbitration graph defined - Add the `ChaseGhost` behavior component as a new member of the `PacmanAgent` class and initialize it in the constructor. - Extend the `PacmanAgent` parameter struct to include the parameters for the `ChaseGhost` behavior component. - Add a new option to the priority arbitrator. -- Run the game, take a look at the new arbitration graph and observe how PacMan behaves. +- Run the game, take a look at the new arbitration graph and observe how Pac-Man behaves. ## Solution diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index f4129b8c..15407c44 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -13,7 +13,7 @@ We have now implemented a few behavior components and integrated them into the a So far, all behavior components are children of the root arbitrator. Let's make things a bit more interesting by adding a long-term behavior component that's also about eating dots. -The `ChangeDotCluster` behavior will move to an area in the maze where there is a higher density of dots. +The `ChangeDotCluster` behavior will move Pac-man to an area in the maze where there is a higher density of dots. For now, we'll just decide between the two dot eating strategies using chance. We can achieve that by adding them to a random arbitrator which is then added as an option to the root arbitrator. @@ -30,7 +30,7 @@ Add the `EatClosestDot` and `ChangeDotCluster` behavior components to a random a - Add a random arbitrator as a new member of the `PacmanAgent` class, analogous to the priority arbitrator. - Add the `EatClosestDot` and `ChangeDotCluster` behavior components as options to the random arbitrator. - Add the random arbitrator as an option to the root arbitrator. -- Run the game and observe how PacMan behaves. +- Run the game and observe how Pac-Man behaves. ## Solution diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 853a6698..b3775ac4 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -9,12 +9,12 @@ Execute only safe commands and add a fallback strategy. ## Context -The arbitration graph is now complete and PacMan is eating dots like a pro. +The arbitration graph is now complete and Pac-Man is eating dots like a pro. But there is one last topic we want to talk about: **safety and robustness**. Depending on your application, you might only want to execute commands that you know meet certain criteria. The specific requirements will depend on your application and could be anything from physical constraints to safety requirements. -In our case, we only want to execute commands where PacMan does not run into walls. +In our case, we only want to execute commands where Pac-Man does not run into walls. We can ensure that commands obey these requirements by adding a verifier to the arbitrators. The arbitrator will then run the **verification step** and only choose commands that pass this step. @@ -39,9 +39,9 @@ We can mark a behavior component as last resort fallback layer in order to exclu After all, it's our last straw and it's better to execute that than to do nothing. In our case, we will add a `StayInPlace` behavior component. -PacMan is not actually able to stop, so he will just keep moving back and forth. +Pac-Man is not actually able to stop, so he will just keep moving back and forth. Probably not an ideal strategy to win the game, but we can be sure to have a comprehensible command at all times. -Also, PacMan will never run into a wall with this behavior component. +Also, Pac-Man will never run into a wall with this behavior component. Phew, that was long read. Time to get our hands dirty! From 4ede15aff0d656e7234278a55c78e88ec9ef7a1f Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 18:43:35 +0100 Subject: [PATCH 44/48] Fix crosslinks in docs/Tutorial.md Co-authored-by: ll-nick <68419636+ll-nick@users.noreply.github.com> --- docs/Tutorial.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Tutorial.md b/docs/Tutorial.md index b81a2806..73cefcdd 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -131,6 +131,6 @@ With the basics out of the way, let's work through the tasks. 1. [Implement your first behavior component](./tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./tasks/2_extend_arbitration_graph.md) -3. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) -4. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) -5. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) +3. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) +4. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) +5. [Verify commands and add a fallback strategy](./tasks/6_verification.md) From bf91747a71a0c9dc5e6f36c44772a5f183582842 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 18:49:57 +0100 Subject: [PATCH 45/48] Improve tasks based on review suggestions Co-authored-by: ll-nick <68419636+ll-nick@users.noreply.github.com> --- docs/tasks/1_implement_behavior_component.md | 4 ++-- docs/tasks/4_nested_arbitrators.md | 2 +- docs/tasks/5_cost_arbitration.md | 6 ++++++ docs/tasks/6_verification.md | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index 3afa421d..ba9ec7f3 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -19,7 +19,7 @@ That's great and all but if we ate a power pellet, we want to take advantage and To do this, we need to implement the `ChaseGhost` behavior component. It essentially does the exact opposite of the `AvoidGhost` behavior component but is only applicable when Pac-Man ate a power pellet. -We can ensure that's always the case using the behavior's invocation condition. +We can ensure that this is always the case by using the behavior's invocation condition. But wait - the current implementation of the invocation condition is not complete. It should only be applicable if there is one of these tasty ghosts close by. @@ -34,7 +34,7 @@ Finish the implementation of the `checkInvocationCondition()` and `getCommand()` ## Instructions - Build and run the game, take a look at the arbitration graph and observe how Pac-Man behaves. -- Run the unit tests and note that the `ChaseGhost` `scheckInvocationConditionFalse` test is failing +- Run the unit tests and note that the `ChaseGhost`'s `checkInvocationConditionFalse` test is failing - Open the implementation of the `ChaseGhost` behavior component in `src/chase_ghost_behavior.cpp`. - The `checkInvocationCondition()` function is already implemented but does not check for the presence of a ghost. - Implement the missing piece. Take a look at the implementation of `AvoidGhostBehavior::checkInvocationCondition()` if you need inspiration. diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/4_nested_arbitrators.md index 15407c44..9a8f24b5 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/4_nested_arbitrators.md @@ -9,7 +9,7 @@ Integrate a long-term behavior and add another layer to the arbitration graph. ## Context -We have now implemented a few behavior components and integrated them into the arbitration graph. +We have now implemented a behavior component and integrated it into the arbitration graph. So far, all behavior components are children of the root arbitrator. Let's make things a bit more interesting by adding a long-term behavior component that's also about eating dots. diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index bcbb6c58..610c5708 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -76,6 +76,12 @@ Also, include `cost_estimator.hpp`: #include "cost_estimator.hpp" ``` +To keep things tidy and consistent, add an alias definition analogous to the existing ones: + +```cpp +using CostArbitrator = arbitration_graphs::CostArbitrator; +``` + Change the type of the `eatDotsArbitrator_` member in the `PacmanAgent` class to `CostArbitrator` and add an instance of the `CostEstimator`: ```cpp private: diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index b3775ac4..805c856b 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -53,7 +53,8 @@ Add the `MoveRandomly` behavior component as a last resort fallback layer. ## Instructions -- In `verifier.cpp`, finish the implementation of the `Verifier::analyze()` method. +- In `verifier.hpp`, finish the implementation of the `Verifier::analyze()` method. +- Compile and run the unit tests for the `Verifier` to verify that your implementation is correct. - Add an instance of the `Verifier` to the `PacmanAgent` class and initialize it in the constructor. - Pass the `Verifier` instance to the constructors of the arbitrators. (Hint: You'll need to adjust the template parameters of the arbitrators.) From f5d7159f23d379907310294430c2189e6618d5a1 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 18:51:14 +0100 Subject: [PATCH 46/48] Fix task code snippets based on code review Co-authored-by: ll-nick <68419636+ll-nick@users.noreply.github.com> --- docs/tasks/5_cost_arbitration.md | 2 +- docs/tasks/6_verification.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/5_cost_arbitration.md index 610c5708..4941652f 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/5_cost_arbitration.md @@ -45,7 +45,7 @@ Finish the implementation of the `CostEstimator` and replace the random arbitrat Finish the implementation of the `CostEstimator` class in `cost_estimator.cpp`: ```cpp double CostEstimator::estimateCost(const Command& command, bool /*isActive*/) { - Positions absolutePath = utils::toAbsolutePath(command.path, environmentModel_); + Positions absolutePath = environmentModel_->toAbsolutePath(command.path); // Compute the number of dots along the path and in the neighborhood of the path end using helper functions const int nDotsAlongPath = utils::dotsAlongPath(absolutePath, environmentModel_); diff --git a/docs/tasks/6_verification.md b/docs/tasks/6_verification.md index 805c856b..f0b5ba6d 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/6_verification.md @@ -107,7 +107,7 @@ Make sure to also pass the verifier to the arbitrator constructors: explicit PacmanAgent(const entt::Game& game) : parameters_{}, environmentModel_{std::make_shared(game)}, - verifier_{environmentModel_} // We can initialize the verifier in the member initializer list { + verifier_{environmentModel_} { // We can initialize the verifier in the member initializer list avoidGhostBehavior_ = std::make_shared(environmentModel_, parameters_.avoidGhostBehavior); changeDotClusterBehavior_ = std::make_shared(environmentModel_); From d09defff0a2a4bf2ab0dc248317b774bacea4339 Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 18:56:57 +0100 Subject: [PATCH 47/48] Fix numbering of tutorial tasks --- README.md | 6 +++--- docs/Tutorial.md | 10 +++++----- docs/tasks/2_extend_arbitration_graph.md | 2 +- ...4_nested_arbitrators.md => 3_nested_arbitrators.md} | 6 +++--- .../{5_cost_arbitration.md => 4_cost_arbitration.md} | 8 ++++---- docs/tasks/{6_verification.md => 5_verification.md} | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) rename docs/tasks/{4_nested_arbitrators.md => 3_nested_arbitrators.md} (96%) rename docs/tasks/{5_cost_arbitration.md => 4_cost_arbitration.md} (97%) rename docs/tasks/{6_verification.md => 5_verification.md} (99%) diff --git a/README.md b/README.md index 682539a2..7a4d214e 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,9 @@ It's based on this demo and guides you through all important concepts: 0. [Introduction – start here!](./docs/Tutorial.md) 1. [Implement your first behavior component](./docs/tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./docs/tasks/2_extend_arbitration_graph.md) -3. [Learn about nested arbitration graphs](./docs/tasks/4_nested_arbitrators.md) -4. [Arbitrate based on predicted utility](./docs/tasks/5_cost_arbitration.md) -5. [Verify commands and add a fallback strategy](./docs/tasks/6_verification.md) +3. [Learn about nested arbitration graphs](./docs/tasks/3_nested_arbitrators.md) +4. [Arbitrate based on predicted utility](./docs/tasks/4_cost_arbitration.md) +5. [Verify commands and add a fallback strategy](./docs/tasks/5_verification.md) ## Installation diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 73cefcdd..e3a83098 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -114,9 +114,9 @@ You guessed it, it contains the environment model for the arbitration graph. In it, we store things like current positions of Pac-Man and the ghosts, the maze, several utility functions and other things required by the behavior components. -The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/5_cost_arbitration.md). +The `cost_estimator.hpp` file will be relevant for a later task when we cover [cost arbitrators](./tasks/4_cost_arbitration.md). -Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph [near the end](./tasks/6_verification.md) of the tutorial. +Similarly, the `verifier.hpp` file will be used to add a verification layer to the arbitration graph [near the end](./tasks/5_verification.md) of the tutorial. Finally, in `pacman_agent.hpp`, the behavior components are assembled into an arbitration graph. It's also where you'll spend most of your time during this tutorial. @@ -131,6 +131,6 @@ With the basics out of the way, let's work through the tasks. 1. [Implement your first behavior component](./tasks/1_implement_behavior_component.md) 2. [Extend the arbitration graph with that behavior](./tasks/2_extend_arbitration_graph.md) -3. [Learn about nested arbitration graphs](./tasks/4_nested_arbitrators.md) -4. [Arbitrate based on predicted utility](./tasks/5_cost_arbitration.md) -5. [Verify commands and add a fallback strategy](./tasks/6_verification.md) +3. [Learn about nested arbitration graphs](./tasks/3_nested_arbitrators.md) +4. [Arbitrate based on predicted utility](./tasks/4_cost_arbitration.md) +5. [Verify commands and add a fallback strategy](./tasks/5_verification.md) diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index a2ba773f..45c21206 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -82,4 +82,4 @@ explicit PacmanAgent(const entt::Game& game) | [Tutorial Home](../Tutorial.md) | -[Next task →](4_nested_arbitrators.md) +[Next task →](3_nested_arbitrators.md) diff --git a/docs/tasks/4_nested_arbitrators.md b/docs/tasks/3_nested_arbitrators.md similarity index 96% rename from docs/tasks/4_nested_arbitrators.md rename to docs/tasks/3_nested_arbitrators.md index 9a8f24b5..1a5cc783 100644 --- a/docs/tasks/4_nested_arbitrators.md +++ b/docs/tasks/3_nested_arbitrators.md @@ -3,7 +3,7 @@ title: "Arbitration Graphs Tutorial" menu_title: "Nesting" --- -# Task 4: Nested arbitration graphs +# Task 3: Nested arbitration graphs Integrate a long-term behavior and add another layer to the arbitration graph. @@ -18,7 +18,7 @@ The `ChangeDotCluster` behavior will move Pac-man to an area in the maze where t For now, we'll just decide between the two dot eating strategies using chance. We can achieve that by adding them to a random arbitrator which is then added as an option to the root arbitrator. -There are more sophisticated ways to decide between behavior components, we'll cover those in the [next task](5_cost_arbitration.md). +There are more sophisticated ways to decide between behavior components, we'll cover those in the [next task](4_cost_arbitration.md). ## Goal @@ -94,4 +94,4 @@ explicit PacmanAgent(const entt::Game& game) | [Tutorial Home](../Tutorial.md) | -[Next task →](5_cost_arbitration.md) +[Next task →](4_cost_arbitration.md) diff --git a/docs/tasks/5_cost_arbitration.md b/docs/tasks/4_cost_arbitration.md similarity index 97% rename from docs/tasks/5_cost_arbitration.md rename to docs/tasks/4_cost_arbitration.md index 4941652f..82745150 100644 --- a/docs/tasks/5_cost_arbitration.md +++ b/docs/tasks/4_cost_arbitration.md @@ -3,13 +3,13 @@ title: "Arbitration Graphs Tutorial" menu_title: "Cost Arbitrator" --- -# Task 5: Arbitrate based on predicted utility +# Task 4: Arbitrate based on predicted utility Learn how the cost arbitrator can help you to arbitrate between behaviors based on their expected cost/utility. ## Context -The `EatDot` arbitrator we added in the [previous task](4_nested_arbitrators.md) decides between the two dot eating strategies randomly. +The `EatDot` arbitrator we added in the [previous task](3_nested_arbitrators.md) decides between the two dot eating strategies randomly. That's obviously not the greatest idea. There must be a better way. @@ -140,8 +140,8 @@ explicit PacmanAgent(const entt::Game& game) --- -[← Previous task](4_nested_arbitrators.md) +[← Previous task](3_nested_arbitrators.md) | [Tutorial Home](../Tutorial.md) | -[Next task →](6_verification.md) +[Next task →](5_verification.md) diff --git a/docs/tasks/6_verification.md b/docs/tasks/5_verification.md similarity index 99% rename from docs/tasks/6_verification.md rename to docs/tasks/5_verification.md index f0b5ba6d..f24a8348 100644 --- a/docs/tasks/6_verification.md +++ b/docs/tasks/5_verification.md @@ -3,7 +3,7 @@ title: "Arbitration Graphs Tutorial" menu_title: "Verification and Fallbacks" --- -# Task 6: Better safe than sorry +# Task 5: Better safe than sorry Execute only safe commands and add a fallback strategy. @@ -141,6 +141,6 @@ Make sure to also pass the verifier to the arbitrator constructors: --- -[← Previous task](5_cost_arbitration.md) +[← Previous task](4_cost_arbitration.md) | [Tutorial Home](../Tutorial.md) From cbaf5aae5136700066fee97a81325442d5d89fdf Mon Sep 17 00:00:00 2001 From: Piotr Spieker Date: Tue, 26 Nov 2024 20:27:45 +0100 Subject: [PATCH 48/48] Improve HTML title --- _config.yml | 2 ++ docs/Tutorial.md | 4 ++++ docs/_layouts/default.html | 7 ++++++- docs/tasks/1_implement_behavior_component.md | 1 + docs/tasks/2_extend_arbitration_graph.md | 1 + docs/tasks/3_nested_arbitrators.md | 1 + docs/tasks/4_cost_arbitration.md | 1 + docs/tasks/5_verification.md | 1 + 8 files changed, 17 insertions(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 100338af..b881b7a5 100644 --- a/_config.yml +++ b/_config.yml @@ -17,6 +17,8 @@ layouts_dir: docs/_layouts sass: sass_dir: docs/assets/_sass +# This will be used as default HTML (sub)title +tagline: decision-making for robotics # Support collapsible details/summary sections markdown: CommonMarkGhPages diff --git a/docs/Tutorial.md b/docs/Tutorial.md index e3a83098..31f93278 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -1,3 +1,7 @@ +--- +tagline: "decision-making for Pac-Man" +--- + # Arbitration Graphs Tutorial Let's write an agent for the famous Pac-Man game using Arbitration Graphs 🕹ī¸ diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index e52daeb1..6704facb 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -3,7 +3,12 @@ -{% seo %} + {% capture htmltitle %}{{ page.title }} | {{ page.tagline | default: site.tagline | default: site.github.repository_name }}{% endcapture %} + {{ htmltitle }} + + + {% seo title=false %} + diff --git a/docs/tasks/1_implement_behavior_component.md b/docs/tasks/1_implement_behavior_component.md index ba9ec7f3..0341802a 100644 --- a/docs/tasks/1_implement_behavior_component.md +++ b/docs/tasks/1_implement_behavior_component.md @@ -1,6 +1,7 @@ --- title: "Arbitration Graphs Tutorial" menu_title: "First Behavior" +tagline: "Task 1: Implement a Behavior Component" --- # Task 1: Implement a Behavior Component diff --git a/docs/tasks/2_extend_arbitration_graph.md b/docs/tasks/2_extend_arbitration_graph.md index 45c21206..83d0ac63 100644 --- a/docs/tasks/2_extend_arbitration_graph.md +++ b/docs/tasks/2_extend_arbitration_graph.md @@ -1,6 +1,7 @@ --- title: "Arbitration Graphs Tutorial" menu_title: "Extending the Graph" +tagline: "Task 2: Extend the Arbitration Graph" --- # Task 2: Extend the Arbitration Graph diff --git a/docs/tasks/3_nested_arbitrators.md b/docs/tasks/3_nested_arbitrators.md index 1a5cc783..48b92d28 100644 --- a/docs/tasks/3_nested_arbitrators.md +++ b/docs/tasks/3_nested_arbitrators.md @@ -1,6 +1,7 @@ --- title: "Arbitration Graphs Tutorial" menu_title: "Nesting" +tagline: "Task 3: Nested arbitration graphs" --- # Task 3: Nested arbitration graphs diff --git a/docs/tasks/4_cost_arbitration.md b/docs/tasks/4_cost_arbitration.md index 82745150..b49113cc 100644 --- a/docs/tasks/4_cost_arbitration.md +++ b/docs/tasks/4_cost_arbitration.md @@ -1,6 +1,7 @@ --- title: "Arbitration Graphs Tutorial" menu_title: "Cost Arbitrator" +tagline: "Task 4: Arbitrate based on predicted utility" --- # Task 4: Arbitrate based on predicted utility diff --git a/docs/tasks/5_verification.md b/docs/tasks/5_verification.md index f24a8348..b540069c 100644 --- a/docs/tasks/5_verification.md +++ b/docs/tasks/5_verification.md @@ -1,6 +1,7 @@ --- title: "Arbitration Graphs Tutorial" menu_title: "Verification and Fallbacks" +tagline: "Task 5: Better safe than sorry" --- # Task 5: Better safe than sorry