{"id":23806868,"url":"https://github.com/joelbeedle/salsa","last_synced_at":"2026-02-19T11:02:26.370Z","repository":{"id":251030707,"uuid":"721758864","full_name":"joelbeedle/salsa","owner":"joelbeedle","description":"2D Swarm Algorithm Simulator written in C++","archived":false,"fork":false,"pushed_at":"2025-04-02T15:32:16.000Z","size":20416,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-13T09:50:34.140Z","etag":null,"topics":["drone-swarm","drones","simulation","swarm-intelligence"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"zlib","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joelbeedle.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-21T18:02:35.000Z","updated_at":"2025-04-07T16:43:57.000Z","dependencies_parsed_at":"2024-09-17T20:51:32.451Z","dependency_job_id":"3b62ac42-5607-4306-ba88-8c8457111679","html_url":"https://github.com/joelbeedle/salsa","commit_stats":{"total_commits":462,"total_committers":2,"mean_commits":231.0,"dds":0.008658008658008698,"last_synced_commit":"78826f12c9c89593b64a54135e326d2ad83b248d"},"previous_names":["joelbeedle/salsa"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/joelbeedle/salsa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelbeedle%2Fsalsa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelbeedle%2Fsalsa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelbeedle%2Fsalsa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelbeedle%2Fsalsa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joelbeedle","download_url":"https://codeload.github.com/joelbeedle/salsa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelbeedle%2Fsalsa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29611002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T10:52:55.328Z","status":"ssl_error","status_checked_at":"2026-02-19T10:52:26.323Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drone-swarm","drones","simulation","swarm-intelligence"],"created_at":"2025-01-01T23:16:05.132Z","updated_at":"2026-02-19T11:02:26.344Z","avatar_url":"https://github.com/joelbeedle.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![DOI](https://zenodo.org/badge/721758864.svg)](https://zenodo.org/doi/10.5281/zenodo.13151118) [![SALSA Paper](https://img.shields.io/badge/IEEE-Xplore-orange)](https://ieeexplore.ieee.org/document/10766106)\n\n# SALSA - Swarm Algorithm Simulator\n\n**S**warm **Al**gorithm **S**imul**a**tior Library and Testbed, written in C++.\n\n**SALSA** is intended for use primarily in swarm behavior algorithm testing. Ideally, it fits early-on in the process of developing software for swarms of drones, helping users to develop algorithms, and view prelimiary tests on algorithm effectiveness and correctness. After verification, depending on user requirements, could either stick with **SALSA**, maybe even extending it for their specific needs (such as adding their drone specifications, adding a movement model, or even a new testbed using the Library), or they could move on to more sophisticated software, now that they know what their algorithm **should** look like when performing correctly.\n\n[SALSA Testbed Demonstration video](https://youtu.be/K64oUI9zK0c)\n\n## Getting Started\n\nThere is a Docker container available. It opens a noVNC web app on `localhost` with `salsa` pre-installed.\n\n### Using Docker\n#### Prebuilt Docker container\n\nThis docker container **only** contains what is in the repository. If you want to extend the program, you need to clone the repository and build the docker container / the code.\n\n- **Run the docker image:**\n\n```bash\ndocker run --shm-size=256m -it -p 5901:5901 -e VNC_PASSWD=123456 ghcr.io/joelbeedle/salsa:latest\n```\n\n#### Building the Docker container yourself\n\n- **Clone the repository:**\n\n```bash\ngit clone --recursive https://github.com/joelbeedle/salsa.git\ngit submodule update --init --recursive\n```\n\n- **Build the docker image:**\n\n```bash\ndocker build -t salsa-test/testbed .\n```\n\n- **Run the container:**\n\n```bash\ndocker run --shm-size=256m -it -p 5901:5901 -e VNC_PASSWD=123456 salsa-test/testbed\n```\n\nUsing either method, to use the virtual machine:\n\n- Go to `http://localhost:5901` and enter the password `123456`\n\n- Right click, select `Applications \u003e Shells \u003e Bash` and you will find yourself already in a terminal in the repository.\n\n- The testbed application can be found at `./build/testbed/`\n\n- More information on how to use the testbed can be found [here](#using-the-testbed)\n\n### Building it yourself\n\n`salsa` was designed with to be cross-platform, for Windows, Linux, and macOS.\n\n#### Requirements\n\n- CMake **3.14+**\n- A **C++17** compatible compiler (gcc, clang, cl)\n- Git\n- OpenGL\n- Python3\n- Optional: [Doxygen](https://github.com/doxygen/doxygen), [Ninja](https://github.com/ninja-build/ninja)\n\nRequirements in bold are **essential**.\n\n`salsa` uses the following packages directly:\n\n- [Box2D](https://github.com/erincatto/box2d)\n- [GLAD](https://github.com/Dav1dde/glad) and [GLFW](https://www.glfw.org/)\n- [spdlog](https://github.com/gabime/spdlog)\n- [nlohmann_json](https://github.com/nlohmann/json)\n- [CLI11](https://github.com/CLIUtils/CLI11)\n- [ImGui](https://github.com/ocornut/imgui)\n- [googletest](https://github.com/google/googletest)\n\nThese requirements are all either managed as git submodules, or are fetched and installed into `build/_deps` when configuring using CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module automatically, so you shouldn't have to do anything to set them up.\n\n#### Steps\n\n- **Clone the repository and all submodules:**\n  ```bash\n  git clone --recursive https://github.com/joelbeedle/salsa.git\n  ```\n  \u003e **Note**: the `--recursive` tag is important, as this also clones the submodules, which are needed.\n- **Initialise and update the submodules:**\n  ```bash\n  git submodule update --init --recursive\n  ```\n- **Configure the project with CMake:**\n\n  ```bash\n  cd salsa\n  cmake -S . -B build\n  ```\n\n  \u003e If you have Ninja installed, for a faster build time use:\n  \u003e\n  \u003e ```bash\n  \u003e  cmake -S . -B build -GNinja\n  \u003e ```\n\n- **Build the project:**\n  ```bash\n  cmake --build build\n  ```\n- **To build documentation (requires Doxygen):**\n  ```bash\n  cmake --build build --target docs\n  ```\n  \u003e Documentation can then be found in `build/docs/html/index.html`\n\n\u003e There are also some common build configurations found in `CMakePresents.json`.\n\n### Running Testbed\n\nTo run the testbed:\n\n- Navigate to the `build/testbed` directory and execute `./testbed`.\n- Use `./testbed --help` for a list of command line parameters\n\nThe testbed, when opened, presents the main menu. From here, we can access the following features:\n\n- **Simulators**\n  - [Queue Mode](#queue-mode)\n  - [Sandbox Mode](#sandbox-mode)\n- [**Map Creator**](#map-creator)\n\n## Using the Testbed\n\nThe testbed is extended from the original Box2D testbed. It has three interactive GUI modes, and a headless mode. The three GUI modes are Sandbox, Queue, and Map Creator.\n\nThe testbed comes with a template `user.cpp` file, containing an example on how to configure the testbed and use the Test Queue. There is more detail on how to create custom implementations in the [Extensibility section](#extensibility).\n\nBoth Sandbox and Queue modes allow the user to dynamically interact with the simulation as it is occuring. Queue mode is intended to collect data, and Sandbox mode is intended for algorithm development. Modes can be switched between seamlessly. Registries are used internally inside the `salsa` library as communication interfaces.\n\nHeadless mode can be entered using `./testbed --headless`. Headless mode runs much faster than the visual modes, as it is intended to iterate through simulations, outputting data. Verbose mode can be selected using `-v`, and a `.json` queue file (generated from the testbed) to use can be specified using `-q`. The `.json` file extension does not need to be included, but if it is, the program still runs.\n\n\u003e Example: `./testbed --headless -v -q example_queue` \n\nAn example of how to use **Sandbox** and **Queue** is shown in the [demonstration video](https://www.youtube.com/watch?v=K64oUI9zK0c)\n\n### Queue Mode\n\u003cimg src=\"./docs/imgs/boxplot.jpg\" width=\"500\"\u003e\n\nWe used the Queue mode to generate the data used for the plot above. To run a similar queue (bar the Levy Flocking), you can load [example queue](./example_queue.json).\n\n**Features:**\n- Create a test queue of various simulations and parameters, and get output data. Data is logged to the `testbed/results` folder.\n- After the time limit for each runs out, plots are created from the data automatically.\n  \u003e In headless mode, all plots are generated unless specified otherwise.\n- The queue can be set beforehand in `user.cpp`, or generated in the GUI.\n  - To generate in the GUI: go to the Test Queue section, click the `+` button, and choose whether to add a single test or add a group of tests, permuting behavior parameters.\n\n#### Saving and Loading Queues\n\n- Queues can be saved and loaded through the GUI, and also in user code, using `TestQueue::load(filename)` and `TestQueue::save(filename)`. A saved queue can also be independently loaded in headless mode using the `-q` option.\n\n#### Performance Analysis\n\n- The real-time factor performance of the simulator is assessed when ran headless and using the `-v` verbose setting. The simulator will then go through the test queue, and for each entry, when the test is complete, calculates the RTF. It outputs this into `results/` with the `.csv` filename the same as the test queue configuration file.\n\n- To generate the data shown in `Table 1` of the paper:\n  - **Ensure that the** `.csv` **file is empty, or deleted**\n  - **Build the simulator**\n  - **Run the simulator headless, with verbosity, no plots, and specify the automatically generated test queue:** `./testbed --headless -v --no-plots -q performance_table_queue`\n  - **wait until this is complete**\n  - **Go to** `testbed/plot/`\n  - **Run** `python3 table.py performance_table_queue.csv`\n  - **The table is displayed in the console**\n\n### Sandbox Mode\n\nSandbox mode is used to test a behavior, without having to create tests. It is intended as a way for users to visually interact with their algorithms, and assess if they are functioning correctly.\n\n**Features:**\n- Dynamically change parameters, maps, drone configurations, etc., on the go.\n- Change swarm sizes, map, behaviour, and any parameters, and get instant feedback on what the changes do.\n\n### Map Creator\n\nThe Map Creator allows the user to create their own maps. The menu on the left is the main interface.\n\n- **Drawing Tips:**\n  - Drawing lines is done by clicking and holding, then dragging and releasing to end the line\n  - Drawing shapes (hollow polygon, polygon) is done by clicking once, releasing, then clicking again to set the next vertex. Connect the last vertex to the first to draw the shape.\n  - The drone spawn point should be set for where you want drones to spawn.\n\n    \u003e Drones wont spawn inside solid objects, but they will spawn inside hollow polygons.\n\n  - A square world boundary can be set by checking Draw Boundary and adjusting the size of the sides.\n  - Press `Q` to `undo` the last drawing action, or reset the cursor.\n\n#### Saving and Loading Maps\n- **To save**, click `File \u003e Save As` and then enter a name when prompted. This will refresh the map registry, so if you want to use the map in a simulation straight away, you can.\n- **To load**, click `File \u003e Load`, and select a map to load.\n\n## Extensibility\n\nSALSA is designed with extensibility at it's heart - it works best when it's utilised and moulded to whatever the user wants.\n\nThe testbed can be extended in multiple ways: users can create custom swarm algorithms, targets, contact listeners and managers, and drone configurations, alongside custom maps and data. New testbed modes could be added, similar to the current `Queue` and `Sandbox` modes. Furthermore, as the Library function is decoupled from our Testbed, a new testbed could be created entirely: perhaps targeting ground based robots, utilising the framework the Library provides in the same ways that our Testbed does.\n\n\u003e [!IMPORTANT]\n\u003e **Any new files need to be added to the testbed `CMakeLists.txt` file, in `MY_TESTBED_SOURCE_FILES`.**\n\nFor more information and examples on extending the various aspects of the testbed, expand a section below.\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAdding new swarm Algorithms\u003c/summary\u003e\n\n### Add a Custom swarm Algorithm\n\nTo add a custom swarm algorithm:\nCreate a new `.cpp` file inside `testbed/behaviors`, and name it, etc `my_alg.cpp`.\n\nInside this file, import `\u003csalsa/salsa.h\u003e` to import all library headers. (The following examples are as if the code is written inside the `salsa` namespace, for ease of reading)\n\nCreate a class that extends the `Behaviour` class:\n\n```cpp\n#include \u003csalsa/salsa.h\u003e\n\nclass MyAlg : public Behaviour {};\n```\n\nDefine any parameters as a behaviour::Parameter\n\n```cpp\nclass MyAlg : public Behaviour {\n  private:\n   behaviour::Parameter param_1_;\n   behaviour::Parameter param_2_;\n   behaviour::Parameter param_3_;\n};\n```\n\nImplement a constructor that takes as arguments the behaviour parameters, and pass these into the defined `behaviour::Parameter`s in the constructor initializer list.\n\nThen, create a key value pair in `parameters_`, a map of names to parameters, using as a key the display name, and as value a reference to the internal `behaviour::Parameter`.\n\n```cpp\n class MyAlg : public Behaviour {\n   private:\n    behaviour::Parameter param_1_;\n    behaviour::Parameter param_2_;\n   public:\n    // 1. Implement constructor, pass values in constructor initializer list.\n    MyAlg(float param_1, float param_2) {\n      // 2. Create key, value pair in parameters_ map.\n      // parameters_ is defined in Behaviour and is a unordered_map\u003cParameter*\u003e\n      parameters_[\"Parameter 1\"] = \u0026param_1_;\n      parameters_[\"Parameter 2\"] = \u0026param_2_;\n    }\n\n```\n\nImplement `execute()`, returning an acceleration vector for that drone.\n\n```cpp\n// \u003csnip\u003e\nb2Vec2 execute(const std::vector\u003cstd::unique_ptr\u003cDrone\u003e\u003e \u0026drones,\n            Drone \u0026currentDrone) override {\n   // Insert custom behaviour code here\n   return drone_acceleration;\n}\n```\n\nAfter the class definition, create an instance and register it with the behaviour registry with its initial parameters.\n\n```cpp\nauto alg = behaviour::Registry::get().add(\n    \"My Alg\",\n    std::make_unique\u003cMyAlg\u003e(param_1, param_2));\n```\n\nThis behaviour will now appear in the testbed, and can be set in a TestConfig using the behaviour namme specified, e.g. `My Alg`\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \n\u003csummary\u003eAdding new Targets\u003c/summary\u003e\n\n### Add a custom Target\n\nCreate a `.cpp` and `.h` file in `testbed/targets`, and name it, etc. `my_target.h`.\n\nIn the header file, include `\u003ccore/simulation.h\u003e` and create a class that extends `salsa::Target`\n\n```cpp\nclass MyTarget : public Target {};\n```\n\nIn its constructor, a target **must** have the first 3 parameters as `b2World* world, const b2Vec2\u0026 position, int id`, but any other parameters are user definable.\n\n```cpp\nMyTarget(b2World* world, const b2Vec2 \u0026position, int id, bool visible, float radius, int arg) {}\n```\n\nA target should follow this pattern for its body definitions:\n\n```cpp\n  // Shape can be anything\n  b2CircleShape shape;\n  shape.m_radius = radius;\n\n  // Targets have a fixture that is a sensor\n  b2FixtureDef fixtureDef;\n  fixtureDef.shape = \u0026shape;\n  fixtureDef.isSensor = true;\n\n  // We register this type with the collision manager, get a config back\n  //  and set the filter category and mask the received settings.\n  auto config = CollisionManager::getCollisionConfig\u003cTree\u003e();\n  fixtureDef.filter.categoryBits = config.categoryBits;\n  fixtureDef.filter.maskBits = config.maskBits;\n\n  // We then create a salsa::UserData object. This is metadata and how collision callbacks are managed.\n  UserData *my_data = new UserData();\n  // Set the userData's object argument to point to this instance\n  my_data-\u003eobject = this;\n  // Set the userData of the fixtureDef as a pointer to our salsa::UserData object and create fixture\n  fixtureDef.userData.pointer = reinterpret_cast\u003cuintptr_t\u003e(my_data);\n  body_-\u003eCreateFixture(\u0026fixtureDef);\n```\n\nWe don't need to worry about creating the body, as this is done through the `Entity` class that `Target` inherits from. This is done to simplify creation and abstract the physics engine interface from the user.\nOnce the target is fully defined, we register it with the `TargetFactory` and the collision manager, in our `user.cpp`.\n\n```cpp\n// user.cpp\n// If we want drones to detect this target type and the target type to also detect the trees, define both.\n// If not, `registerType` should take \u003c The thing you want to do the detecting \u003e\nCollisionManager::registerType\u003cDrone\u003e({typeid(Tree).name()});\nCollisionManager::registerType\u003cTree\u003e({typeid(Drone).name()});\n\n// Register our custom type with the TargetFactory. We supply it with template parameters corresponding to the **unique** parameters in our target class (AKA not the three that need to be there)\nTargetFactory::registerTarget\u003cMyTarget, bool, bool, float\u003e(\"Target Instance Name\", false, false, true);\n```\n\nNow the type is fully registered and can be included in the simulation through TestConfigs like as follows:\n\n```cpp\n  salsa::TestConfig config = {\"My Alg\",\n                           behaviour_parameters,\n                           drone_config,\n                           map_name,\n                           drone_count,\n                           target_count,\n                           time_limit,\n                           \"Target Instance Name\"\n                           contact_listener_name};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAdding custom Contact Listeners\u003c/summary\u003e\n\n### Adding a new Contact Listener\n\nAfter registering types as shown above, collisions between them can be controlled via the `salsa::BaseContactListener` class. (This class could also be extended, if the user wishes)\nTo do this, in the main testbed entrypoint `main.cpp`, create a new static shared pointer of `salsa::BaseContactListener` (it has to be static so it can be accessed from other scopes), and give it a name:\n\n```cpp\n  static auto contact_listener = std::make_shared\u003cBaseContactListener\u003e(\"Name\");\n```\n\nThen, add collision handlers to it using the `addCollisionHandler` function. This function takes two types, which can be retrieved via `salsa::get_type\u003cClass Name\u003e`, and a user defined function. This function needs to be `void`, and takes two function parameters: `b2Fixture*` and `b2Fixture*`. These two fixtures represent the two fixtures that have been found to be colliding.\n\nHere's an example of adding a collision handler between a `Drone` and a `MyTarget`, using a lambda function:\n\n```cpp\n\nvoid collideDroneMyTarget(b2Fixture* drone_fixture, b2Fixture* target_fixture) {\n     // Check if the drone fixture is a sensor, we don't want to do this if it's the physical drone\n  if (drone_fixture.isSensor()) {\n      Drone *drone = reinterpret_cast\u003cUserData *\u003e(\n                               drone_fixture-\u003eGetUserData().pointer)\n                               -\u003eas\u003cDrone\u003e();\n      MyTarget *my_target = reinterpret_cast\u003cUserData *\u003e(\n                      target_fixture-\u003eGetUserData().pointer)\n                      -\u003eas\u003cMyTarget\u003e();\n      my_target-\u003eDoSomething();\n      drone-\u003eaddTargetFound(my_target);\n      std::cout \u003c\u003c drone-\u003egetId() \u003c\u003c \" found \" \u003c\u003c std::cout \u003c\u003c my_target-\u003egetId() \u003c\u003c std::endl;\n   }\n}\ncontact_listener-\u003eaddCollisionHandler(\n      get_type\u003cDrone\u003e, get_type\u003cMyTarget\u003e,\n      collideDroneMyTarget\n      );\n```\n\n- This can also be done inline using lambda functions:\n\n```cpp\n   contact_listener-\u003eaddCollisionHandler(\n      get_type\u003cDrone\u003e, get_type\u003cMyTarget\u003e,\n      [](b2Fixture* a, b2Fixture* b) -\u003e void {\n         // Do something with a and b\n      });\n```\n\nWe then pass the listener's name into the `TestConfig` for it to be used by a simulation.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAdding custom Drone Configurations\u003c/summary\u003e\n  \n### Adding a new Drone Configuration\nDrone configurations are simple to add. We simpy create one in `user.cpp`, give it a name, and it will appear in the testbed.\n\n```cpp\nsalsa::DroneConfiguration *drone_config = new salsa::DroneConfiguration(\n    \"Config Name\", 15.0f, 50.2f, 10.0f, 0.3f, 1.0f, 1.5f, 134.0f);\n```\n\n\u003c/details\u003e\n\n## Example Testbed Configuration\n\n```cpp\n// user.cpp\n#include \"testbed.h\"\n\nusing namespace salsa;\n\nvoid user() {\n  // Get the default parameters for CustomBehaviour\n  auto behaviour_parameters = behaviour::Registry::get().behaviour(\"Custom Behaviour\")-\u003egetParameters();\n\n  // Create a drone configuration\n  auto *drone_config = new DroneConfiguration(\"My Config\",\n      25.0f, 50.0f, 10.0f, 0.3f, 1.0f, 1.5f, 4000.0f);\n\n  // Set up the listener to listen for collisions.\n  // Has to be static, and named\n  static auto listener = std::make_shared\u003cBaseContactListener\u003e(\"Default\");\n\n  // Register the drones and targets with the collision manager\n  CollisionManager::registerType\u003cDrone\u003e({typeid(CustomTarget).name()});\n  CollisionManager::registerType\u003cCustomTarget\u003e({typeid(Drone).name()});\n\n  // Add the target to the TargetFactory, supplying any custom parameters and their types\n  // This can be done multiple times for the same Target class, with a different name.\n   TargetFactory::registerTarget\u003cCustomTarget, bool, bool, float\u003e(\"Custom_1\", false,\n                                                                false, 5.0f);\n\n  // Add a collision handler between Drone and Target types, when this collision is detected, userHandlingFunction is called to handle the collision.\n  listener.addColisionHandler(typeid(Drone), typeid(CustomTarget), userHandlingFunction)\n\n  // Set up test environment\n  auto map_name = \"test\" // \"test.json\" here is a map that has already been created and is in testbed/maps\n  auto num_drones = 100;\n  auto num_targets = 1000;\n  auto time_limit = 1200.0;\n\n  TestConfig test = {\n     \"Custom Behaviour\",\n     behaviour_parameters,\n     drone_config,\n     map_name,\n     num_drones,\n     num_targets,\n     target_type,   // \"Custom_1\"\n     listener_name, // \"Default\"\n     time_limit,    // 100.0\n  };\n\n  // Add test to the Simulator's TestQueue\n  TestQueue::push(test);\n\n  // Or... load a queue that you've saved before:\n  TestQueue::load(\"my_queue\");\n}\n```\n\nThis code will not compile. For an example that sets up a test queue, check the real `testbed/user.cpp` file.\n\n## Contributions\nContributions are welcome for SALSA! Please see the [Contributing to SALSA guide](https://github.com/joelbeedle/salsa/blob/master/.github/CONTRIBUTING.md) for more information.\n\n## Publications\n\n- [SALSA: Swarm Algorithm Simulator](https://ieeexplore.ieee.org/document/10766106)\n  ```\n  J. Beedle, C. Imrie and R. Calinescu, \"SALSA: Swarm Algorithm Simulator,\" 2024 IEEE International Conference on Autonomic Computing and Self-Organizing Systems Companion (ACSOS-C), Aarhus, Denmark, 2024, pp. 140-145, doi: 10.1109/ACSOS-C63493.2024.00045.\n  ```\n\n## License\nSALSA is licensed under the [zlib License](https://www.zlib.net/zlib_license.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoelbeedle%2Fsalsa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoelbeedle%2Fsalsa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoelbeedle%2Fsalsa/lists"}