diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 67a9183de..6180919f5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. mac/linux/windows] - - Version [e.g. 1.0.2] + - Version [e.g. 1.1.0] **Additional context** Add any other context about the problem here. diff --git a/.gitmodules b/.gitmodules index c7835f09c..db530b4e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,4 +14,7 @@ path=python/examples/experiments/conditional-action-trees url=https://github.com/Bam4d/conditional-action-trees ignore = dirty - +[submodule "python/examples/experiments/rts-self-play"] + path = python/examples/experiments/rts-self-play + url = https://github.com/Bam4d/rts-self-play + ignore = dirty diff --git a/CMakeLists.txt b/CMakeLists.txt index fe71fc69f..fce710fb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10.0) -project(Griddly VERSION 1.0.2) +project(Griddly VERSION 1.1.0) set(BINARY ${CMAKE_PROJECT_NAME}) diff --git a/bindings/python.cpp b/bindings/python.cpp index d2b1d1c22..5f49ab57c 100644 --- a/bindings/python.cpp +++ b/bindings/python.cpp @@ -12,7 +12,7 @@ namespace griddly { PYBIND11_MODULE(python_griddly, m) { m.doc() = "Griddly python bindings"; - m.attr("version") = "1.0.2"; + m.attr("version") = "1.1.0"; #ifndef NDEBUG spdlog::set_level(spdlog::level::debug); @@ -62,6 +62,10 @@ PYBIND11_MODULE(python_griddly, m) { game_process.def("get_width", &Py_GameWrapper::getWidth); game_process.def("get_height", &Py_GameWrapper::getHeight); + // Observation shapes + game_process.def("get_global_observation_shape", &Py_GameWrapper::getGlobalObservationShape); + game_process.def("get_player_observation_shape", &Py_GameWrapper::getPlayerObservationShape); + // Tile size of the global observer game_process.def("get_tile_size", &Py_GameWrapper::getTileSize); game_process.def("observe", &Py_GameWrapper::observe); diff --git a/bindings/wrapper/GameWrapper.cpp b/bindings/wrapper/GameWrapper.cpp index 65d0b43a0..d0607839f 100644 --- a/bindings/wrapper/GameWrapper.cpp +++ b/bindings/wrapper/GameWrapper.cpp @@ -9,27 +9,26 @@ namespace griddly { class ValidActionNode { - public: - std::unordered_map> children; - - bool contains(uint32_t value) { - return children.find(value) != children.end(); - } + public: + std::unordered_map> children; - void add(uint32_t value) { - children[value] = std::shared_ptr(new ValidActionNode()); - } + bool contains(uint32_t value) { + return children.find(value) != children.end(); + } - static py::dict toPyDict(std::shared_ptr node) { - py::dict py_dict; - for(auto child: node->children) { - py_dict[py::cast(child.first)] = toPyDict(child.second); - } + void add(uint32_t value) { + children[value] = std::shared_ptr(new ValidActionNode()); + } - return py_dict; + static py::dict toPyDict(std::shared_ptr node) { + py::dict py_dict; + for (auto child : node->children) { + py_dict[py::cast(child.first)] = toPyDict(child.second); } -}; + return py_dict; + } +}; class Py_GameWrapper { public: @@ -65,8 +64,8 @@ class Py_GameWrapper { const uint32_t getActionTypeId(std::string actionName) const { auto actionNames = gdyFactory_->getExternalActionNames(); - for(int i = 0; i buildValidActionTrees() const { - - std::vector valid_action_trees; + std::vector valid_action_trees; auto externalActionNames = gdyFactory_->getExternalActionNames(); spdlog::debug("Building tree, {0} actions", externalActionNames.size()); for (int playerId = 1; playerId <= playerCount_; playerId++) { @@ -84,10 +82,7 @@ class Py_GameWrapper { auto location = actionNamesAtLocation.first; auto actionNames = actionNamesAtLocation.second; - - for (auto actionName : actionNames) { - spdlog::debug("[{0}] available at location [{1}, {2}]", actionName, location.x, location.y); std::shared_ptr treePtr = node; @@ -102,14 +97,14 @@ class Py_GameWrapper { if (gdyFactory_->getAvatarObject().length() == 0) { auto py_x = locationVec[0]; auto py_y = locationVec[1]; - if(!treePtr->contains(py_x)) { - treePtr->add(py_x); + if (!treePtr->contains(py_x)) { + treePtr->add(py_x); } treePtr = treePtr->children[py_x]; - if(!treePtr->contains(py_y)) { - treePtr->add(py_y); + if (!treePtr->contains(py_y)) { + treePtr->add(py_y); } treePtr = treePtr->children[py_y]; @@ -117,14 +112,14 @@ class Py_GameWrapper { if (externalActionNames.size() > 1) { auto actionTypeId = getActionTypeId(actionName); - if(!treePtr->contains(actionTypeId)) { + if (!treePtr->contains(actionTypeId)) { treePtr->add(actionTypeId); } treePtr = treePtr->children[actionTypeId]; } - for(auto id : actionIdsForName) { + for (auto id : actionIdsForName) { treePtr->add(id); } treePtr->add(0); @@ -180,14 +175,21 @@ class Py_GameWrapper { gameProcess_->setLevel(levelString); } - std::shared_ptr> reset() { - auto observation = gameProcess_->reset(); - if (observation != nullptr) { - auto observer = gameProcess_->getObserver(); - return std::shared_ptr>(new NumpyWrapper(observer->getShape(), observer->getStrides(), std::move(observation))); + void reset() { + gameProcess_->reset(); + } + + std::vector getGlobalObservationShape() const { + auto observer = gameProcess_->getObserver(); + if (observer == nullptr) { + return {}; + } else { + return observer->getShape(); } + } - return nullptr; + std::vector getPlayerObservationShape() const { + return players_[0]->getObservationShape(); } std::shared_ptr> observe() { @@ -197,7 +199,9 @@ class Py_GameWrapper { throw std::invalid_argument("No global observer configured"); } - return std::shared_ptr>(new NumpyWrapper(observer->getShape(), observer->getStrides(), gameProcess_->observe())); + auto observationData = observer->update(); + + return std::shared_ptr>(new NumpyWrapper(observer->getShape(), observer->getStrides(), observationData)); } py::tuple stepParallel(py::buffer stepArray) { @@ -265,13 +269,17 @@ class Py_GameWrapper { auto playerStepResult = players_[p]->stepSingle(actionName, actionArray, lastPlayer); - playerRewards.push_back(playerStepResult[0].cast()); + //playerRewards.push_back(playerStepResult[0].cast()); if (lastPlayer) { - terminated = playerStepResult[1].cast(); - info = playerStepResult[2]; + terminated = playerStepResult[0].cast(); + info = playerStepResult[1]; } } + for(int p = 0; p < playerSize; p++) { + playerRewards.push_back(gameProcess_->getAccumulatedRewards(p+1)); + } + return py::make_tuple(playerRewards, terminated, info); } diff --git a/bindings/wrapper/StepPlayerWrapper.cpp b/bindings/wrapper/StepPlayerWrapper.cpp index 65a191b43..06bfd90bb 100644 --- a/bindings/wrapper/StepPlayerWrapper.cpp +++ b/bindings/wrapper/StepPlayerWrapper.cpp @@ -25,13 +25,19 @@ class Py_StepPlayerWrapper { return {(uint32_t)tileSize[0], (uint32_t)tileSize[1]}; } + std::vector getObservationShape() const { + return player_->getObserver()->getShape(); + } + std::shared_ptr> observe() { auto observer = player_->getObserver(); if (observer == nullptr) { throw std::invalid_argument("No player observer configured"); } - return std::shared_ptr>(new NumpyWrapper(observer->getShape(), observer->getStrides(), player_->observe())); + auto observationData = observer->update(); + + return std::shared_ptr>(new NumpyWrapper(observer->getShape(), observer->getStrides(), observationData)); } py::tuple stepMulti(py::buffer stepArray, bool updateTicks) { @@ -100,23 +106,30 @@ class Py_StepPlayerWrapper { } } - return performActions(actions, updateTicks); + auto actionResult = player_->performActions(actions, updateTicks); + auto info = buildInfo(actionResult); + auto rewards = gameProcess_->getAccumulatedRewards(player_->getId()); + return py::make_tuple(rewards, actionResult.terminated, info); + } py::tuple stepSingle(std::string actionName, std::vector actionArray, bool updateTicks) { - auto gameProcess = player_->getGameProcess(); - - if (gameProcess != nullptr && !gameProcess->isInitialized()) { + if (gameProcess_ != nullptr && !gameProcess_->isInitialized()) { throw std::invalid_argument("Cannot send player commands when game has not been initialized."); } auto action = buildAction(actionName, actionArray); + ActionResult actionResult; if (action != nullptr) { - return performActions({action}, updateTicks); + actionResult = player_->performActions({action}, updateTicks); } else { - return performActions({}, updateTicks); + actionResult = player_->performActions({}, updateTicks); } + + auto info = buildInfo(actionResult); + + return py::make_tuple(actionResult.terminated, info); } private: @@ -124,12 +137,6 @@ class Py_StepPlayerWrapper { const std::shared_ptr gdyFactory_; const std::shared_ptr gameProcess_; - py::tuple performActions(std::vector> actions, bool updateTicks) { - auto actionResult = player_->performActions(actions, updateTicks); - auto info = buildInfo(actionResult); - return py::make_tuple(actionResult.reward, actionResult.terminated, info); - } - py::dict buildInfo(ActionResult actionResult) { py::dict py_info; diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 35d16c7e1..aae786a78 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -16,4 +16,8 @@ .game-gallery p { margin: 10px !important; white-space: normal !important; +} + +.embedded-video { + text-align: center; } \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 791cda6d3..9def514bc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Chris Bamford' # The full version, including alpha/beta/rc tags -release = '1.0.2' +release = '1.1.0' # -- General configuration --------------------------------------------------- diff --git a/docs/games/Bait/img/Bait-level-Block2D-1.png b/docs/games/Bait/img/Bait-level-Block2D-1.png index 9dfa12cf3..54890ef95 100644 Binary files a/docs/games/Bait/img/Bait-level-Block2D-1.png and b/docs/games/Bait/img/Bait-level-Block2D-1.png differ diff --git a/docs/games/Bait/img/Bait-level-Block2D-3.png b/docs/games/Bait/img/Bait-level-Block2D-3.png index d3bab6e32..fb6610be2 100644 Binary files a/docs/games/Bait/img/Bait-level-Block2D-3.png and b/docs/games/Bait/img/Bait-level-Block2D-3.png differ diff --git a/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-1.png b/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-1.png index 9dfa12cf3..54890ef95 100644 Binary files a/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-1.png and b/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-1.png differ diff --git a/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-3.png b/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-3.png index d3bab6e32..fb6610be2 100644 Binary files a/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-3.png and b/docs/games/Bait_With_Keys/img/Bait_With_Keys-level-Block2D-3.png differ diff --git a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-1.png b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-1.png index 74920bd79..279576afa 100644 Binary files a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-1.png and b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-1.png differ diff --git a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-3.png b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-3.png index 6102a454c..279576afa 100644 Binary files a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-3.png and b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-3.png differ diff --git a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-5.png b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-5.png index e9af362f6..279576afa 100644 Binary files a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-5.png and b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-5.png differ diff --git a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-7.png b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-7.png index 0fb0fe63f..279576afa 100644 Binary files a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-7.png and b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-7.png differ diff --git a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-9.png b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-9.png index 642970ea8..d44d37c81 100644 Binary files a/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-9.png and b/docs/games/Butterflies_and_Spiders/img/Butterflies_and_Spiders-level-Block2D-9.png differ diff --git a/docs/games/Clusters/img/Clusters-level-Block2D-1.png b/docs/games/Clusters/img/Clusters-level-Block2D-1.png index b2af26802..19d7c2150 100644 Binary files a/docs/games/Clusters/img/Clusters-level-Block2D-1.png and b/docs/games/Clusters/img/Clusters-level-Block2D-1.png differ diff --git a/docs/games/Clusters/img/Clusters-level-Block2D-3.png b/docs/games/Clusters/img/Clusters-level-Block2D-3.png index c54c511f7..19d7c2150 100644 Binary files a/docs/games/Clusters/img/Clusters-level-Block2D-3.png and b/docs/games/Clusters/img/Clusters-level-Block2D-3.png differ diff --git a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-1.png b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-1.png index 701ee2ae2..14ad67145 100644 Binary files a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-1.png and b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-1.png differ diff --git a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-3.png b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-3.png index 39e7dacb8..14ad67145 100644 Binary files a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-3.png and b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-3.png differ diff --git a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-5.png b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-5.png index 0e0d8881a..14ad67145 100644 Binary files a/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-5.png and b/docs/games/Cook_Me_Pasta/img/Cook_Me_Pasta-level-Block2D-5.png differ diff --git a/docs/games/Doggo/img/Doggo-level-Block2D-1.png b/docs/games/Doggo/img/Doggo-level-Block2D-1.png index 331ec464d..a5bfa50ab 100644 Binary files a/docs/games/Doggo/img/Doggo-level-Block2D-1.png and b/docs/games/Doggo/img/Doggo-level-Block2D-1.png differ diff --git a/docs/games/Doggo/img/Doggo-level-Block2D-3.png b/docs/games/Doggo/img/Doggo-level-Block2D-3.png index 0f440e871..49f4e9f67 100644 Binary files a/docs/games/Doggo/img/Doggo-level-Block2D-3.png and b/docs/games/Doggo/img/Doggo-level-Block2D-3.png differ diff --git a/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-1.png b/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-1.png index 6228cc49b..a5bfa50ab 100644 Binary files a/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-1.png and b/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-1.png differ diff --git a/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-3.png b/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-3.png index dd7cc19b4..49f4e9f67 100644 Binary files a/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-3.png and b/docs/games/Drunk_Dwarf/img/Drunk_Dwarf-level-Block2D-3.png differ diff --git a/docs/games/Foragers/img/Foragers-level-Block2D-1.png b/docs/games/Foragers/img/Foragers-level-Block2D-1.png index e608df94f..4bf7e243c 100644 Binary files a/docs/games/Foragers/img/Foragers-level-Block2D-1.png and b/docs/games/Foragers/img/Foragers-level-Block2D-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-0.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-0.png index 543350561..6b346a004 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-0.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-0.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png index 04031561a..e1d8b1a94 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-2.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-2.png index f191f3c35..b6fe50b46 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-2.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-2.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-3.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-3.png new file mode 100644 index 000000000..57770c1b8 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-3.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-0.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-0.png index 326c0dffd..df9a75136 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-0.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-0.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-1.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-1.png index 258515942..04971bc3b 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-1.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-2.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-2.png index 4acb8f756..8199a4568 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-2.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-2.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-3.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-3.png new file mode 100644 index 000000000..cf1a023c2 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Isometric-3.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-0.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-0.png index d33f360f9..2bafc42fa 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-0.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-0.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-1.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-1.png index 2d0f010cc..36e45f02e 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-1.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-2.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-2.png index 0b8fe81bc..a80797ab2 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-2.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-2.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-3.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-3.png new file mode 100644 index 000000000..e74fba634 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Sprite2D-3.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-0.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-0.png index 674000fdb..b6de172d8 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-0.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-0.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-1.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-1.png index d9c0a2c85..9da20c9b4 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-1.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-2.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-2.png index abd891300..d74317d5c 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-2.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-2.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-3.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-3.png new file mode 100644 index 000000000..18254137f Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Vector-3.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Block2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Block2D.png new file mode 100644 index 000000000..d1dffcb3d Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Block2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Isometric.png new file mode 100644 index 000000000..3e1f2788b Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Isometric.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Sprite2D.png new file mode 100644 index 000000000..55dcd3188 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Sprite2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Vector.png new file mode 100644 index 000000000..0dea1ddca Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Block2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Block2D.png new file mode 100644 index 000000000..c74bc2db8 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Block2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Isometric.png new file mode 100644 index 000000000..b16dd2c49 Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Isometric.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Sprite2D.png new file mode 100644 index 000000000..bf52ae1ec Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Sprite2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Vector.png new file mode 100644 index 000000000..0dea1ddca Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-barracks_disabled-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Isometric.png index 5e41fe194..b38fad7ff 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Isometric.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Isometric.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Vector.png index 40f1980b9..0dea1ddca 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Vector.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-base-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Block2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Block2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Block2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Block2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Isometric.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Isometric.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Isometric.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Sprite2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Sprite2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Vector.png new file mode 100644 index 000000000..0dea1ddca Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-combat-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-fixed_wall-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-fixed_wall-Vector.png index ebe2993c5..50a43e1f7 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-fixed_wall-Vector.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-fixed_wall-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Vector.png deleted file mode 100644 index 40f1980b9..000000000 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Vector.png and /dev/null differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Isometric.png index 2b4841cec..b080c5097 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Isometric.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Isometric.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Vector.png index 5f7dd9cd6..5137506e1 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Vector.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-minerals-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-movable_wall-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-movable_wall-Vector.png index 81269459b..e7623ec6f 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-movable_wall-Vector.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-movable_wall-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Vector.png deleted file mode 100644 index 40f1980b9..000000000 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Vector.png and /dev/null differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Vector.png deleted file mode 100644 index 40f1980b9..000000000 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Vector.png and /dev/null differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Block2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Block2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Block2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Block2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Isometric.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Isometric.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Isometric.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Sprite2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Sprite2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Vector.png new file mode 100644 index 000000000..0dea1ddca Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-ranged-Vector.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Block2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Block2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Block2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Block2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Isometric.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Isometric.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Isometric.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Isometric.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Sprite2D.png similarity index 100% rename from docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png rename to docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Sprite2D.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Vector.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Vector.png new file mode 100644 index 000000000..0dea1ddca Binary files /dev/null and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-worker-Vector.png differ diff --git a/docs/games/GriddlyRTS/index.rst b/docs/games/GriddlyRTS/index.rst index 50bcf19d1..06c8f4be2 100644 --- a/docs/games/GriddlyRTS/index.rst +++ b/docs/games/GriddlyRTS/index.rst @@ -28,7 +28,7 @@ Levels * - Level ID - 0 * - Size - - 30x30 + - 16x16 - .. thumbnail:: img/GriddlyRTS-level-Vector-0.png - .. thumbnail:: img/GriddlyRTS-level-Sprite2D-0.png - .. thumbnail:: img/GriddlyRTS-level-Block2D-0.png @@ -48,11 +48,21 @@ Levels * - Level ID - 2 * - Size - - 57x58 + - 30x30 - .. thumbnail:: img/GriddlyRTS-level-Vector-2.png - .. thumbnail:: img/GriddlyRTS-level-Sprite2D-2.png - .. thumbnail:: img/GriddlyRTS-level-Block2D-2.png - .. thumbnail:: img/GriddlyRTS-level-Isometric-2.png + * - .. list-table:: + + * - Level ID + - 3 + * - Size + - 57x58 + - .. thumbnail:: img/GriddlyRTS-level-Vector-3.png + - .. thumbnail:: img/GriddlyRTS-level-Sprite2D-3.png + - .. thumbnail:: img/GriddlyRTS-level-Block2D-3.png + - .. thumbnail:: img/GriddlyRTS-level-Isometric-3.png Code Example ------------ @@ -92,59 +102,71 @@ Objects * - Name -> - minerals - - harvester - - pusher - - puncher + - worker + - ranged + - combat - fixed_wall - movable_wall - base + - barracks_disabled + - barracks * - Map Char -> - `M` - `H` - - `P` - - `p` + - `r` + - `c` - `W` - `w` + - `A` + - `b` - `B` * - Vector - .. image:: img/GriddlyRTS-tile-minerals-Vector.png - - .. image:: img/GriddlyRTS-tile-harvester-Vector.png - - .. image:: img/GriddlyRTS-tile-pusher-Vector.png - - .. image:: img/GriddlyRTS-tile-puncher-Vector.png + - .. image:: img/GriddlyRTS-tile-worker-Vector.png + - .. image:: img/GriddlyRTS-tile-ranged-Vector.png + - .. image:: img/GriddlyRTS-tile-combat-Vector.png - .. image:: img/GriddlyRTS-tile-fixed_wall-Vector.png - .. image:: img/GriddlyRTS-tile-movable_wall-Vector.png - .. image:: img/GriddlyRTS-tile-base-Vector.png + - .. image:: img/GriddlyRTS-tile-barracks_disabled-Vector.png + - .. image:: img/GriddlyRTS-tile-barracks-Vector.png * - Sprite2D - .. image:: img/GriddlyRTS-tile-minerals-Sprite2D.png - - .. image:: img/GriddlyRTS-tile-harvester-Sprite2D.png - - .. image:: img/GriddlyRTS-tile-pusher-Sprite2D.png - - .. image:: img/GriddlyRTS-tile-puncher-Sprite2D.png + - .. image:: img/GriddlyRTS-tile-worker-Sprite2D.png + - .. image:: img/GriddlyRTS-tile-ranged-Sprite2D.png + - .. image:: img/GriddlyRTS-tile-combat-Sprite2D.png - .. image:: img/GriddlyRTS-tile-fixed_wall-Sprite2D.png - .. image:: img/GriddlyRTS-tile-movable_wall-Sprite2D.png - .. image:: img/GriddlyRTS-tile-base-Sprite2D.png + - .. image:: img/GriddlyRTS-tile-barracks_disabled-Sprite2D.png + - .. image:: img/GriddlyRTS-tile-barracks-Sprite2D.png * - Block2D - .. image:: img/GriddlyRTS-tile-minerals-Block2D.png - - .. image:: img/GriddlyRTS-tile-harvester-Block2D.png - - .. image:: img/GriddlyRTS-tile-pusher-Block2D.png - - .. image:: img/GriddlyRTS-tile-puncher-Block2D.png + - .. image:: img/GriddlyRTS-tile-worker-Block2D.png + - .. image:: img/GriddlyRTS-tile-ranged-Block2D.png + - .. image:: img/GriddlyRTS-tile-combat-Block2D.png - .. image:: img/GriddlyRTS-tile-fixed_wall-Block2D.png - .. image:: img/GriddlyRTS-tile-movable_wall-Block2D.png - .. image:: img/GriddlyRTS-tile-base-Block2D.png + - .. image:: img/GriddlyRTS-tile-barracks_disabled-Block2D.png + - .. image:: img/GriddlyRTS-tile-barracks-Block2D.png * - Isometric - .. image:: img/GriddlyRTS-tile-minerals-Isometric.png - - .. image:: img/GriddlyRTS-tile-harvester-Isometric.png - - .. image:: img/GriddlyRTS-tile-pusher-Isometric.png - - .. image:: img/GriddlyRTS-tile-puncher-Isometric.png + - .. image:: img/GriddlyRTS-tile-worker-Isometric.png + - .. image:: img/GriddlyRTS-tile-ranged-Isometric.png + - .. image:: img/GriddlyRTS-tile-combat-Isometric.png - .. image:: img/GriddlyRTS-tile-fixed_wall-Isometric.png - .. image:: img/GriddlyRTS-tile-movable_wall-Isometric.png - .. image:: img/GriddlyRTS-tile-base-Isometric.png + - .. image:: img/GriddlyRTS-tile-barracks_disabled-Isometric.png + - .. image:: img/GriddlyRTS-tile-barracks-Isometric.png Actions ------- -gather -^^^^^^ +build_barracks +^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 @@ -179,8 +201,8 @@ move - Down -spawn_harvester -^^^^^^^^^^^^^^^ +spawn_combat +^^^^^^^^^^^^ :Internal: This action can only be called from other actions, not by the player. @@ -199,8 +221,8 @@ spawn_harvester - Down -punch -^^^^^ +attack +^^^^^^ .. list-table:: :header-rows: 1 @@ -217,8 +239,10 @@ punch - Down -build_harvester -^^^^^^^^^^^^^^^ +spawn_worker +^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. .. list-table:: :header-rows: 1 @@ -235,6 +259,62 @@ build_harvester - Down +construct_barracks +^^^^^^^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Completes construction of a barracks + + +build_combat +^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Build + + +gather +^^^^^^ + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Left + * - 2 + - Up + * - 3 + - Right + * - 4 + - Down + + +build_worker +^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Build + + YAML ---- @@ -249,7 +329,7 @@ YAML TileSize: 16 BackgroundTile: oryx/oryx_tiny_galaxy/tg_sliced/tg_world/tg_world_floor_panel_metal_a.png Isometric: - TileSize: [32, 48] + TileSize: [ 32, 48 ] BackgroundTile: oryx/oryx_iso_dungeon/floor-1.png IsoTileHeight: 16 IsoTileDepth: 4 @@ -264,102 +344,120 @@ YAML Count: 2 Termination: Lose: - - eq: [base:count, 0] # If the player has no bases - Win: - - eq: [_score, 10] # First player to 10 reward points + - Conditions: + - eq: [ base:count, 0 ] # If the player has no bases + Reward: -10 # -10 for a loss + OpposingReward: 10 # as the agent didnt lose Levels: - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W - W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W - W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W - W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . M M M M . . . . . . . . . . W - W . . . . . . . . . . . . . . M M M M M M . . . . . . . . W - W . . . . . . . . . . . . . M . . M . M M . . . . . . . . W - W . . . . . . . . . . . . . M M M M M M M . . . . . . . . W - W . . . . . . . . . . . . . . . M M M M . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W - W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W + M M . . . . . . . . . . . . . . + M M . . . . . . . . . . . . . . + . . A1 H1 . . . . . . . . . . . . + . . H1 . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . H2 . . + . . . . . . . . . . . . H2 A2 . . + . . . . . . . . . . . . . . M M + . . . . . . . . . . . . . . M M + - | + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W + W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W + W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W + W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . M M M M . . . . . . . . . . W + W . . . . . . . . . . . . . . M M M M M M . . . . . . . . W + W . . . . . . . . . . . . . M . . M . M M . . . . . . . . W + W . . . . . . . . . . . . . M M M M M M M . . . . . . . . W + W . . . . . . . . . . . . . . . M M M M . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W + W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W - W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W - W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W - W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W W W W W W W W W . . . . . . . . . . . . . . W W W W W w W - W . . . . . . W W . . . w w w w w w . . . . . W W W W W w W - W . . . . . . . . . . . . . w w . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . M M M M . . . . W W W W W w W - W . . . . P1 w . . . . . . . . M M M M M M . W W W W W W W W - W . . . . P1 w . . . . . . . M . . M . M M . . . . . . . . W - W . . . . P2 w . . . . . . . M M M M M M M . . . . . . . . W - W . . . . P2 w . . . . . . . . . M M M M . . . . . . . . . W - W . . . . P1 w . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W - W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W + W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W + W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W + W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W W W W W W W W W . . . . . . . . . . . . . . W W W W W w W + W . . . . . . W W . . . w w w w w w . . . . . W W W W W w W + W . . . . . . . . . . . . . w w . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . M M M M . . . . W W W W W w W + W . . . . . w . . . . . . . . M M M M M M . W W W W W W W W + W . . . . . w . . . . . . . M . . M . M M . . . . . . . . W + W . . . . . w . . . . . . . M M M M M M M . . . . . . . . W + W . . . . . w . . . . . . . . . M M M M . . . . . . . . . W + W . . . . . w . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W + W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . . . M M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . M M M M W - W . . . . . M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . M M W - W . . . . . . M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . H2 . . M W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . B2 H2 . M W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W W W w w W W W W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W W W . . W W W W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W W W W W W W W W W W W W w w w w w w w w w w w w w W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M M . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M M M . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . . . W - W W W W W W W W W W W . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . W W W W W W W W W W W + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . . . M M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . M M M M W + W . . . . . M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . M M W + W . . . . . . M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . H2 . . M W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . B2 H2 . M W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W W W w w W W W W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W W W . . W W W W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W W W W W W W W W W W W W w w w w w w w w w w w w w W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M M . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M M M . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . . . W + W W W W W W W W W W W . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . W W W W W W W W W W W W . . . . . . . . . . . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . . . . . . . . M M M W W . . . . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . M M W W . . . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . M W @@ -391,48 +489,138 @@ YAML W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W Actions: - - Name: spawn_harvester + - Name: spawn_worker InputMapping: Internal: true Behaviours: - Src: Object: base Commands: - - spawn: harvester + - spawn: worker + - set: [ is_busy, 0 ] Dst: Object: _empty - - Src: Object: base Dst: - Object: [base, puncher, harvester, pusher, movable_wall] + Object: [ base, barracks, combat, worker, ranged, movable_wall ] Commands: + # Try to spawn in another location on the next tick - exec: - Action: spawn_harvester + Action: spawn_worker + Delay: 1 + Randomize: true + - Name: spawn_combat + InputMapping: + Internal: true + Behaviours: + - Src: + Object: barracks + Commands: + - spawn: combat + - set: [ is_busy, 0 ] + Dst: + Object: _empty + + - Src: + Object: barracks + Dst: + Object: [ base, barracks, combat, worker, ranged, movable_wall ] + Commands: + # Try to spawn in another location on the next tick + - exec: + Action: spawn_combat Delay: 1 Randomize: true - # Harvester costs 5 resources to build - - Name: build_harvester + - Name: construct_barracks + InputMapping: + Inputs: + 1: + Description: Completes construction of a barracks + VectorToDest: [ 0, 0 ] + Internal: true + Behaviours: + - Src: + Object: barracks_disabled + Commands: + - set: [ is_busy, 0 ] + - change_to: barracks + Dst: + Object: barracks_disabled + + # worker costs 5 resources to build, get a reward when a worker is built + - Name: build_worker + InputMapping: + Inputs: + 1: + Description: Build + VectorToDest: [ 0, 0 ] Behaviours: - Src: - Preconditions: - - gt: [player_resources, 5] Object: base + Preconditions: + - gte: [ player_resources, 5 ] + - eq: [ is_busy, 0 ] + Commands: + - set: [ is_busy, 1 ] + - sub: [ player_resources, 5 ] + - reward: 1 + # Queue a build which will take 10 seconds + - exec: + Action: spawn_worker + Delay: 10 + Randomize: true + Executor: action Dst: Object: base + + - Name: build_combat + InputMapping: + Inputs: + 1: + Description: Build + VectorToDest: [ 0, 0 ] + Behaviours: + - Src: + Object: barracks + Preconditions: + - gte: [ player_resources, 5 ] + - eq: [ is_busy, 0 ] Commands: + - set: [ is_busy, 1 ] + - sub: [ player_resources, 5 ] + - reward: 1 - exec: - Action: spawn_harvester + Action: spawn_combat Delay: 10 Randomize: true - - + Executor: action + Dst: + Object: barracks + + - Name: build_barracks + Behaviours: + - Src: + Object: worker + Preconditions: + - gte: [ player_resources, 20 ] + - eq: [ is_busy, 0 ] + Commands: + - sub: [ player_resources, 20 ] + - reward: 1 + - spawn: barracks_disabled + Dst: + Object: _empty + - Name: gather Behaviours: - Src: - Object: harvester + Object: worker + Preconditions: + - lt: [ resources, 5 ] + - eq: [ is_busy, 0 ] Commands: - incr: resources - reward: 1 @@ -440,12 +628,24 @@ YAML Object: minerals Commands: - decr: resources + - lt: + Arguments: [resources, 10] + Commands: + - set_tile: 1 + - lt: + Arguments: [ resources, 5 ] + Commands: + - set_tile: 2 - eq: - Arguments: [resources, 0] + Arguments: [ resources, 0 ] Commands: - remove: true - Src: - Object: harvester + Object: worker + Preconditions: + - eq: [ is_busy, 0 ] + - gt: [ resources, 0 ] + - eq: [ src._playerId, dst._playerId ] Commands: - decr: resources - reward: 1 @@ -457,33 +657,56 @@ YAML - Name: move Behaviours: - Src: - Object: [harvester, puncher, pusher, movable_wall] + Preconditions: + - eq: [ is_busy, 0 ] + Object: [ worker, combat, ranged ] Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: Object: _empty - Src: - Object: pusher + Object: ranged Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: - Object: [movable_wall, harvester, puncher] + Object: [ movable_wall, worker, combat ] Commands: - cascade: _dest # reapply the same action to the dest location of the action - - Name: punch + # Name: ranged_attack + - Name: attack Behaviours: + - Src: - Object: puncher + Object: worker + Preconditions: + - neq: [ src._playerId, dst._playerId ] + - eq: [ is_busy, 0 ] Commands: - reward: 1 Dst: - Object: [puncher, harvester, pusher, base] + Object: [ base, combat, worker, ranged ] Commands: - - decr: health + - sub: [ health, 1 ] - eq: - Arguments: [0, health] + Arguments: [ health, 0 ] + Commands: + - remove: true + + - Src: + Object: combat + Preconditions: + - neq: [ src._playerId, dst._playerId ] + - eq: [ is_busy, 0 ] + Commands: + - reward: 1 + Dst: + Object: [ base, combat, worker, ranged, barracks ] + Commands: + - sub: [ health, 5 ] + - eq: + Arguments: [ 0, health ] Commands: - remove: true @@ -492,59 +715,67 @@ YAML MapCharacter: M Variables: - Name: resources - InitialValue: 200 + InitialValue: 20 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_items/tg_items_crystal_green.png Block2D: - Shape: triangle - Color: [0.0, 1.0, 0.0] + Color: [ 0.0, 1.0, 0.0 ] Scale: 1.0 Isometric: - - Image: oryx/oryx_iso_dungeon/minerals-1.png + - Image: oryx/oryx_iso_dungeon/minerals-1-0.png + - Image: oryx/oryx_iso_dungeon/minerals-1-1.png + - Image: oryx/oryx_iso_dungeon/minerals-1-2.png - - Name: harvester + - Name: worker MapCharacter: H Variables: - Name: resources InitialValue: 0 - Name: health InitialValue: 10 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_jelly_d1.png Block2D: - Shape: square - Color: [0.6, 0.2, 0.2] + Color: [ 0.6, 0.2, 0.2 ] Scale: 0.5 Isometric: - Image: oryx/oryx_iso_dungeon/jelly-1.png - - Name: pusher - MapCharacter: P + - Name: ranged + MapCharacter: r Variables: - Name: health - InitialValue: 10 + InitialValue: 20 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_crawler_queen_d1.png Block2D: - Shape: square - Color: [0.2, 0.2, 0.6] + Color: [ 0.2, 0.2, 0.6 ] Scale: 1.0 Isometric: - Image: oryx/oryx_iso_dungeon/queen-1.png - - Name: puncher - MapCharacter: p + - Name: combat + MapCharacter: c Variables: - Name: health - InitialValue: 5 + InitialValue: 30 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_beast_d1.png Block2D: - - Color: [0.2, 0.6, 0.6] + - Color: [ 0.2, 0.6, 0.6 ] Shape: square Scale: 0.8 Isometric: @@ -559,7 +790,7 @@ YAML - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img33.png - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img40.png Block2D: - - Color: [0.5, 0.5, 0.5] + - Color: [ 0.5, 0.5, 0.5 ] Shape: square Isometric: - Image: oryx/oryx_iso_dungeon/wall-grey-1.png @@ -570,23 +801,61 @@ YAML Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img282.png Block2D: - - Color: [0.8, 0.8, 0.8] + - Color: [ 0.8, 0.8, 0.8 ] Shape: square Isometric: - Image: oryx/oryx_iso_dungeon/crate-1.png - Name: base - MapCharacter: B + MapCharacter: A Variables: - Name: health - InitialValue: 10 + InitialValue: 50 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img324.png Block2D: - - Color: [0.8, 0.8, 0.3] + - Color: [ 0.8, 0.8, 0.3 ] Shape: triangle Isometric: - Image: oryx/oryx_iso_dungeon/base-1.png + - Name: barracks_disabled + MapCharacter: b + InitialActions: + - Action: construct_barracks + Delay: 20 + Variables: + - Name: health + InitialValue: 20 + - Name: is_busy + InitialValue: 1 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img280.png + Block2D: + - Color: [ 0.3, 0.3, 0.3 ] + Shape: triangle + Size: 0.5 + Isometric: + - Image: oryx/oryx_iso_dungeon/barracks-disabled-1.png + + - Name: barracks + MapCharacter: B + Variables: + - Name: health + InitialValue: 40 + - Name: is_busy + InitialValue: 0 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img320.png + Block2D: + - Color: [ 0.8, 0.3, 0.8 ] + Shape: triangle + Isometric: + - Image: oryx/oryx_iso_dungeon/barracks-1.png + diff --git a/docs/games/Heal_Or_Die/img/Heal_Or_Die-level-Block2D-1.png b/docs/games/Heal_Or_Die/img/Heal_Or_Die-level-Block2D-1.png index a0a6b2686..bb8de1c9a 100644 Binary files a/docs/games/Heal_Or_Die/img/Heal_Or_Die-level-Block2D-1.png and b/docs/games/Heal_Or_Die/img/Heal_Or_Die-level-Block2D-1.png differ diff --git a/docs/games/Labyrinth/img/Labyrinth-level-Block2D-1.png b/docs/games/Labyrinth/img/Labyrinth-level-Block2D-1.png index b30b59e8f..3e24d7b29 100644 Binary files a/docs/games/Labyrinth/img/Labyrinth-level-Block2D-1.png and b/docs/games/Labyrinth/img/Labyrinth-level-Block2D-1.png differ diff --git a/docs/games/Labyrinth/img/Labyrinth-level-Block2D-3.png b/docs/games/Labyrinth/img/Labyrinth-level-Block2D-3.png index d0cc64aff..3e24d7b29 100644 Binary files a/docs/games/Labyrinth/img/Labyrinth-level-Block2D-3.png and b/docs/games/Labyrinth/img/Labyrinth-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-1.png b/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-1.png index 9dfa12cf3..54890ef95 100644 Binary files a/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-1.png and b/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-3.png b/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-3.png index d3bab6e32..fb6610be2 100644 Binary files a/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-3.png and b/docs/games/Partially_Observable_Bait/img/Partially_Observable_Bait-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-1.png b/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-1.png index b2af26802..19d7c2150 100644 Binary files a/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-1.png and b/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-3.png b/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-3.png index c54c511f7..19d7c2150 100644 Binary files a/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-3.png and b/docs/games/Partially_Observable_Clusters/img/Partially_Observable_Clusters-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-1.png b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-1.png index 701ee2ae2..14ad67145 100644 Binary files a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-1.png and b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-3.png b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-3.png index 39e7dacb8..14ad67145 100644 Binary files a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-3.png and b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-5.png b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-5.png index 0e0d8881a..14ad67145 100644 Binary files a/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-5.png and b/docs/games/Partially_Observable_Cook_Me_Pasta/img/Partially_Observable_Cook_Me_Pasta-level-Block2D-5.png differ diff --git a/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-1.png b/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-1.png index b30b59e8f..3e24d7b29 100644 Binary files a/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-1.png and b/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-3.png b/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-3.png index d0cc64aff..3e24d7b29 100644 Binary files a/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-3.png and b/docs/games/Partially_Observable_Labyrinth/img/Partially_Observable_Labyrinth-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-1.png b/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-1.png index fef97ca21..6abfd74ba 100644 Binary files a/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-1.png and b/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-3.png b/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-3.png index da519cf4c..78ba6ee1b 100644 Binary files a/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-3.png and b/docs/games/Partially_Observable_Sokoban_-_2/img/Partially_Observable_Sokoban_-_2-level-Block2D-3.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png index 0e0d2779e..4031e6ef3 100644 Binary files a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-1.png b/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-1.png index d1ec79f17..72c16bc32 100644 Binary files a/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-1.png and b/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-3.png b/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-3.png index de5859725..cf8d2d9f1 100644 Binary files a/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-3.png and b/docs/games/Partially_Observable_Zen_Puzzle/img/Partially_Observable_Zen_Puzzle-level-Block2D-3.png differ diff --git a/docs/games/Push_Mania/img/Push_Mania-level-Block2D-1.png b/docs/games/Push_Mania/img/Push_Mania-level-Block2D-1.png index 32571325f..395c7a354 100644 Binary files a/docs/games/Push_Mania/img/Push_Mania-level-Block2D-1.png and b/docs/games/Push_Mania/img/Push_Mania-level-Block2D-1.png differ diff --git a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-1.png b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-1.png index 74920bd79..279576afa 100644 Binary files a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-1.png and b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-1.png differ diff --git a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-3.png b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-3.png index 6102a454c..279576afa 100644 Binary files a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-3.png and b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-3.png differ diff --git a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-5.png b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-5.png index e9af362f6..279576afa 100644 Binary files a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-5.png and b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-5.png differ diff --git a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-7.png b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-7.png index 0fb0fe63f..279576afa 100644 Binary files a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-7.png and b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-7.png differ diff --git a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-9.png b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-9.png index 642970ea8..d44d37c81 100644 Binary files a/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-9.png and b/docs/games/Random_butterflies/img/Random_butterflies-level-Block2D-9.png differ diff --git a/docs/games/Random_butterflies/index.rst b/docs/games/Random_butterflies/index.rst index 8f2d91b12..df9805414 100644 --- a/docs/games/Random_butterflies/index.rst +++ b/docs/games/Random_butterflies/index.rst @@ -530,7 +530,7 @@ YAML Object: butterfly Commands: - remove: true - - reward: -1 + # if the spider moves into the catcher it dies - Src: Object: spider diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-0.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-0.png index be9331bfe..41745cc8c 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-0.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-0.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-1.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-1.png index 23b60e96e..1a15d7130 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-1.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-1.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-2.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-2.png index 79c6bd329..3679fbb49 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-2.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-2.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-3.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-3.png index 8b5dbd30c..68ea3825a 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-3.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Block2D-3.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-0.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-0.png index 458f4e078..dab6f0806 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-0.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-0.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-1.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-1.png index e8292f96c..e43b91a99 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-1.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-1.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-2.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-2.png index 44c3393d3..4e16ca6fe 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-2.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-2.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-3.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-3.png index 73d55deda..fa3426c08 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-3.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Sprite2D-3.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-0.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-0.png index 8f61177e0..4defc15fb 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-0.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-0.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-1.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-1.png index d2bbfe5a7..84997a7a0 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-1.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-1.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-2.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-2.png index a615e574f..f6405ed4c 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-2.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-2.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-3.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-3.png index f8d23fb2d..87c50c37e 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-3.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-level-Vector-3.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-fixed_wall-Vector.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-fixed_wall-Vector.png index 0aa5dff5a..fcb8b23fd 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-fixed_wall-Vector.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-fixed_wall-Vector.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-moveable_wall-Vector.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-moveable_wall-Vector.png index 3220f5d4c..29635546f 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-moveable_wall-Vector.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-moveable_wall-Vector.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Block2D.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Block2D.png index 3fe75e180..13f54c88d 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Block2D.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Block2D.png differ diff --git a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Vector.png b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Vector.png index dc863080f..e3112deb3 100644 Binary files a/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Vector.png and b/docs/games/Robot_Tag_12v12/img/Robot_Tag_12v12-tile-tagger-Vector.png differ diff --git a/docs/games/Robot_Tag_12v12/index.rst b/docs/games/Robot_Tag_12v12/index.rst index 10839d340..4eda8824a 100644 --- a/docs/games/Robot_Tag_12v12/index.rst +++ b/docs/games/Robot_Tag_12v12/index.rst @@ -5,7 +5,7 @@ Robot Tag 12v12 .. code-block:: - Multi-Agent/robot_tag_8.yaml + Multi-Agent/robot_tag_12.yaml Description ------------- @@ -195,7 +195,7 @@ YAML - Name: tagged_count InitialValue: 0 Player: - Count: 8 + Count: 12 Observer: RotateWithAvatar: true TrackAvatar: true @@ -211,20 +211,20 @@ YAML Levels: - | W W W W W W W W W - W . . f2 . f3 . . W + W . . f2 . f12 . . W W . . . . . . . W - W f1 . . . . . f4 W + W f1 . f3 . f10 . f11 W W . . . . . . . W W . . . . . . . W - W f8 . . . . . f5 W + W f4 . f5 . f7 . f8 W W . . . . . . . W - W . . f7 . f6 . . W + W . . f6 . f9 . . W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W . . . . . . . . . . . . . . . . . . . . W - W . . f2 . . . . . . . . . . . . . . f3 . . W - W . f1 . . . . . . . . . . . . . . . . f4 . W + W . . f2 . . . . . . . . . . . . . . f12 . . W + W . f1 f3 . . . . . . . . . . . . . . f10 f11 . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . W W W W W W . . . . . . . W @@ -239,15 +239,15 @@ YAML W . . . . . . . W W W W W W . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W - W . f8 . . . . . . . . . . . . . . . . f5 . W - W . . f7 . . . . . . . . . . . . . . f6 . . W + W . f4 f5 . . . . . . . . . . . . . . f7 f8 . W + W . . f6 . . . . . . . . . . . . . . f9 . . W W . . . . . . . . . . . . . . . . . . . . W W W W W W W W W W W W W W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W . . . . m . . . . . . . . . . m . . . . W - W . . f2 . m . . . . . . . . . . m . f3 . . W - W . f1 . . m . . . . . . . . . . m . . f4 . W + W . . f2 . m . . . . . . . . . . m . f12 . . W + W . f1 f3 . m . . . . . . . . . . m . f10 f11 . W W . . . . m . . . . . . . . . . m . . . . W W . . . . m . . . . . . . . . . m . . . . W W m m m m m . . W W W W W W . . m m m m m W @@ -262,19 +262,19 @@ YAML W m m m m m . . W W W W W W . . m m m m m W W . . . . m . . . . . . . . . . m . . . . W W . . . . m . . . . . . . . . . m . . . . W - W . f8 . . m . . . . . . . . . . m . . f5 . W - W . . f7 . m . . . . . . . . . . m . f6 . . W + W . f4 f5 . m . . . . . . . . . . m . f7 f8 . W + W . . f6 . m . . . . . . . . . . m . f9 . . W W . . . . m . . . . . . . . . . m . . . . W W W W W W W W W W W W W W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W - W . . . . m f2 . . . . m . . m . . . . . . . . . . m . . m . . . . f3 m . . . . W - W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W + W . . . . m f2 . . . . m . . m . . . . . . . . . . m . . m . . . . f12 m . . . . W + W . . f3 . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . f10 . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W m m m m m . . . . . m . . m . . W W W W W W . . m . . m . . . . . m m m m m W - W . f1 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f4 . W + W . f1 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f11 . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W @@ -305,12 +305,12 @@ YAML W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W - W . f8 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f5 . W + W . f4 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f8 . W W m m m m m . . . . . m . . m . . W W W W W W . . m . . m . . . . . m m m m m W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W - W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W - W . . . . m f7 . . . . m . . m . . . . . . . . . . m . . m . . . . f6 m . . . . W + W . . f5 . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . f7 . . W + W . . . . m f6 . . . . m . . m . . . . . . . . . . m . . m . . . . f9 m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W @@ -369,7 +369,7 @@ YAML - Name: move Behaviours: - Src: - Object: [tagger, moveable_wall] + Object: [ tagger, moveable_wall ] Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: diff --git a/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-1.png b/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-1.png index 2f9466409..1a15d7130 100644 Binary files a/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-1.png and b/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-1.png differ diff --git a/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-3.png b/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-3.png index d3f4b76f5..68ea3825a 100644 Binary files a/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-3.png and b/docs/games/Robot_Tag_4v4/img/Robot_Tag_4v4-level-Block2D-3.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-0.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-0.png index 41745cc8c..be9331bfe 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-0.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-0.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-1.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-1.png index 6d711a411..1a15d7130 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-1.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-1.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-2.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-2.png index 3679fbb49..79c6bd329 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-2.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-2.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-3.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-3.png index 3affb5789..68ea3825a 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-3.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Block2D-3.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-0.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-0.png index dab6f0806..458f4e078 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-0.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-0.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-1.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-1.png index e43b91a99..e8292f96c 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-1.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-1.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-2.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-2.png index 4e16ca6fe..44c3393d3 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-2.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-2.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-3.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-3.png index fa3426c08..73d55deda 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-3.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Sprite2D-3.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-0.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-0.png index 4defc15fb..8f61177e0 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-0.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-0.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-1.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-1.png index 84997a7a0..d2bbfe5a7 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-1.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-1.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-2.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-2.png index f6405ed4c..a615e574f 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-2.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-2.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-3.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-3.png index 87c50c37e..f8d23fb2d 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-3.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-level-Vector-3.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-fixed_wall-Vector.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-fixed_wall-Vector.png index fcb8b23fd..0aa5dff5a 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-fixed_wall-Vector.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-fixed_wall-Vector.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-moveable_wall-Vector.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-moveable_wall-Vector.png index 29635546f..3220f5d4c 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-moveable_wall-Vector.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-moveable_wall-Vector.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Block2D.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Block2D.png index 13f54c88d..3fe75e180 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Block2D.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Block2D.png differ diff --git a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Vector.png b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Vector.png index e3112deb3..dc863080f 100644 Binary files a/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Vector.png and b/docs/games/Robot_Tag_8v8/img/Robot_Tag_8v8-tile-tagger-Vector.png differ diff --git a/docs/games/Robot_Tag_8v8/index.rst b/docs/games/Robot_Tag_8v8/index.rst index 6350d8873..3f9c048f8 100644 --- a/docs/games/Robot_Tag_8v8/index.rst +++ b/docs/games/Robot_Tag_8v8/index.rst @@ -5,7 +5,7 @@ Robot Tag 8v8 .. code-block:: - Multi-Agent/robot_tag_12.yaml + Multi-Agent/robot_tag_8.yaml Description ------------- @@ -195,7 +195,7 @@ YAML - Name: tagged_count InitialValue: 0 Player: - Count: 12 + Count: 8 Observer: RotateWithAvatar: true TrackAvatar: true @@ -211,20 +211,20 @@ YAML Levels: - | W W W W W W W W W - W . . f2 . f12 . . W + W . . f2 . f3 . . W W . . . . . . . W - W f1 . f3 . f10 . f11 W + W f1 . . . . . f4 W W . . . . . . . W W . . . . . . . W - W f4 . f5 . f7 . f8 W + W f8 . . . . . f5 W W . . . . . . . W - W . . f6 . f9 . . W + W . . f7 . f6 . . W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W . . . . . . . . . . . . . . . . . . . . W - W . . f2 . . . . . . . . . . . . . . f12 . . W - W . f1 f3 . . . . . . . . . . . . . . f10 f11 . W + W . . f2 . . . . . . . . . . . . . . f3 . . W + W . f1 . . . . . . . . . . . . . . . . f4 . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . W W W W W W . . . . . . . W @@ -239,15 +239,15 @@ YAML W . . . . . . . W W W W W W . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W W . . . . . . . . . . . . . . . . . . . . W - W . f4 f5 . . . . . . . . . . . . . . f7 f8 . W - W . . f6 . . . . . . . . . . . . . . f9 . . W + W . f8 . . . . . . . . . . . . . . . . f5 . W + W . . f7 . . . . . . . . . . . . . . f6 . . W W . . . . . . . . . . . . . . . . . . . . W W W W W W W W W W W W W W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W . . . . m . . . . . . . . . . m . . . . W - W . . f2 . m . . . . . . . . . . m . f12 . . W - W . f1 f3 . m . . . . . . . . . . m . f10 f11 . W + W . . f2 . m . . . . . . . . . . m . f3 . . W + W . f1 . . m . . . . . . . . . . m . . f4 . W W . . . . m . . . . . . . . . . m . . . . W W . . . . m . . . . . . . . . . m . . . . W W m m m m m . . W W W W W W . . m m m m m W @@ -262,19 +262,19 @@ YAML W m m m m m . . W W W W W W . . m m m m m W W . . . . m . . . . . . . . . . m . . . . W W . . . . m . . . . . . . . . . m . . . . W - W . f4 f5 . m . . . . . . . . . . m . f7 f8 . W - W . . f6 . m . . . . . . . . . . m . f9 . . W + W . f8 . . m . . . . . . . . . . m . . f5 . W + W . . f7 . m . . . . . . . . . . m . f6 . . W W . . . . m . . . . . . . . . . m . . . . W W W W W W W W W W W W W W W W W W W W W W W - | W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W - W . . . . m f2 . . . . m . . m . . . . . . . . . . m . . m . . . . f12 m . . . . W - W . . f3 . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . f10 . . W + W . . . . m f2 . . . . m . . m . . . . . . . . . . m . . m . . . . f3 m . . . . W + W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W m m m m m . . . . . m . . m . . W W W W W W . . m . . m . . . . . m m m m m W - W . f1 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f11 . W + W . f1 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f4 . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W @@ -305,12 +305,12 @@ YAML W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W W . . . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . . . W - W . f4 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f8 . W + W . f8 . . . . . . . . m . . m . . . . . . . . . . m . . m . . . . . . . . f5 . W W m m m m m . . . . . m . . m . . W W W W W W . . m . . m . . . . . m m m m m W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W - W . . f5 . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . f7 . . W - W . . . . m f6 . . . . m . . m . . . . . . . . . . m . . m . . . . f9 m . . . . W + W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W + W . . . . m f7 . . . . m . . m . . . . . . . . . . m . . m . . . . f6 m . . . . W W . . . . m . . . . . m . . m . . . . . . . . . . m . . m . . . . . m . . . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W @@ -369,7 +369,7 @@ YAML - Name: move Behaviours: - Src: - Object: [ tagger, moveable_wall ] + Object: [tagger, moveable_wall] Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: diff --git a/docs/games/Sokoban/img/Sokoban-level-Block2D-1.png b/docs/games/Sokoban/img/Sokoban-level-Block2D-1.png index ca6a16cce..54890ef95 100644 Binary files a/docs/games/Sokoban/img/Sokoban-level-Block2D-1.png and b/docs/games/Sokoban/img/Sokoban-level-Block2D-1.png differ diff --git a/docs/games/Sokoban/img/Sokoban-level-Block2D-3.png b/docs/games/Sokoban/img/Sokoban-level-Block2D-3.png index 64ab267c8..a76a09bd2 100644 Binary files a/docs/games/Sokoban/img/Sokoban-level-Block2D-3.png and b/docs/games/Sokoban/img/Sokoban-level-Block2D-3.png differ diff --git a/docs/games/Sokoban/img/Sokoban-level-Block2D-5.png b/docs/games/Sokoban/img/Sokoban-level-Block2D-5.png index cf20fbb95..4cf627a11 100644 Binary files a/docs/games/Sokoban/img/Sokoban-level-Block2D-5.png and b/docs/games/Sokoban/img/Sokoban-level-Block2D-5.png differ diff --git a/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-1.png b/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-1.png index fef97ca21..6abfd74ba 100644 Binary files a/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-1.png and b/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-1.png differ diff --git a/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-3.png b/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-3.png index da519cf4c..78ba6ee1b 100644 Binary files a/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-3.png and b/docs/games/Sokoban_-_2/img/Sokoban_-_2-level-Block2D-3.png differ diff --git a/docs/games/Spiders/img/Spiders-level-Block2D-1.png b/docs/games/Spiders/img/Spiders-level-Block2D-1.png index 84e076d64..a5bfa50ab 100644 Binary files a/docs/games/Spiders/img/Spiders-level-Block2D-1.png and b/docs/games/Spiders/img/Spiders-level-Block2D-1.png differ diff --git a/docs/games/Spiders/img/Spiders-level-Block2D-3.png b/docs/games/Spiders/img/Spiders-level-Block2D-3.png index bb57cdf9a..49f4e9f67 100644 Binary files a/docs/games/Spiders/img/Spiders-level-Block2D-3.png and b/docs/games/Spiders/img/Spiders-level-Block2D-3.png differ diff --git a/docs/games/Zelda/img/Zelda-level-Block2D-1.png b/docs/games/Zelda/img/Zelda-level-Block2D-1.png index 3ff002988..54890ef95 100644 Binary files a/docs/games/Zelda/img/Zelda-level-Block2D-1.png and b/docs/games/Zelda/img/Zelda-level-Block2D-1.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png index 3ff002988..54890ef95 100644 Binary files a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png differ diff --git a/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-1.png b/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-1.png index d1ec79f17..72c16bc32 100644 Binary files a/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-1.png and b/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-1.png differ diff --git a/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-3.png b/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-3.png index de5859725..cf8d2d9f1 100644 Binary files a/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-3.png and b/docs/games/Zen_Puzzle/img/Zen_Puzzle-level-Block2D-3.png differ diff --git a/docs/games/img/GriddlyRTS-taster.png b/docs/games/img/GriddlyRTS-taster.png index 4acb8f756..cf1a023c2 100644 Binary files a/docs/games/img/GriddlyRTS-taster.png and b/docs/games/img/GriddlyRTS-taster.png differ diff --git a/docs/games/img/Robot_Tag_12v12-taster.png b/docs/games/img/Robot_Tag_12v12-taster.png index 73d55deda..fa3426c08 100644 Binary files a/docs/games/img/Robot_Tag_12v12-taster.png and b/docs/games/img/Robot_Tag_12v12-taster.png differ diff --git a/docs/games/img/Robot_Tag_8v8-taster.png b/docs/games/img/Robot_Tag_8v8-taster.png index fa3426c08..73d55deda 100644 Binary files a/docs/games/img/Robot_Tag_8v8-taster.png and b/docs/games/img/Robot_Tag_8v8-taster.png differ diff --git a/docs/games/index.rst b/docs/games/index.rst index ef8f4875d..da26d16ef 100644 --- a/docs/games/index.rst +++ b/docs/games/index.rst @@ -273,25 +273,25 @@ Multi-Agent .. toctree:: :hidden: - Robot_Tag_8v8/index Robot_Tag_12v12/index + Robot_Tag_8v8/index Foragers/index Robot_Tag_4v4/index .. list-table:: :class: game-gallery - * - **Robot Tag 8v8** + * - **Robot Tag 12v12** - .. image:: img/Robot_Tag_8v8-taster.png - :target: Robot_Tag_8v8/index.html + .. image:: img/Robot_Tag_12v12-taster.png + :target: Robot_Tag_12v12/index.html :width: 200 Robots start randomly as "tagged" or not, robots can "tag" other robots. Any robot that is "tagged" 3 times dies. - - **Robot Tag 12v12** + - **Robot Tag 8v8** - .. image:: img/Robot_Tag_12v12-taster.png - :target: Robot_Tag_12v12/index.html + .. image:: img/Robot_Tag_8v8-taster.png + :target: Robot_Tag_8v8/index.html :width: 200 Robots start randomly as "tagged" or not, robots can "tag" other robots. Any robot that is "tagged" 3 times dies. diff --git a/docs/getting-started/observation spaces/index.rst b/docs/getting-started/observation spaces/index.rst index c2f3802f6..03c0acd50 100644 --- a/docs/getting-started/observation spaces/index.rst +++ b/docs/getting-started/observation spaces/index.rst @@ -226,6 +226,7 @@ A breakdown of the entire environment including internal variable values that th ] } +.. _event_history: ************* Event History diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gt/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gt/index.rst index b17171929..12afd72ba 100644 --- a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gt/index.rst +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gt/index.rst @@ -1,6 +1,6 @@ -.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt: +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt: -.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt Greater Than ============ diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gte/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gte/index.rst new file mode 100644 index 000000000..e33e2f05c --- /dev/null +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/gte/index.rst @@ -0,0 +1,34 @@ +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gte: + +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gte + +Greater Than Or Equal +===================== + +:Description: The specified commands will only be run if the value of the first argument is greater than or equal to the second. + +.. list-table:: + + * - **Data Type** + - **YAML Key** + * - object + - ``gte`` + + +:Properties: + +.. list-table:: + + * - **Property** + - **Required** + * - :ref:`Arguments <#/properties/Actions/items/properties/Behaviours/definitions/commandArgument>` + - + * - :ref:`Commands <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommandList>` + - + + +.. toctree:: + :hidden: + + /reference/GDY/Actions/items/Behaviours/commandArgument/index + /reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommandList/index diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/index.rst index 67acf5c70..89c897441 100644 --- a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/index.rst +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/index.rst @@ -15,9 +15,13 @@ Conditional Behaviour Command - **Required** * - :ref:`eq <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/eq>` - - * - :ref:`lt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt>` + * - :ref:`lt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt>` - - * - :ref:`gt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt>` + * - :ref:`lte <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lte>` + - + * - :ref:`gt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt>` + - + * - :ref:`gte <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gte>` - @@ -26,4 +30,6 @@ Conditional Behaviour Command eq/index lt/index + lte/index gt/index + gte/index diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lt/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lt/index.rst index b3559569f..21f59e255 100644 --- a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lt/index.rst +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lt/index.rst @@ -1,6 +1,6 @@ -.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt: +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt: -.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt Less Than ========= diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lte/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lte/index.rst new file mode 100644 index 000000000..e3acf8980 --- /dev/null +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommand/lte/index.rst @@ -0,0 +1,34 @@ +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lte: + +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lte + +Less Than Or Equal +================== + +:Description: The specified commands will only be run if the value of the first argument is less than or equal to the second. + +.. list-table:: + + * - **Data Type** + - **YAML Key** + * - object + - ``lte`` + + +:Properties: + +.. list-table:: + + * - **Property** + - **Required** + * - :ref:`Arguments <#/properties/Actions/items/properties/Behaviours/definitions/commandArgumentList>` + - + * - :ref:`Commands <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommandList>` + - + + +.. toctree:: + :hidden: + + /reference/GDY/Actions/items/Behaviours/commandArgumentList/index + /reference/GDY/Actions/items/Behaviours/behaviourDefinitionConditionalCommandList/index diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/gte/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/gte/index.rst new file mode 100644 index 000000000..fd95c5aff --- /dev/null +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/gte/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/gte: + +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/gte + +Greater Than Or Equal +===================== + +:Description: Check if the first argument is greater than or equal to the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``gte`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Command Argument<#/properties/Actions/items/properties/Behaviours/definitions/commandArgument>` + - An argument to a behaviour command. + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Actions/items/Behaviours/commandArgument/index diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/index.rst index 2045263e1..ebeb2be84 100644 --- a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/index.rst +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/index.rst @@ -19,8 +19,12 @@ Behaviour Precondition - * - :ref:`gt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/gt>` - + * - :ref:`gte <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/gte>` + - * - :ref:`lt <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lt>` - + * - :ref:`lte <#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lte>` + - .. toctree:: @@ -29,4 +33,6 @@ Behaviour Precondition eq/index neq/index gt/index + gte/index lt/index + lte/index diff --git a/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/lte/index.rst b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/lte/index.rst new file mode 100644 index 000000000..f46235818 --- /dev/null +++ b/docs/reference/GDY/Actions/items/Behaviours/behaviourDefinitionPreconditionCommand/lte/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lte: + +.. #/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lte + +Less Than Or Equal +================== + +:Description: Check if the first argument is less than or equal to the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``lte`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Command Argument<#/properties/Actions/items/properties/Behaviours/definitions/commandArgument>` + - An argument to a behaviour command. + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Actions/items/Behaviours/commandArgument/index diff --git a/docs/reference/GDY/Environment/Termination/End/index.rst b/docs/reference/GDY/Environment/Termination/End/index.rst index 5c1674eee..fefb3c696 100644 --- a/docs/reference/GDY/Environment/Termination/End/index.rst +++ b/docs/reference/GDY/Environment/Termination/End/index.rst @@ -7,26 +7,24 @@ End Conditions :Description: If any of these conditions are met, the game will end. -.. list-table:: +:Possible Values: - * - **Data Type** - - **YAML Key** - * - array - - ``End`` +.. list-table:: + * - **Value** + - **Type** + - **Description** + * - V1 Termination Conditions + - array + - V1 Termination Conditions + * - V2 Termination Conditions + - array + - V2 Termination Conditions -:Array Type: .. list-table:: - * - **Type** - - **Description** - * - :ref:`Termination Conditions<#/properties/Environment/properties/Termination/definitions/terminationCondition>` - - When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score - + * - **YAML Key** + * - ``End`` -.. toctree:: - :maxdepth: 5 - :hidden: - /reference/GDY/Environment/Termination/terminationCondition/index diff --git a/docs/reference/GDY/Environment/Termination/Lose/index.rst b/docs/reference/GDY/Environment/Termination/Lose/index.rst index e574d049e..1865e854e 100644 --- a/docs/reference/GDY/Environment/Termination/Lose/index.rst +++ b/docs/reference/GDY/Environment/Termination/Lose/index.rst @@ -7,26 +7,24 @@ Lose Conditions :Description: If any of these conditions are met, the player associated with this condition will lose the game. -.. list-table:: +:Possible Values: - * - **Data Type** - - **YAML Key** - * - array - - ``Lose`` +.. list-table:: + * - **Value** + - **Type** + - **Description** + * - V1 Termination Conditions + - array + - V1 Termination Conditions + * - V2 Termination Conditions + - array + - V2 Termination Conditions -:Array Type: .. list-table:: - * - **Type** - - **Description** - * - :ref:`Termination Conditions<#/properties/Environment/properties/Termination/definitions/terminationCondition>` - - When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score - + * - **YAML Key** + * - ``Lose`` -.. toctree:: - :maxdepth: 5 - :hidden: - /reference/GDY/Environment/Termination/terminationCondition/index diff --git a/docs/reference/GDY/Environment/Termination/Win/index.rst b/docs/reference/GDY/Environment/Termination/Win/index.rst index 3f3bb33ab..20c4d817e 100644 --- a/docs/reference/GDY/Environment/Termination/Win/index.rst +++ b/docs/reference/GDY/Environment/Termination/Win/index.rst @@ -7,26 +7,24 @@ Win Conditions :Description: If any of these conditions are met, the player associated with this condition will win the game. -.. list-table:: +:Possible Values: - * - **Data Type** - - **YAML Key** - * - array - - ``Win`` +.. list-table:: + * - **Value** + - **Type** + - **Description** + * - V1 Termination Conditions + - array + - V1 Termination Conditions + * - V2 Termination Conditions + - array + - V2 Termination Conditions -:Array Type: .. list-table:: - * - **Type** - - **Description** - * - :ref:`Termination Conditions<#/properties/Environment/properties/Termination/definitions/terminationCondition>` - - When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score - + * - **YAML Key** + * - ``Win`` -.. toctree:: - :maxdepth: 5 - :hidden: - /reference/GDY/Environment/Termination/terminationCondition/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/eq/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/eq/index.rst new file mode 100644 index 000000000..6387fa32b --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/eq/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/eq: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/eq + +Equals +====== + +:Description: Check if the arguments are equal + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``eq`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/gt/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/gt/index.rst new file mode 100644 index 000000000..a217dbe63 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/gt/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gt: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gt + +Greater Than +============ + +:Description: Check if the first argument is greater than the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``gt`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/gte/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/gte/index.rst new file mode 100644 index 000000000..096d539fe --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/gte/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gte: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gte + +Greater Than Or Equal +===================== + +:Description: Check if the first argument is greater than or equal to the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``gte`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/index.rst new file mode 100644 index 000000000..a50367ab7 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/index.rst @@ -0,0 +1,44 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1 + +Termination Conditions V1 +========================= + +:Description: When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score + +.. list-table:: + + * - **Data Type** + * - object + + +:Properties: + +.. list-table:: + + * - **Property** + - **Required** + * - :ref:`eq <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/eq>` + - + * - :ref:`neq <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/neq>` + - + * - :ref:`gt <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gt>` + - + * - :ref:`gte <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gte>` + - + * - :ref:`lt <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lt>` + - + * - :ref:`lte <#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lte>` + - + + +.. toctree:: + :hidden: + + eq/index + neq/index + gt/index + gte/index + lt/index + lte/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/lt/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/lt/index.rst new file mode 100644 index 000000000..b559ba1da --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/lt/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lt: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lt + +Less Than +========= + +:Description: Check if the first argument is less than the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``lt`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/lte/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/lte/index.rst new file mode 100644 index 000000000..89829ca7e --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/lte/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lte: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lte + +Less Than Or Equal +================== + +:Description: Check if the first argument is less than or equal to the second + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``lte`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/neq/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/neq/index.rst new file mode 100644 index 000000000..7f65591c9 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/neq/index.rst @@ -0,0 +1,36 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/neq: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/neq + +Not Equals +========== + +:Description: Check if the arguments are not equal + +.. list-table:: + + * - **Data Type** + - **YAML Key** + - **Max Items** + - **Min Items** + * - array + - ``neq`` + - 2 + - 2 + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Arguments<#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument>` + - An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index.rst new file mode 100644 index 000000000..ff95e6725 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV1/terminationArgument/index.rst @@ -0,0 +1,33 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument + +Termination Arguments +===================== + +:Description: An argument to the termination condition. If there are multiple players, then these arguments expand internally as "per player" + +:Possible Values: + +.. list-table:: + + * - **Value** + - **Type** + - **Description** + * - ``\w+`` + - string + - Any global variable + * - ``\w+:count`` + - string + - Returns the number of objects of the object name before the colon, for example ``flower:count`` or ``car:count`` + * - ``_steps`` + - string + - Returns the number of game ticks that have passed + * - ``_score`` + - string + - The current score + * - ``[integer]`` + - integer + - Any Integer value + + diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV2/Conditions/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV2/Conditions/index.rst new file mode 100644 index 000000000..b10e4bbbd --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV2/Conditions/index.rst @@ -0,0 +1,32 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Conditions: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Conditions + +Conditions +========== + +:Description: If any of these conditions are met, the game will end and distribute rewards to the associated players. + +.. list-table:: + + * - **Data Type** + - **YAML Key** + * - array + - ``Conditions`` + + +:Array Type: + +.. list-table:: + + * - **Type** + - **Description** + * - :ref:`Termination Conditions V1<#/properties/Environment/properties/Termination/definitions/terminationConditionV1>` + - When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score + + +.. toctree:: + :maxdepth: 5 + :hidden: + + /reference/GDY/Environment/Termination/terminationConditionV1/index diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV2/OpposingReward/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV2/OpposingReward/index.rst new file mode 100644 index 000000000..b0ec17c44 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV2/OpposingReward/index.rst @@ -0,0 +1,17 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/OpposingReward: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/OpposingReward + +Opposing Reward +=============== + +:Description: The reward given to other agents if this condition is met. + +.. list-table:: + + * - **Data Type** + - **YAML Key** + * - integer + - ``OpposingReward`` + + diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV2/Reward/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV2/Reward/index.rst new file mode 100644 index 000000000..be0d051d6 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV2/Reward/index.rst @@ -0,0 +1,17 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Reward: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Reward + +Reward +====== + +:Description: The reward given to the agent if this conditions is met. + +.. list-table:: + + * - **Data Type** + - **YAML Key** + * - integer + - ``Reward`` + + diff --git a/docs/reference/GDY/Environment/Termination/terminationConditionV2/index.rst b/docs/reference/GDY/Environment/Termination/terminationConditionV2/index.rst new file mode 100644 index 000000000..aa67e7ef9 --- /dev/null +++ b/docs/reference/GDY/Environment/Termination/terminationConditionV2/index.rst @@ -0,0 +1,35 @@ +.. _#/properties/Environment/properties/Termination/definitions/terminationConditionV2: + +.. #/properties/Environment/properties/Termination/definitions/terminationConditionV2 + +Termination Conditions V2 +========================= + +:Description: When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally "per player". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score + +.. list-table:: + + * - **Data Type** + * - object + + +:Properties: + +.. list-table:: + + * - **Property** + - **Required** + * - :ref:`Conditions <#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Conditions>` + - + * - :ref:`Reward <#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Reward>` + - + * - :ref:`OpposingReward <#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/OpposingReward>` + - + + +.. toctree:: + :hidden: + + Conditions/index + Reward/index + OpposingReward/index diff --git a/docs/rllib/intro/img/agent_info_example.png b/docs/rllib/intro/img/agent_info_example.png new file mode 100644 index 000000000..cc6133047 Binary files /dev/null and b/docs/rllib/intro/img/agent_info_example.png differ diff --git a/docs/rllib/intro/index.rst b/docs/rllib/intro/index.rst index b5cae6d73..a381959ec 100644 --- a/docs/rllib/intro/index.rst +++ b/docs/rllib/intro/index.rst @@ -248,6 +248,11 @@ GAPAgent .. seealso:: You can read more about agents that use Global Average Pooling here: https://arxiv.org/abs/2005.11247 +************************** +Weights and Biases (WandB) +************************** + + **************** Recording Videos @@ -260,16 +265,75 @@ Griddly can automatically record videos during training by placing the ``record_ 'env_config': 'record_video_config': { 'frequency': 20000 + 'directory': '/home/griddlyuser/my_experiment_videos' + 'include_global': True, + 'include_agents': False, }, ... } -Videos are recorded using the global observer. This allows multi agent environments to be viewed from the perspective of the whole game rather than the individual observations of the agents. +.. warning:: the ``directory`` value must be an absolute path, as the working directory of workers is controlled by Ray. + +Videos can be recorded from the perspective of the agent and the perspective of the global observer. ``include_global`` and ``include_agents`` will set which videos are recorded. + +.. seealso:: For more information on how to configure observers see :ref:`Observation Spaces ` The triggering of videos is configured using the ``frequency`` variable. The ``frequency`` variable refers to the number of steps in each environment that pass before the recording is triggered. -Once triggered, the next episode is recorded in full. Videos of episodes are recorded on every ray environment. +Once triggered, the next episode is recorded in full. Videos of episodes are recorded on the first environment in every worker in RLLib. + +Uploading Videos to WandB +========================= + +To automatically upload videos to WandB, the ``VideoCallback`` can be set in the RLLib config: + +.. code-block:: python + + 'config': { + ..., + + 'callbacks': VideoCallback, + + ... + } + + +***************************** +Recording Environment Actions +***************************** + +.. figure:: img/agent_info_example.png + :align: center + + An example of logged events for each agent in an environment during training. Can help to diagnose problems with reward shaping and track exploration. -.. seealso:: For more information on how to configure observers see :ref:`Observation Spaces ` \ No newline at end of file +Griddly's RLLib integration hooks into the :ref:`Event History ` and records all the frequency of the actions that are being taken by agents during training. +This event history can then be picked up in the agent's ``info`` in RLLib's callback methods, e,g ``on_episode_step`` + +.. code-block:: python + + 'env_config': + 'record_actions': True, + + ... + } + + + +Uploading Environment Events to WandB +===================================== + + +To automatically upload action events to WandB, the ``ActionTrackerCallback`` can be set in the RLLib config: + +.. code-block:: python + + 'config': { + ..., + + 'callbacks': ActionTrackerCallback, + + ... + } diff --git a/docs/rllib/multi-agent/index.rst b/docs/rllib/multi-agent/index.rst index 0d1b61a7a..db7f4776f 100644 --- a/docs/rllib/multi-agent/index.rst +++ b/docs/rllib/multi-agent/index.rst @@ -10,7 +10,7 @@ To register the multi-agent Griddly environment for usage with RLLib, the enviro .. code-block:: python - # Create the gridnet environment and wrap it in a multi-agent wrapper for self-play + # Create the environment and wrap it in a multi-agent wrapper for self-play def _create_env(env_config): env = RLlibEnv(env_config) return RLlibMultiAgentWrapper(env, env_config) diff --git a/docs/rllib/rts/index.rst b/docs/rllib/rts/index.rst index 620783ab5..9abd34afb 100644 --- a/docs/rllib/rts/index.rst +++ b/docs/rllib/rts/index.rst @@ -4,4 +4,115 @@ Real Time Strategy ################## -Coming Soon! \ No newline at end of file +Griddly also supports Strategy games! Strategy games in the context of Griddly are games where the player can control multiple "units" at at a single time. + +RTS environments similar to multi-agent environments, but the units are controlled by individually selecting them and then performing actions. In this example, only a single action can be send to a particular unit on each turn. + + +************************ +Conditional Action Trees +************************ + +This example uses Conditional Action Trees in order to handle multiple units and invalid action masking. Conditional Action Trees are implemented in RLLib in the ``ConditionalActionImpalaTrainer``. + +.. seealso:: For more information on Conditional Action Trees, see the github repository: https://github.com/Bam4d/conditional-action-trees and the paper: https://arxiv.org/abs/2104.07294. + +************ +Full Example +************ + +.. raw:: html + +
+ +

A video taken during self-training of two agents in the "Griddly-RTS" environment.¶

+
+ +In this example, self-play is used to train the agent controlling both armies. We are using a single IMPALA-CNN policy to teach both agents. This means the policy must learn to play from both perspectives (starting from the bottom of the map or the top). + +.. code-block:: python + + import os + import sys + + import ray + from ray import tune + from ray.rllib.models import ModelCatalog + from ray.tune.registry import register_env + from rts.models import ImpalaCNNAgent + + from griddly import gd + from griddly.util.rllib.callbacks import MultiCallback, ActionTrackerCallback + from griddly.util.rllib.environment.core import RLlibMultiAgentWrapper, RLlibEnv + from griddly.util.rllib.torch.conditional_actions.conditional_action_policy_trainer import \ + ConditionalActionImpalaTrainer + + if __name__ == '__main__': + sep = os.pathsep + os.environ['PYTHONPATH'] = sep.join(sys.path) + + ray.init(num_gpus=1) + + env_name = "griddly-rts-env" + + + def _create_env(env_config): + env = RLlibEnv(env_config) + return RLlibMultiAgentWrapper(env, env_config) + + + register_env(env_name, _create_env) + ModelCatalog.register_custom_model("ImpalaCNN", ImpalaCNNAgent) + + max_training_steps = 100000000 + + config = { + 'framework': 'torch', + ' + 'num_workers': 8, + 'num_envs_per_worker': 5, + + 'callbacks': ActionTrackerCallback, + + 'model': { + 'custom_model': 'ImpalaCNN', + 'custom_model_config': {} + }, + 'env': env_name, + 'env_config': { + 'generate_valid_action_trees': True, + 'yaml_file': 'RTS/Griddly_RTS.yaml', + 'global_observer_type': gd.ObserverType.ISOMETRIC, + 'level': 0, + 'record_actions': True, + 'max_steps': 1000, + }, + + 'record_video_config': { + 'frequency': 20000, # number of rollouts + 'directory': 'videos' + }, + + 'entropy_coeff_schedule': [ + [0, 0.001], + [max_training_steps, 0.0] + ], + 'lr_schedule': [ + [0, args.lr], + [max_training_steps, 0.0] + ], + + } + + stop = { + "timesteps_total": max_training_steps, + } + + result = tune.run(ConditionalActionImpalaTrainer, config=config, stop=stop) + diff --git a/python/.gitignore b/python/.gitignore index 5391f8bed..acdb5a934 100644 --- a/python/.gitignore +++ b/python/.gitignore @@ -146,3 +146,6 @@ scratchpad/ # Video folders .video/ + +# HPC +.apocrita/ diff --git a/python/examples/experiments/conditional-action-trees b/python/examples/experiments/conditional-action-trees index 0c1cc7e39..0fd2cdf11 160000 --- a/python/examples/experiments/conditional-action-trees +++ b/python/examples/experiments/conditional-action-trees @@ -1 +1 @@ -Subproject commit 0c1cc7e39e3024d0538064c629142abe130b0a3d +Subproject commit 0fd2cdf11c2785aa469fc0704be2aff7a3807974 diff --git a/python/examples/experiments/rts-self-play b/python/examples/experiments/rts-self-play new file mode 160000 index 000000000..6cca22aee --- /dev/null +++ b/python/examples/experiments/rts-self-play @@ -0,0 +1 @@ +Subproject commit 6cca22aeeffcb590913fd380d86b131c7d6697c9 diff --git a/python/examples/griddlyrts/play_griddlyrts_gym.py b/python/examples/griddlyrts/play_griddlyrts_gym.py index 8159740f2..aada45c00 100644 --- a/python/examples/griddlyrts/play_griddlyrts_gym.py +++ b/python/examples/griddlyrts/play_griddlyrts_gym.py @@ -10,7 +10,7 @@ wrapper = GymWrapperFactory() wrapper.build_gym_from_yaml("GriddlyRTS-Adv", - 'predator_prey.yaml', + 'RTS/GriddlyRTS.yaml', global_observer_type=gd.ObserverType.SPRITE_2D, player_observer_type=gd.ObserverType.VECTOR, level=0) diff --git a/python/examples/gym/gym_human_player.py b/python/examples/gym/gym_human_player.py index 2e4171754..b10ca6e9f 100644 --- a/python/examples/gym/gym_human_player.py +++ b/python/examples/gym/gym_human_player.py @@ -7,7 +7,7 @@ def callback(env): - initial_global_obs = env.render(observer='global', mode="rgb_array") + initial_global_obs = env.render(observer=0, mode="rgb_array") observation_shape = initial_global_obs.shape recorder = VideoRecorder() @@ -15,7 +15,7 @@ def callback(env): def _callback(prev_obs, obs, action, rew, env_done, info): - global_obs = env.render(observer='global', mode="rgb_array") + global_obs = env.render(observer=0, mode="rgb_array") recorder.add_frame(global_obs) if rew != 0: print(f'\nReward: {rew}') @@ -39,7 +39,7 @@ def _callback(prev_obs, obs, action, rew, env_done, info): # yaml_path = 'Single-Player/GVGAI/bait_keys.yaml' # yaml_path = 'Single-Player/Mini-Grid/minigrid-drunkdwarf.yaml' # yaml_path = 'Single-Player/Mini-Grid/minigrid-spiders.yaml' - # yaml_path = 'Single-Player/GVGAI/spider-nest.yaml' + yaml_path = 'Single-Player/GVGAI/spider-nest.yaml' # yaml_path = 'Single-Player/GVGAI/cookmepasta.yaml' # yaml_path = 'Single-Player/GVGAI/clusters.yaml' # yaml_path = 'Single-Player/GVGAI/zenpuzzle.yaml' @@ -55,11 +55,11 @@ def _callback(prev_obs, obs, action, rew, env_done, info): # yaml_path = '../resources/rataban.yaml' - level = 1 + level = 0 wrapper.build_gym_from_yaml(environment_name, yaml_path, - player_observer_type=gd.ObserverType.SPRITE_2D, - global_observer_type=gd.ObserverType.SPRITE_2D, level=level) + player_observer_type=gd.ObserverType.BLOCK_2D, + global_observer_type=gd.ObserverType.BLOCK_2D, level=level) env = gym.make(f'GDY-{environment_name}-v0') # env.enable_history(True) env.reset() diff --git a/python/examples/rllib/rllib_multi_agent.py b/python/examples/rllib/rllib_multi_agent.py index efa82c5a7..031da44ce 100644 --- a/python/examples/rllib/rllib_multi_agent.py +++ b/python/examples/rllib/rllib_multi_agent.py @@ -2,9 +2,9 @@ import sys import ray +from griddly.util.rllib.callbacks import VideoCallback from ray import tune from ray.rllib.agents.impala import ImpalaTrainer -from ray.rllib.agents.ppo import PPOTrainer from ray.rllib.models import ModelCatalog from ray.tune.registry import register_env @@ -33,10 +33,10 @@ def _create_env(env_config): config = { 'framework': 'torch', - 'num_workers': 8, - 'num_envs_per_worker': 2, + 'num_workers': 3, + 'num_envs_per_worker': 1, - 'num_gpus': 1, + 'callbacks': VideoCallback, 'model': { 'custom_model': 'SimpleConv', diff --git a/python/examples/rllib/rllib_rts.py b/python/examples/rllib/rllib_rts.py new file mode 100644 index 000000000..fe96e0a3b --- /dev/null +++ b/python/examples/rllib/rllib_rts.py @@ -0,0 +1,79 @@ +import os +import sys + +import ray +from ray import tune +from ray.rllib.models import ModelCatalog +from ray.tune.registry import register_env + +from griddly import gd +from griddly.util.rllib.callbacks import ActionTrackerCallback, MultiCallback, VideoCallback +from griddly.util.rllib.environment.core import RLlibMultiAgentWrapper, RLlibEnv +from griddly.util.rllib.torch.agents.impala_cnn import ImpalaCNNAgent +from griddly.util.rllib.torch.conditional_actions.conditional_action_policy_trainer import \ + ConditionalActionImpalaTrainer + +if __name__ == '__main__': + sep = os.pathsep + os.environ['PYTHONPATH'] = sep.join(sys.path) + + ray.init(num_gpus=1) + + env_name = "griddly-rts-env" + + + def _create_env(env_config): + env = RLlibEnv(env_config) + return RLlibMultiAgentWrapper(env, env_config) + + + register_env(env_name, _create_env) + ModelCatalog.register_custom_model("ImpalaCNN", ImpalaCNNAgent) + + max_training_steps = 100000000 + + config = { + 'framework': 'torch', + + 'num_workers': 3, + 'num_envs_per_worker': 2, + + 'callbacks': MultiCallback([ + ActionTrackerCallback, + VideoCallback + ]), + + 'model': { + 'custom_model': 'ImpalaCNN', + 'custom_model_config': {} + }, + 'env': env_name, + 'env_config': { + 'generate_valid_action_trees': True, + 'yaml_file': 'RTS/GriddlyRTS.yaml', + 'global_observer_type': gd.ObserverType.ISOMETRIC, + 'level': 0, + 'record_actions': True, + 'max_steps': 1000, + + 'record_video_config': { + 'frequency': 20000, # number of rollouts + 'directory': 'videos' + }, + }, + 'entropy_coeff_schedule': [ + [0, 0.001], + [max_training_steps, 0.0] + ], + 'lr_schedule': [ + [0, 0.0005], + [max_training_steps, 0.0] + ], + + } + + stop = { + "timesteps_total": max_training_steps, + } + + result = tune.run(ConditionalActionImpalaTrainer, config=config, stop=stop) diff --git a/python/examples/rllib/rllib_single_agent.py b/python/examples/rllib/rllib_single_agent.py index 4f6b47a1d..aa80a90df 100644 --- a/python/examples/rllib/rllib_single_agent.py +++ b/python/examples/rllib/rllib_single_agent.py @@ -2,6 +2,7 @@ import sys import ray +from griddly.util.rllib.callbacks import VideoCallback from ray import tune from ray.rllib.agents.impala import ImpalaTrainer from ray.rllib.models import ModelCatalog @@ -29,12 +30,15 @@ 'num_workers': 8, 'num_envs_per_worker': 4, + 'callbacks': VideoCallback, + 'model': { 'custom_model': 'GAP', 'custom_model_config': {} }, 'env': env_name, 'env_config': { + 'record_video_config': { 'frequency': 100000, 'directory': 'videos' diff --git a/python/griddly/GymWrapper.py b/python/griddly/GymWrapper.py index 913661d5a..72fd76f0e 100644 --- a/python/griddly/GymWrapper.py +++ b/python/griddly/GymWrapper.py @@ -12,7 +12,8 @@ class GymWrapper(gym.Env): metadata = {'render.modes': ['human', 'rgb_array']} def __init__(self, yaml_file=None, level=0, global_observer_type=gd.ObserverType.VECTOR, - player_observer_type=gd.ObserverType.VECTOR, max_steps=None, gdy_path=None, image_path=None, shader_path=None, + player_observer_type=gd.ObserverType.VECTOR, max_steps=None, gdy_path=None, image_path=None, + shader_path=None, gdy=None, game=None, **kwargs): """ Currently only supporting a single player (player 1 as defined in the environment yaml @@ -160,7 +161,12 @@ def reset(self, level_id=None, level_string=None, global_observations=False): self.initialize_spaces() + for p in range(self.player_count): + self._player_last_observation.append(np.array(self._players[p].observe(), copy=False)) + if global_observations: + self._global_last_observation = np.array(self.game.observe(), copy=False) + return { 'global': self._global_last_observation, 'player': self._player_last_observation[0] if self.player_count == 1 else self._player_last_observation @@ -170,18 +176,14 @@ def reset(self, level_id=None, level_string=None, global_observations=False): def initialize_spaces(self): self._player_last_observation = [] - for p in range(self.player_count): - self._player_last_observation.append(np.array(self._players[p].observe(), copy=False)) - - self._global_last_observation = np.array(self.game.observe(), copy=False) - self.player_observation_shape = self._player_last_observation[0].shape - self.global_observation_shape = self._global_last_observation.shape + self.player_observation_shape = self.game.get_player_observation_shape() + self.global_observation_shape = self.game.get_global_observation_shape() self.global_observation_space = gym.spaces.Box(low=0, high=255, shape=self.global_observation_shape, dtype=np.uint8) - self._observation_shape = self._player_last_observation[0].shape + self._observation_shape = self.player_observation_shape observation_space = gym.spaces.Box(low=0, high=255, shape=self._observation_shape, dtype=np.uint8) if self.player_count > 1: diff --git a/python/griddly/util/rllib/callbacks.py b/python/griddly/util/rllib/callbacks.py index c46e85824..5684d2e73 100644 --- a/python/griddly/util/rllib/callbacks.py +++ b/python/griddly/util/rllib/callbacks.py @@ -1,20 +1,159 @@ from typing import Optional, Dict - -from ray.rllib import Policy, BaseEnv +from collections import Counter +from ray.rllib import Policy, BaseEnv, SampleBatch from ray.rllib.agents.callbacks import DefaultCallbacks +from ray.rllib.env.base_env import _VectorEnvToBaseEnv from ray.rllib.evaluation import MultiAgentEpisode -from ray.rllib.utils.typing import PolicyID +from ray.rllib.utils.typing import PolicyID, AgentID from wandb import Video -class GriddlyCallbacks(DefaultCallbacks): +class MultiCallback(DefaultCallbacks): + + def __init__(self, callback_class_list): + super().__init__() + self._callback_class_list = callback_class_list + + self._callback_list = [] + + def __call__(self, *args, **kwargs): + self._callback_list = [callback_class() for callback_class in self._callback_class_list] + + return self + + def on_episode_start(self, *, worker: "RolloutWorker", base_env: BaseEnv, policies: Dict[PolicyID, Policy], + episode: MultiAgentEpisode, env_index: Optional[int] = None, **kwargs) -> None: + for callback in self._callback_list: + callback.on_episode_start(worker=worker, base_env=base_env, policies=policies, episode=episode, + env_index=env_index, **kwargs) + + def on_episode_step(self, *, worker: "RolloutWorker", base_env: BaseEnv, episode: MultiAgentEpisode, + env_index: Optional[int] = None, **kwargs) -> None: + for callback in self._callback_list: + callback.on_episode_step(worker=worker, base_env=base_env, episode=episode, env_index=env_index, **kwargs) + + def on_episode_end(self, *, worker: "RolloutWorker", base_env: BaseEnv, policies: Dict[PolicyID, Policy], + episode: MultiAgentEpisode, env_index: Optional[int] = None, **kwargs) -> None: + for callback in self._callback_list: + callback.on_episode_end(worker=worker, base_env=base_env, policies=policies, episode=episode, + env_index=env_index, **kwargs) + + def on_postprocess_trajectory(self, *, worker: "RolloutWorker", episode: MultiAgentEpisode, agent_id: AgentID, + policy_id: PolicyID, policies: Dict[PolicyID, Policy], + postprocessed_batch: SampleBatch, original_batches: Dict[AgentID, SampleBatch], + **kwargs) -> None: + for callback in self._callback_list: + callback.on_postprocess_trajectory(worker=worker, episode=episode, agent_id=agent_id, policy_id=policy_id, + policies=policies, postprocessed_batch=postprocessed_batch, + original_batches=original_batches, **kwargs) + + def on_sample_end(self, *, worker: "RolloutWorker", samples: SampleBatch, **kwargs) -> None: + for callback in self._callback_list: + callback.on_sample_end(worker=worker, samples=samples, **kwargs) + + def on_learn_on_batch(self, *, policy: Policy, train_batch: SampleBatch, result: dict, **kwargs) -> None: + for callback in self._callback_list: + callback.on_learn_on_batch(policy=policy, train_batch=train_batch, result=result, **kwargs) + + def on_train_result(self, *, trainer, result: dict, **kwargs) -> None: + for callback in self._callback_list: + callback.on_train_result(trainer=trainer, result=result, **kwargs) + + +class VideoCallback(DefaultCallbacks): + + def _get_envs(self, base_env): + if isinstance(base_env, _VectorEnvToBaseEnv): + return base_env.vector_env.envs + else: + return base_env.envs + + def on_episode_start(self, + *, + worker: "RolloutWorker", + base_env: BaseEnv, + policies: Dict[PolicyID, Policy], + episode: MultiAgentEpisode, + env_index: Optional[int] = None, + **kwargs) -> None: + + envs = self._get_envs(base_env) + envs[env_index].on_episode_start(worker.worker_index, env_index) + + def on_episode_end(self, + *, + worker: "RolloutWorker", + base_env: BaseEnv, + policies: Dict[PolicyID, Policy], + episode: MultiAgentEpisode, + env_index: Optional[int] = None, + **kwargs) -> None: + + envs = self._get_envs(base_env) + num_players = envs[env_index].player_count + + info = episode.last_info_for(1) if num_players > 1 else episode.last_info_for() + if 'videos' in info: + for video in info['videos']: + level = video['level'] + path = video['path'] + episode.media[f'level_{level}_1'] = Video(path) + + +class ActionTrackerCallback(DefaultCallbacks): + + def __init__(self): + super().__init__() + + self._action_frequency_trackers = {} + + def _get_envs(self, base_env): + if isinstance(base_env, _VectorEnvToBaseEnv): + return base_env.vector_env.envs + else: + return base_env.envs + + def on_episode_start(self, + *, + worker: "RolloutWorker", + base_env: BaseEnv, + policies: Dict[PolicyID, Policy], + episode: MultiAgentEpisode, + env_index: Optional[int] = None, + **kwargs) -> None: + envs = self._get_envs(base_env) + num_players = envs[env_index].player_count + self._action_frequency_trackers[episode.episode_id] = [] + for p in range(0, num_players): + self._action_frequency_trackers[episode.episode_id].append(Counter()) + + def on_episode_step(self, + *, + worker: "RolloutWorker", + base_env: BaseEnv, + episode: MultiAgentEpisode, + env_index: Optional[int] = None, + **kwargs) -> None: + + envs = self._get_envs(base_env) + num_players = envs[env_index].player_count + + for p in range(0, num_players): + info = episode.last_info_for(p+1) + if 'History' in info: + history = info['History'] + for event in history: + action_name = event['ActionName'] + self._action_frequency_trackers[episode.episode_id][p][action_name] += 1 def on_episode_end(self, *, worker: "RolloutWorker", base_env: BaseEnv, policies: Dict[PolicyID, Policy], episode: MultiAgentEpisode, env_index: Optional[int] = None, **kwargs) -> None: - if env_index == 0: - if not worker.multiagent: - info = episode.last_info_for() - if 'video' in info: - level = info['video']['level'] - path = info['video']['path'] - episode.media[f'level_{level}'] = Video(path) + + envs = self._get_envs(base_env) + num_players = envs[env_index].player_count + + for p in range(0, num_players): + for action_name, frequency in self._action_frequency_trackers[episode.episode_id][p].items(): + episode.custom_metrics[f'agent_info/{p+1}/{action_name}'] = frequency + + del self._action_frequency_trackers[episode.episode_id] diff --git a/python/griddly/util/rllib/environment/core.py b/python/griddly/util/rllib/environment/core.py index 602fa5f16..3eddaf55c 100644 --- a/python/griddly/util/rllib/environment/core.py +++ b/python/griddly/util/rllib/environment/core.py @@ -1,7 +1,5 @@ import os from collections import defaultdict -from enum import Enum -from uuid import uuid1 import gym import numpy as np @@ -9,14 +7,7 @@ from ray.rllib.utils.typing import MultiAgentDict from griddly import GymWrapper -from griddly.RenderTools import VideoRecorder - - -class RecordingState(Enum): - NOT_RECORDING = 1 - WAITING_FOR_EPISODE_START = 2 - BEFORE_RECORDING = 3 - RECORDING = 4 +from griddly.util.rllib.environment.observer_episode_recorder import ObserverEpisodeRecorder class RLlibEnv(GymWrapper): @@ -55,23 +46,32 @@ class RLlibEnv(GymWrapper): def __init__(self, env_config): super().__init__(**env_config) + self.env_steps = 0 + self._env_idx = None + self._worker_idx = None + + self.video_initialized = False + + self.record_video_config = env_config.get('record_video_config', None) + + if self.record_video_config is not None: + self.video_frequency = self.record_video_config.get('frequency', 1000) + self.video_directory = os.path.realpath(self.record_video_config.get('directory', '.')) + self.include_global_video = self.record_video_config.get('include_global', True) + self.include_agent_videos = self.record_video_config.get('include_agents', False) + os.makedirs(self.video_directory, exist_ok=True) + + self.record_actions = env_config.get('record_actions', False) + self.generate_valid_action_trees = env_config.get('generate_valid_action_trees', False) - self._record_video_config = env_config.get('record_video_config', None) self._random_level_on_reset = env_config.get('random_level_on_reset', False) super().reset() - self._recording_state = None - self._env_steps = 0 - - if self._record_video_config is not None: - self._recording_state = RecordingState.BEFORE_RECORDING - self._video_frequency = self._record_video_config.get('frequency', 1000) - self._video_directory = os.path.realpath(self._record_video_config.get('directory', '.')) - os.makedirs(self._video_directory, exist_ok=True) - self.set_transform() + self.enable_history(self.record_actions) + def _transform(self, observation): if self.player_count > 1: @@ -83,37 +83,21 @@ def _transform(self, observation): def _after_step(self, observation, reward, done, info): extra_info = {} - if self._recording_state is not None: - if self._recording_state is RecordingState.NOT_RECORDING and self._env_steps % self._video_frequency == 0: - self._recording_state = RecordingState.WAITING_FOR_EPISODE_START - if self._recording_state == RecordingState.BEFORE_RECORDING: - global_obs = self.render(observer='global', mode='rgb_array') - self._global_recorder = VideoRecorder() - - video_filename = os.path.join( - self._video_directory, - f'global_video_{uuid1()}_{self.level_id}_{self._env_steps}.mp4' - ) - - self._global_recorder.start(video_filename, global_obs.shape) - self._recording_state = RecordingState.RECORDING - - if self._recording_state == RecordingState.RECORDING: - global_obs = self.render(observer='global', mode='rgb_array') - self._global_recorder.add_frame(global_obs) - if done: - self._recording_state = RecordingState.NOT_RECORDING - self._global_recorder.close() - - extra_info['video'] = { - 'level': self.level_id, - 'path': self._global_recorder.output_file - } - - if self._recording_state == RecordingState.WAITING_FOR_EPISODE_START: - if done: - self._recording_state = RecordingState.BEFORE_RECORDING + # If we are in a multi-agent setting then we handle videos elsewhere + if self.is_video_enabled(): + if self.player_count == 1: + videos_list = [] + if self.include_agent_videos: + video_info = self._agent_recorder.step(self.level_id, self.env_steps, done) + if video_info is not None: + videos_list.append(video_info) + if self.include_global_video: + video_info = self._global_recorder.step(self.level_id, self.env_steps, done) + if video_info is not None: + videos_list.append(video_info) + + extra_info['videos'] = videos_list return extra_info @@ -158,20 +142,48 @@ def step(self, action): extra_info = self._after_step(observation, reward, done, info) - if 'video' in extra_info: - info['video'] = extra_info['video'] - - self._env_steps += 1 + if 'videos' in extra_info: + info['videos'] = extra_info['videos'] if self.generate_valid_action_trees: self.last_valid_action_trees = self._get_valid_action_trees() - info['valid_action_tree'] = dict(self.last_valid_action_trees) + info['valid_action_tree'] = self.last_valid_action_trees.copy() + + self.env_steps += 1 return self._transform(observation), reward, done, info def render(self, mode='human', observer=0): return super().render(mode, observer='global') + def is_video_enabled(self): + return self.record_video_config is not None and self._env_idx is not None and self._env_idx == 0 + + def on_episode_start(self, worker_idx, env_idx): + self._env_idx = env_idx + self._worker_idx = worker_idx + + if self.is_video_enabled() and not self.video_initialized: + self.init_video_recording() + self.video_initialized = True + + def init_video_recording(self): + if self.player_count == 1: + if self.include_agent_videos: + self._agent_recorder = ObserverEpisodeRecorder( + self, + 1, + self.video_frequency, + self.video_directory + ) + if self.include_global_video: + self._global_recorder = ObserverEpisodeRecorder( + self, + 'global', + self.video_frequency, + self.video_directory + ) + class RLlibMultiAgentWrapper(gym.Wrapper, MultiAgentEnv): @@ -183,6 +195,12 @@ def __init__(self, env, env_config): # Used to keep track of agents that are active in the environment self._active_agents = set() + self._agent_recorders = None + self._global_recorder = None + + self._worker_idx = None + self._env_idx = None + assert self.player_count > 1, 'RLlibMultiAgentWrapper can only be used with environments that have multiple agents' def _to_multi_agent_map(self, data): @@ -197,6 +215,26 @@ def _resolve_player_done_variable(self): resolved_variables = self.game.get_global_variable([self._player_done_variable]) return resolved_variables[self._player_done_variable] + def _after_step(self, obs_map, reward_map, done_map, info_map): + extra_info = {} + + + if self.is_video_enabled(): + videos_list = [] + if self.include_agent_videos: + for a in self._active_agents: + video_info = self._agent_recorders[a].step(self.level_id, self.env_steps, done_map[a - 1]) + if video_info is not None: + videos_list.append(video_info) + if self.include_global_video: + video_info = self._global_recorder.step(self.level_id, self.env_steps, done_map['__all__']) + if video_info is not None: + videos_list.append(video_info) + + extra_info['videos'] = videos_list + + return extra_info + def step(self, action_dict: MultiAgentDict): actions_array = np.zeros((self.player_count, *self.action_space.shape)) for agent_id, action in action_dict.items(): @@ -217,11 +255,19 @@ def step(self, action_dict: MultiAgentDict): if self.generate_valid_action_trees: info_map = self._to_multi_agent_map([ - {'valid_action_tree': valid_action_tree} for valid_action_tree in info['valid_action_trees'] + {'valid_action_tree': valid_action_tree} for valid_action_tree in info['valid_action_tree'] ]) else: info_map = self._to_multi_agent_map(defaultdict(dict)) + if self.record_actions: + for event in info['History']: + event_player_id = event['PlayerId'] + if event_player_id != 0: + if 'History' not in info_map[event_player_id]: + info_map[event_player_id]['History'] = [] + info_map[event_player_id]['History'].append(event) + obs_map = self._to_multi_agent_map(obs) reward_map = self._to_multi_agent_map(reward) @@ -230,8 +276,43 @@ def step(self, action_dict: MultiAgentDict): if is_done: self._active_agents.discard(agent_id) + extra_info = self._after_step(obs_map, reward_map, done_map, info_map) + + if 'videos' in extra_info: + info_map[1]['videos'] = extra_info['videos'] + assert len(obs_map) == len(reward_map) assert len(obs_map) == len(done_map) - 1 assert len(obs_map) == len(info_map) return obs_map, reward_map, done_map, info_map + + def is_video_enabled(self): + return self.record_video_config is not None and self._env_idx is not None and self._env_idx == 0 + + def on_episode_start(self, worker_idx, env_idx): + self._env_idx = env_idx + self._worker_idx = worker_idx + + if self.is_video_enabled() and not self.video_initialized: + self.init_video_recording() + self.video_initialized = True + + def init_video_recording(self): + if self.include_agent_videos: + self._agent_recorders = {} + for a in range(self.player_count): + agent_id = a + 1 + self._agent_recorders[agent_id] = ObserverEpisodeRecorder( + self, + agent_id, + self.video_frequency, + self.video_directory + ) + if self.include_global_video: + self._global_recorder = ObserverEpisodeRecorder( + self, + 'global', + self.video_frequency, + self.video_directory + ) diff --git a/python/griddly/util/rllib/environment/observer_episode_recorder.py b/python/griddly/util/rllib/environment/observer_episode_recorder.py new file mode 100644 index 000000000..c943cf07f --- /dev/null +++ b/python/griddly/util/rllib/environment/observer_episode_recorder.py @@ -0,0 +1,60 @@ +from enum import Enum +import os +from uuid import uuid1 + +from griddly.RenderTools import VideoRecorder + + +class RecordingState(Enum): + NOT_RECORDING = 1 + WAITING_FOR_EPISODE_START = 2 + BEFORE_RECORDING = 3 + RECORDING = 4 + +class ObserverEpisodeRecorder(): + + def __init__(self, env, observer, video_frequency, video_directory="."): + + self._video_frequency = video_frequency + self._video_directory = video_directory + self._observer = observer + self._env = env + + self._recording_state = RecordingState.BEFORE_RECORDING + + def step(self, level_id, step_count, done): + + video_info = None + + if self._recording_state is RecordingState.NOT_RECORDING and step_count % self._video_frequency == 0: + self._recording_state = RecordingState.WAITING_FOR_EPISODE_START + + if self._recording_state == RecordingState.BEFORE_RECORDING: + obs = self._env.render(observer=self._observer, mode='rgb_array') + self._recorder = VideoRecorder() + + video_filename = os.path.join( + self._video_directory, + f'episode_video_{self._observer}_{uuid1()}_{level_id}_{step_count}.mp4' + ) + + self._recorder.start(video_filename, obs.shape) + self._recording_state = RecordingState.RECORDING + + if self._recording_state == RecordingState.RECORDING: + obs = self._env.render(observer=self._observer, mode='rgb_array') + self._recorder.add_frame(obs) + if done: + self._recording_state = RecordingState.NOT_RECORDING + self._recorder.close() + + video_info = { + 'level': level_id, + 'path': self._recorder.output_file + } + + if self._recording_state == RecordingState.WAITING_FOR_EPISODE_START: + if done: + self._recording_state = RecordingState.BEFORE_RECORDING + + return video_info \ No newline at end of file diff --git a/python/griddly/util/rllib/torch/agents/impala_cnn.py b/python/griddly/util/rllib/torch/agents/impala_cnn.py new file mode 100644 index 000000000..70291c7fa --- /dev/null +++ b/python/griddly/util/rllib/torch/agents/impala_cnn.py @@ -0,0 +1,80 @@ +from ray.rllib.models.torch.torch_modelv2 import TorchModelV2 +from torch import nn +import torch +from griddly.util.rllib.torch.agents.common import layer_init + + +class ResidualBlock(nn.Module): + def __init__(self, channels): + super().__init__() + self.conv0 = nn.Conv2d(in_channels=channels, out_channels=channels, kernel_size=3, padding=1) + self.conv1 = nn.Conv2d(in_channels=channels, out_channels=channels, kernel_size=3, padding=1) + + def forward(self, x): + inputs = x + x = torch.relu(x) + x = self.conv0(x) + x = torch.relu(x) + x = self.conv1(x) + return x + inputs + + +class ConvSequence(nn.Module): + def __init__(self, input_shape, out_channels): + super().__init__() + self._input_shape = input_shape + self._out_channels = out_channels + self.conv = nn.Conv2d(in_channels=self._input_shape[0], out_channels=self._out_channels, kernel_size=3, + padding=1) + self.res_block0 = ResidualBlock(self._out_channels) + self.res_block1 = ResidualBlock(self._out_channels) + + def forward(self, x): + x = self.conv(x) + x = torch.max_pool2d(x, kernel_size=3, stride=2, padding=1) + x = self.res_block0(x) + x = self.res_block1(x) + assert x.shape[1:] == self.get_output_shape() + return x + + def get_output_shape(self): + _c, h, w = self._input_shape + return (self._out_channels, (h + 1) // 2, (w + 1) // 2) + + +class ImpalaCNNAgent(TorchModelV2, nn.Module): + """ + Simple Convolution agent that calculates the required linear output layer + """ + + def __init__(self, obs_space, action_space, num_outputs, model_config, name): + super().__init__(obs_space, action_space, num_outputs, model_config, name) + nn.Module.__init__(self) + + conv_seqs = [] + h, w, c = obs_space.shape + shape = (c, h, w) + for out_channels in [16, 32, 32]: + conv_seq = ConvSequence(shape, out_channels) + shape = conv_seq.get_output_shape() + conv_seqs.append(conv_seq) + conv_seqs += [ + nn.Flatten(), + nn.ReLU(), + nn.Linear(in_features=shape[0] * shape[1] * shape[2], out_features=256), + nn.ReLU(), + ] + self.network = nn.Sequential(*conv_seqs) + self._actor_head = layer_init(nn.Linear(256, num_outputs), std=0.01) + self._critic_head = layer_init(nn.Linear(256, 1), std=1) + + def forward(self, input_dict, state, seq_lens): + obs_transformed = input_dict['obs'].permute(0, 3, 1, 2) + network_output = self.network(obs_transformed) + value = self._critic_head(network_output) + self._value = value.reshape(-1) + logits = self._actor_head(network_output) + return logits, state + + def value_function(self): + return self._value diff --git a/python/griddly/util/rllib/torch/conditional_actions/conditional_action_exploration.py b/python/griddly/util/rllib/torch/conditional_actions/conditional_action_exploration.py index 164442adb..4e6842d3b 100644 --- a/python/griddly/util/rllib/torch/conditional_actions/conditional_action_exploration.py +++ b/python/griddly/util/rllib/torch/conditional_actions/conditional_action_exploration.py @@ -5,9 +5,11 @@ from torch.distributions import Categorical import numpy as np + class TorchConditionalMaskingExploration(): - def __init__(self, model, dist_inputs, valid_action_trees, explore=False, invalid_action_masking='conditional', allow_nop=False): + def __init__(self, model, dist_inputs, valid_action_trees, explore=False, invalid_action_masking='conditional', + allow_nop=False): self._valid_action_trees = valid_action_trees self._num_inputs = dist_inputs.shape[0] @@ -19,23 +21,28 @@ def __init__(self, model, dist_inputs, valid_action_trees, explore=False, invali self._num_action_logits = np.sum(self._action_space_shape) self._num_action_parts = len(self._action_space_shape) + self.model = model + self._invalid_action_masking = invalid_action_masking self._allow_nop = allow_nop + self.device = dist_inputs.device + self._explore = explore self._inputs_split = dist_inputs.split(tuple(self._action_space_shape), dim=1) - self._full_tree = self._fill_node(self._action_space_shape,0) - - def _mask_and_sample(self, options, logits, is_parameters=False): + def _mask_and_sample(self, subtrees, logits): - mask = torch.zeros([logits.shape[0]]).to(logits.device) - mask[options] = 1 - - if is_parameters: - if not self._allow_nop: - mask[0] = 0 + mask = torch.zeros_like(logits).to(self.device) + for i in range(self._num_inputs): + try: + mask[i][list(subtrees[i].keys())] = 1 + except IndexError as e: + print(e) + print(list(subtrees[i].keys())) + print(subtrees) + raise e masked_logits = logits + torch.log(mask) @@ -44,92 +51,54 @@ def _mask_and_sample(self, options, logits, is_parameters=False): logp = dist.log_prob(sampled) out_logits = masked_logits - # if not self._allow_nop and is_parameters: - # assert sampled != 0 - - - return sampled, out_logits, logp, mask - - def _fill_node(self, keys, pos): - if pos < len(keys): - return {k: self._fill_node(keys, pos + 1) for k in np.arange(keys[pos])} - else: - return {} + next_subtrees = [] + for i in range(self._num_inputs): + next_subtrees.append(subtrees[i][int(sampled[i])]) - def _merge_all_branches(self, tree): - all_nodes = {} - merged_tree = {} - for k, v in tree.items(): - v = self._merge_all_branches(v) - all_nodes.update(v) + return sampled, next_subtrees, out_logits, logp, mask - for k in tree.keys(): - merged_tree[k] = all_nodes - - return merged_tree - - def _process_valid_action_tree(self, valid_action_tree): + def _process_valid_action_tree_batched(self, valid_action_tree): subtree = valid_action_tree - subtree_options = list(subtree.keys()) # In the case there are no available actions for the player - if len(subtree_options) == 0: - subtree = self._full_tree - # build_tree = subtree - # for _ in range(self._num_action_parts): - # build_tree[0] = {} - # build_tree = build_tree[0] - subtree_options = list(subtree.keys()) + if len(subtree.keys()) == 0: + build_tree = subtree + for _ in range(self._num_action_parts): + build_tree[0] = {} + build_tree = build_tree[0] - # If we want very basic action masking where parameterized masks are superimposed we use this - if self._invalid_action_masking == 'collapsed': - subtree = self._merge_all_branches(valid_action_tree) - subtree_options = list(subtree.keys()) - - return subtree, subtree_options + return subtree def get_actions_and_mask(self): - actions = torch.zeros([self._num_inputs, self._num_action_parts]) - masked_logits = torch.zeros([self._num_inputs, self._num_action_logits]) - mask = torch.zeros([self._num_inputs, self._num_action_logits]) - logp_sums = torch.zeros([self._num_inputs]) + actions = torch.zeros([self._num_inputs, self._num_action_parts]).to(self.device) + masked_logits = torch.zeros([self._num_inputs, self._num_action_logits]).to(self.device) + mask = torch.zeros([self._num_inputs, self._num_action_logits]).to(self.device) + logp_sums = torch.zeros([self._num_inputs]).to(self.device) if self._valid_action_trees is not None: - for i in range(self._num_inputs): - if len(self._valid_action_trees) >= 1: - - subtree, subtree_options = self._process_valid_action_tree(self._valid_action_trees[i]) - - logp_parts = torch.zeros([self._num_action_parts]) - mask_offset = 0 - for a in range(self._num_action_parts): - - try: - dist_part = self._inputs_split[a] - is_parameters = a==(self._num_action_parts-1) - sampled, masked_part_logits, logp, mask_part = self._mask_and_sample(subtree_options, dist_part[i], is_parameters) - - # Set the action and the mask for each part of the action - actions[i, a] = sampled - masked_logits[i, mask_offset:mask_offset + self._action_space_shape[a]] = masked_part_logits - mask[i, mask_offset:mask_offset + self._action_space_shape[a]] = mask_part + if len(self._valid_action_trees) >= 1: - logp_parts[a] = logp + subtrees = [self._process_valid_action_tree_batched(tree) for tree in self._valid_action_trees] + mask_offset = 0 + for a in range(self._num_action_parts): + dist_part = self._inputs_split[a] - mask_offset += self._action_space_shape[a] + sampled, subtrees, masked_part_logits, logp, mask_part = self._mask_and_sample(subtrees, + dist_part) - subtree = subtree[int(sampled)] - subtree_options = list(subtree.keys()) - except ValueError as e: - print(e) + # Set the action and the mask for each part of the action + actions[:, a] = sampled + masked_logits[:, mask_offset:mask_offset + self._action_space_shape[a]] = masked_part_logits + mask[:, mask_offset:mask_offset + self._action_space_shape[a]] = mask_part + logp_sums += logp - logp_sums[i] = torch.sum(logp_parts) + mask_offset += self._action_space_shape[a] # if its a discrete then flatten the space if self._num_action_parts == 1: actions = actions.flatten() - return actions, masked_logits, logp_sums, mask \ No newline at end of file + return actions, masked_logits, logp_sums, mask diff --git a/python/setup.py b/python/setup.py index f30016c60..6873b62b6 100644 --- a/python/setup.py +++ b/python/setup.py @@ -71,7 +71,7 @@ def griddly_package_data(config='Debug'): setup( name='griddly', - version="1.0.2", + version="1.1.0", author_email="chrisbam4d@gmail.com", description="Griddly Python Libraries", long_description=long_description, diff --git a/resources/games/RTS/GriddlyRTS.yaml b/resources/games/RTS/GriddlyRTS.yaml index 2dc2f1876..a1687daea 100644 --- a/resources/games/RTS/GriddlyRTS.yaml +++ b/resources/games/RTS/GriddlyRTS.yaml @@ -7,7 +7,7 @@ Environment: TileSize: 16 BackgroundTile: oryx/oryx_tiny_galaxy/tg_sliced/tg_world/tg_world_floor_panel_metal_a.png Isometric: - TileSize: [32, 48] + TileSize: [ 32, 48 ] BackgroundTile: oryx/oryx_iso_dungeon/floor-1.png IsoTileHeight: 16 IsoTileDepth: 4 @@ -22,102 +22,120 @@ Environment: Count: 2 Termination: Lose: - - eq: [base:count, 0] # If the player has no bases - Win: - - eq: [_score, 10] # First player to 10 reward points + - Conditions: + - eq: [ base:count, 0 ] # If the player has no bases + Reward: -10 # -10 for a loss + OpposingReward: 10 # as the agent didnt lose Levels: - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W - W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W - W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W - W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . M M M M . . . . . . . . . . W - W . . . . . . . . . . . . . . M M M M M M . . . . . . . . W - W . . . . . . . . . . . . . M . . M . M M . . . . . . . . W - W . . . . . . . . . . . . . M M M M M M M . . . . . . . . W - W . . . . . . . . . . . . . . . M M M M . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W - W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W + M M . . . . . . . . . . . . . . + M M . . . . . . . . . . . . . . + . . A1 H1 . . . . . . . . . . . . + . . H1 . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . H2 . . + . . . . . . . . . . . . H2 A2 . . + . . . . . . . . . . . . . . M M + . . . . . . . . . . . . . . M M + - | + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W + W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W + W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W + W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . M M M M . . . . . . . . . . W + W . . . . . . . . . . . . . . M M M M M M . . . . . . . . W + W . . . . . . . . . . . . . M . . M . M M . . . . . . . . W + W . . . . . . . . . . . . . M M M M M M M . . . . . . . . W + W . . . . . . . . . . . . . . . M M M M . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W + W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W - W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W - W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W - W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W - W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W W W W W W W W W . . . . . . . . . . . . . . W W W W W w W - W . . . . . . W W . . . w w w w w w . . . . . W W W W W w W - W . . . . . . . . . . . . . w w . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W - W . . . . . . . . . . . . . . M M M M . . . . W W W W W w W - W . . . . P1 w . . . . . . . . M M M M M M . W W W W W W W W - W . . . . P1 w . . . . . . . M . . M . M M . . . . . . . . W - W . . . . P2 w . . . . . . . M M M M M M M . . . . . . . . W - W . . . . P2 w . . . . . . . . . M M M M . . . . . . . . . W - W . . . . P1 w . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W - W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . B1 . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . H1 . . . . . . . . . . . . . . . . . . . . . . W + W . . . H1 . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M . . . . . . . . . . . . . W + W . . . . . . . . . . M M M M M M . . . . . . . . . . . . W + W . . . . . . . . . M M . M M M M . . . . . . . . . . . . W + W . . . . . . . . . M . M M M . M . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W W W W W W W W W . . . . . . . . . . . . . . W W W W W w W + W . . . . . . W W . . . w w w w w w . . . . . W W W W W w W + W . . . . . . . . . . . . . w w . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . . . . . . . . . W W W W W w W + W . . . . . . . . . . . . . . M M M M . . . . W W W W W w W + W . . . . . w . . . . . . . . M M M M M M . W W W W W W W W + W . . . . . w . . . . . . . M . . M . M M . . . . . . . . W + W . . . . . w . . . . . . . M M M M M M M . . . . . . . . W + W . . . . . w . . . . . . . . . M M M M . . . . . . . . . W + W . . . . . w . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . H2 . . . . . . W + W . . . . . . . . . . . . . . . . . . H2 . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . B2 . . W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - | - W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W - W . . . . M M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . M M M M W - W . . . . . M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . M M W - W . . . . . . M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . H2 . . M W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . B2 H2 . M W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W - W W W w w W W W W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W W W . . W W W W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W W W W W W W W W W W W W w w w w w w w w w w w w w W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M M . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . . W - W M M M . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . . . W - W W W W W W W W W W W . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . W W W W W W W W W W W + W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W + W . . . . M M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . M M M M W + W . . . . . M M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . M M W + W . . . . . . M W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . H2 . . M W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . B2 H2 . M W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W . . . . . . . W . . . . . . . . . . . . . . . . . . . w . . . . . . . . . . . . . . . . . . . W . . . . . . . W + W W W w w W W W W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W W W . . W W W W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W W W W W W W W W W W W W w w w w w w w w w w w w w W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W . . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M . . . . . . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M M . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . . W + W M M M . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . . . W + W W W W W W W W W W W . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . W W W W W W W W W W W W . . . . . . . . . . . . . . W . . . . . . . . . . M M M M M . . . . . . . . . . W . . . . . . . . . . . M M M W W . . . . . . . . . . . . . . W . . . . . . . . . . . M M M . . . . . . . . . . . W . . . . . . . . . . . . M M W W . . . . . . . . . . . . . . W . . . . . . . . . . . . M . . . . . . . . . . . . W . . . . . . . . . . . . . M W @@ -149,48 +167,138 @@ Environment: W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W Actions: - - Name: spawn_harvester + - Name: spawn_worker InputMapping: Internal: true Behaviours: - Src: Object: base Commands: - - spawn: harvester + - spawn: worker + - set: [ is_busy, 0 ] Dst: Object: _empty - - Src: Object: base Dst: - Object: [base, puncher, harvester, pusher, movable_wall] + Object: [ base, barracks, combat, worker, ranged, movable_wall ] Commands: + # Try to spawn in another location on the next tick - exec: - Action: spawn_harvester + Action: spawn_worker + Delay: 1 + Randomize: true + - Name: spawn_combat + InputMapping: + Internal: true + Behaviours: + - Src: + Object: barracks + Commands: + - spawn: combat + - set: [ is_busy, 0 ] + Dst: + Object: _empty + + - Src: + Object: barracks + Dst: + Object: [ base, barracks, combat, worker, ranged, movable_wall ] + Commands: + # Try to spawn in another location on the next tick + - exec: + Action: spawn_combat Delay: 1 Randomize: true - # Harvester costs 5 resources to build - - Name: build_harvester + - Name: construct_barracks + InputMapping: + Inputs: + 1: + Description: Completes construction of a barracks + VectorToDest: [ 0, 0 ] + Internal: true + Behaviours: + - Src: + Object: barracks_disabled + Commands: + - set: [ is_busy, 0 ] + - change_to: barracks + Dst: + Object: barracks_disabled + + # worker costs 5 resources to build, get a reward when a worker is built + - Name: build_worker + InputMapping: + Inputs: + 1: + Description: Build + VectorToDest: [ 0, 0 ] Behaviours: - Src: - Preconditions: - - gt: [player_resources, 5] Object: base + Preconditions: + - gte: [ player_resources, 5 ] + - eq: [ is_busy, 0 ] + Commands: + - set: [ is_busy, 1 ] + - sub: [ player_resources, 5 ] + - reward: 1 + # Queue a build which will take 10 seconds + - exec: + Action: spawn_worker + Delay: 10 + Randomize: true + Executor: action Dst: Object: base + + - Name: build_combat + InputMapping: + Inputs: + 1: + Description: Build + VectorToDest: [ 0, 0 ] + Behaviours: + - Src: + Object: barracks + Preconditions: + - gte: [ player_resources, 5 ] + - eq: [ is_busy, 0 ] Commands: + - set: [ is_busy, 1 ] + - sub: [ player_resources, 5 ] + - reward: 1 - exec: - Action: spawn_harvester + Action: spawn_combat Delay: 10 Randomize: true - - + Executor: action + Dst: + Object: barracks + + - Name: build_barracks + Behaviours: + - Src: + Object: worker + Preconditions: + - gte: [ player_resources, 20 ] + - eq: [ is_busy, 0 ] + Commands: + - sub: [ player_resources, 20 ] + - reward: 1 + - spawn: barracks_disabled + Dst: + Object: _empty + - Name: gather Behaviours: - Src: - Object: harvester + Object: worker + Preconditions: + - lt: [ resources, 5 ] + - eq: [ is_busy, 0 ] Commands: - incr: resources - reward: 1 @@ -198,12 +306,24 @@ Actions: Object: minerals Commands: - decr: resources + - lt: + Arguments: [resources, 10] + Commands: + - set_tile: 1 + - lt: + Arguments: [ resources, 5 ] + Commands: + - set_tile: 2 - eq: - Arguments: [resources, 0] + Arguments: [ resources, 0 ] Commands: - remove: true - Src: - Object: harvester + Object: worker + Preconditions: + - eq: [ is_busy, 0 ] + - gt: [ resources, 0 ] + - eq: [ src._playerId, dst._playerId ] Commands: - decr: resources - reward: 1 @@ -215,33 +335,56 @@ Actions: - Name: move Behaviours: - Src: - Object: [harvester, puncher, pusher, movable_wall] + Preconditions: + - eq: [ is_busy, 0 ] + Object: [ worker, combat, ranged ] Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: Object: _empty - Src: - Object: pusher + Object: ranged Commands: - mov: _dest # mov will move the object, _dest is the destination location of the action Dst: - Object: [movable_wall, harvester, puncher] + Object: [ movable_wall, worker, combat ] Commands: - cascade: _dest # reapply the same action to the dest location of the action - - Name: punch + # Name: ranged_attack + - Name: attack Behaviours: + + - Src: + Object: worker + Preconditions: + - neq: [ src._playerId, dst._playerId ] + - eq: [ is_busy, 0 ] + Commands: + - reward: 1 + Dst: + Object: [ base, combat, worker, ranged ] + Commands: + - sub: [ health, 1 ] + - eq: + Arguments: [ health, 0 ] + Commands: + - remove: true + - Src: - Object: puncher + Object: combat + Preconditions: + - neq: [ src._playerId, dst._playerId ] + - eq: [ is_busy, 0 ] Commands: - reward: 1 Dst: - Object: [puncher, harvester, pusher, base] + Object: [ base, combat, worker, ranged, barracks ] Commands: - - decr: health + - sub: [ health, 5 ] - eq: - Arguments: [0, health] + Arguments: [ 0, health ] Commands: - remove: true @@ -250,59 +393,67 @@ Objects: MapCharacter: M Variables: - Name: resources - InitialValue: 200 + InitialValue: 20 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_items/tg_items_crystal_green.png Block2D: - Shape: triangle - Color: [0.0, 1.0, 0.0] + Color: [ 0.0, 1.0, 0.0 ] Scale: 1.0 Isometric: - - Image: oryx/oryx_iso_dungeon/minerals-1.png + - Image: oryx/oryx_iso_dungeon/minerals-1-0.png + - Image: oryx/oryx_iso_dungeon/minerals-1-1.png + - Image: oryx/oryx_iso_dungeon/minerals-1-2.png - - Name: harvester + - Name: worker MapCharacter: H Variables: - Name: resources InitialValue: 0 - Name: health InitialValue: 10 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_jelly_d1.png Block2D: - Shape: square - Color: [0.6, 0.2, 0.2] + Color: [ 0.6, 0.2, 0.2 ] Scale: 0.5 Isometric: - Image: oryx/oryx_iso_dungeon/jelly-1.png - - Name: pusher - MapCharacter: P + - Name: ranged + MapCharacter: r Variables: - Name: health - InitialValue: 10 + InitialValue: 20 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_crawler_queen_d1.png Block2D: - Shape: square - Color: [0.2, 0.2, 0.6] + Color: [ 0.2, 0.2, 0.6 ] Scale: 1.0 Isometric: - Image: oryx/oryx_iso_dungeon/queen-1.png - - Name: puncher - MapCharacter: p + - Name: combat + MapCharacter: c Variables: - Name: health - InitialValue: 5 + InitialValue: 30 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_beast_d1.png Block2D: - - Color: [0.2, 0.6, 0.6] + - Color: [ 0.2, 0.6, 0.6 ] Shape: square Scale: 0.8 Isometric: @@ -317,7 +468,7 @@ Objects: - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img33.png - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img40.png Block2D: - - Color: [0.5, 0.5, 0.5] + - Color: [ 0.5, 0.5, 0.5 ] Shape: square Isometric: - Image: oryx/oryx_iso_dungeon/wall-grey-1.png @@ -328,21 +479,59 @@ Objects: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img282.png Block2D: - - Color: [0.8, 0.8, 0.8] + - Color: [ 0.8, 0.8, 0.8 ] Shape: square Isometric: - Image: oryx/oryx_iso_dungeon/crate-1.png - Name: base - MapCharacter: B + MapCharacter: A Variables: - Name: health - InitialValue: 10 + InitialValue: 50 + - Name: is_busy + InitialValue: 0 Observers: Sprite2D: - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img324.png Block2D: - - Color: [0.8, 0.8, 0.3] + - Color: [ 0.8, 0.8, 0.3 ] Shape: triangle Isometric: - Image: oryx/oryx_iso_dungeon/base-1.png + + - Name: barracks_disabled + MapCharacter: b + InitialActions: + - Action: construct_barracks + Delay: 20 + Variables: + - Name: health + InitialValue: 20 + - Name: is_busy + InitialValue: 1 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img280.png + Block2D: + - Color: [ 0.3, 0.3, 0.3 ] + Shape: triangle + Size: 0.5 + Isometric: + - Image: oryx/oryx_iso_dungeon/barracks-disabled-1.png + + - Name: barracks + MapCharacter: B + Variables: + - Name: health + InitialValue: 40 + - Name: is_busy + InitialValue: 0 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img320.png + Block2D: + - Color: [ 0.8, 0.3, 0.8 ] + Shape: triangle + Isometric: + - Image: oryx/oryx_iso_dungeon/barracks-1.png diff --git a/resources/gdy-schema.json b/resources/gdy-schema.json index f7fd9b96d..84c4c4903 100644 --- a/resources/gdy-schema.json +++ b/resources/gdy-schema.json @@ -304,92 +304,192 @@ "properties": { "Lose": { "$id": "#/properties/Environment/properties/Termination/properties/Lose", - "type": "array", "title": "Lose Conditions", "description": "If any of these conditions are met, the player associated with this condition will lose the game.", - "additionalItems": false, - "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition" - } + "oneOf": [ + { + "type": "array", + "title": "V1 Termination Conditions", + "description": "V1 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1" + } + }, + { + "type": "array", + "title": "V2 Termination Conditions", + "description": "V2 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2" + } + } + ] }, "Win": { "$id": "#/properties/Environment/properties/Termination/properties/Win", - "type": "array", "title": "Win Conditions", "description": "If any of these conditions are met, the player associated with this condition will win the game.", "additionalItems": false, - "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition" - } + "oneOf": [ + { + "type": "array", + "title": "V1 Termination Conditions", + "description": "V1 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1" + } + }, + { + "type": "array", + "title": "V2 Termination Conditions", + "description": "V2 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2" + } + } + ] }, "End": { "$id": "#/properties/Environment/properties/Termination/properties/End", - "type": "array", "title": "End Conditions", "description": "If any of these conditions are met, the game will end.", "additionalItems": false, - "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition" - } + "oneOf": [ + { + "type": "array", + "title": "V1 Termination Conditions", + "description": "V1 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1" + } + }, + { + "type": "array", + "title": "V2 Termination Conditions", + "description": "V2 Termination Conditions", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2" + } + } + ] } }, "definitions": { - "terminationCondition": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition", + "terminationConditionV2": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2", "type": "object", - "title": "Termination Conditions", + "title": "Termination Conditions V2", + "description": "When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally \"per player\". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score", + "additionalProperties": false, + "properties": { + "Conditions": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Conditions", + "type": "array", + "title": "Conditions", + "description": "If any of these conditions are met, the game will end and distribute rewards to the associated players.", + "additionalItems": false, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1" + } + }, + "Reward": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/Reward", + "type": "integer", + "title": "Reward", + "description": "The reward given to the agent if this conditions is met." + }, + "OpposingReward": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV2/properties/OpposingReward", + "type": "integer", + "title": "Opposing Reward", + "description": "The reward given to other agents if this condition is met." + } + } + }, + "terminationConditionV1": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1", + "type": "object", + "title": "Termination Conditions V1", "description": "When a termination condition is met, the game will reset itself. If there are multiple players, the termination arguments are expanded internally \"per player\". This can be used to find the first player to a certain number of objects, or the first player to reach a certain score", "maxProperties": 1, "additionalProperties": false, "properties": { "eq": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition/properties/eq", + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/eq", "type": "array", "title": "Equals", "description": "Check if the arguments are equal", "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition/definitions/terminationArgument" + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" } }, "neq": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition/properties/neq", + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/neq", "type": "array", "title": "Not Equals", "description": "Check if the arguments are not equal", "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition/definitions/terminationArgument" + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" } }, "gt": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition/properties/gt", + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gt", "type": "array", "title": "Greater Than", "description": "Check if the first argument is greater than the second", "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition/definitions/terminationArgument" + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" + } + }, + "gte": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/gte", + "type": "array", + "title": "Greater Than Or Equal", + "description": "Check if the first argument is greater than or equal to the second", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" } }, "lt": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition/properties/lt", + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lt", "type": "array", "title": "Less Than", "description": "Check if the first argument is less than the second", "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/properties/Environment/properties/Termination/definitions/terminationCondition/definitions/terminationArgument" + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" + } + }, + "lte": { + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/properties/lte", + "type": "array", + "title": "Less Than Or Equal", + "description": "Check if the first argument is less than or equal to the second", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument" } } }, "definitions": { "terminationArgument": { - "$id": "#/properties/Environment/properties/Termination/definitions/terminationCondition/definitions/terminationArgument", + "$id": "#/properties/Environment/properties/Termination/definitions/terminationConditionV1/definitions/terminationArgument", "description": "An argument to the termination condition. If there are multiple players, then these arguments expand internally as \"per player\"", "title": "Termination Arguments", "oneOf": [ @@ -672,6 +772,17 @@ "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgument" } }, + "gte": { + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/gte", + "type": "array", + "title": "Greater Than Or Equal", + "description": "Check if the first argument is greater than or equal to the second", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgument" + } + }, "lt": { "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lt", "type": "array", @@ -682,6 +793,17 @@ "items": { "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgument" } + }, + "lte": { + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionPreconditionCommand/properties/lte", + "type": "array", + "title": "Less Than Or Equal", + "description": "Check if the first argument is less than or equal to the second", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgument" + } } } }, @@ -709,7 +831,7 @@ } }, "lt": { - "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt", + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt", "type": "object", "title": "Less Than", "description": "The specified commands will only be run if the value of the first argument is less than the second.", @@ -724,8 +846,24 @@ } } }, + "lte": { + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lte", + "type": "object", + "title": "Less Than Or Equal", + "description": "The specified commands will only be run if the value of the first argument is less than or equal to the second.", + "minItems": 2, + "maxItems": 2, + "properties": { + "Arguments": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgumentList" + }, + "Commands": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommandList" + } + } + }, "gt": { - "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/lt", + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gt", "type": "object", "title": "Greater Than", "description": "The specified commands will only be run if the value of the first argument is greater than the second.", @@ -737,6 +875,20 @@ "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommandList" } } + }, + "gte": { + "$id": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommand/properties/gte", + "type": "object", + "title": "Greater Than Or Equal", + "description": "The specified commands will only be run if the value of the first argument is greater than or equal to the second.", + "properties": { + "Arguments": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/commandArgument" + }, + "Commands": { + "$ref": "#/properties/Actions/items/properties/Behaviours/definitions/behaviourDefinitionConditionalCommandList" + } + } } } }, diff --git a/resources/images/oryx/oryx_iso_dungeon/barracks-1.png b/resources/images/oryx/oryx_iso_dungeon/barracks-1.png new file mode 100644 index 000000000..8a4f259da Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/barracks-1.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/barracks-disabled-1.png b/resources/images/oryx/oryx_iso_dungeon/barracks-disabled-1.png new file mode 100644 index 000000000..37de3a3c5 Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/barracks-disabled-1.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/base-1.png b/resources/images/oryx/oryx_iso_dungeon/base-1.png index e266316d1..6c56c8bc2 100644 Binary files a/resources/images/oryx/oryx_iso_dungeon/base-1.png and b/resources/images/oryx/oryx_iso_dungeon/base-1.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/base-disabled-1.png b/resources/images/oryx/oryx_iso_dungeon/base-disabled-1.png new file mode 100644 index 000000000..192aa1765 Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/base-disabled-1.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/minerals-1-0.png b/resources/images/oryx/oryx_iso_dungeon/minerals-1-0.png new file mode 100644 index 000000000..6a37fd917 Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/minerals-1-0.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/minerals-1-1.png b/resources/images/oryx/oryx_iso_dungeon/minerals-1-1.png new file mode 100644 index 000000000..e6bd686ac Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/minerals-1-1.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/minerals-1-2.png b/resources/images/oryx/oryx_iso_dungeon/minerals-1-2.png new file mode 100644 index 000000000..0b121e8fb Binary files /dev/null and b/resources/images/oryx/oryx_iso_dungeon/minerals-1-2.png differ diff --git a/resources/images/oryx/oryx_iso_dungeon/minerals-1.png b/resources/images/oryx/oryx_iso_dungeon/minerals-1.png deleted file mode 100644 index 28a8aae66..000000000 Binary files a/resources/images/oryx/oryx_iso_dungeon/minerals-1.png and /dev/null differ diff --git a/src/Griddly/Core/GDY/GDYFactory.cpp b/src/Griddly/Core/GDY/GDYFactory.cpp index f343b3ab5..7eecf7b7d 100644 --- a/src/Griddly/Core/GDY/GDYFactory.cpp +++ b/src/Griddly/Core/GDY/GDYFactory.cpp @@ -236,6 +236,41 @@ YAML::iterator GDYFactory::validateCommandPairNode(YAML::Node commandPairNodeLis return commandPairNodeList.begin(); } +void GDYFactory::parseTerminationConditionV1(TerminationState state, YAML::Node conditionNode) { + for (std::size_t c = 0; c < conditionNode.size(); c++) { + auto commandIt = validateCommandPairNode(conditionNode[c]); + auto commandName = commandIt->first.as(); + auto commandArguments = singleOrListNodeToList(commandIt->second); + + terminationGenerator_->defineTerminationCondition(state, commandName, 0, 0, commandArguments); + } +} + +bool GDYFactory::parseTerminationConditionV2(TerminationState state, YAML::Node conditionListNode) { + for (std::size_t c = 0; c < conditionListNode.size(); c++) { + auto conditionNode = conditionListNode[c]["Conditions"]; + if (!conditionNode.IsDefined()) { + return false; + } + + auto rewardNode = conditionListNode[c]["Reward"]; + auto opposingRewardNode = conditionListNode[c]["OpposingReward"]; + + auto reward = rewardNode.as(0); + auto opposingReward = opposingRewardNode.as(0); + + for (std::size_t c = 0; c < conditionNode.size(); c++) { + auto commandIt = validateCommandPairNode(conditionNode[c]); + auto commandName = commandIt->first.as(); + auto commandArguments = singleOrListNodeToList(commandIt->second); + + terminationGenerator_->defineTerminationCondition(state, commandName, reward, opposingReward, commandArguments); + } + } + + return true; +} + void GDYFactory::parseTerminationConditions(YAML::Node terminationNode) { if (!terminationNode.IsDefined()) { return; @@ -243,43 +278,31 @@ void GDYFactory::parseTerminationConditions(YAML::Node terminationNode) { auto winNode = terminationNode["Win"]; if (winNode.IsDefined()) { - spdlog::debug("Parsing win conditions."); - for (std::size_t c = 0; c < winNode.size(); c++) { - auto commandIt = validateCommandPairNode(winNode[c]); - auto commandName = commandIt->first.as(); - auto commandArguments = singleOrListNodeToList(commandIt->second); - - terminationGenerator_->defineTerminationCondition(TerminationState::WIN, commandName, commandArguments); + spdlog::debug("Parsing win conditions"); + if (!parseTerminationConditionV2(TerminationState::WIN, winNode)) { + parseTerminationConditionV1(TerminationState::WIN, winNode); } } auto loseNode = terminationNode["Lose"]; if (loseNode.IsDefined()) { spdlog::debug("Parsing lose conditions."); - for (std::size_t c = 0; c < loseNode.size(); c++) { - auto commandIt = validateCommandPairNode(loseNode[c]); - auto commandName = commandIt->first.as(); - auto commandArguments = singleOrListNodeToList(commandIt->second); - - terminationGenerator_->defineTerminationCondition(TerminationState::LOSE, commandName, commandArguments); + if (!parseTerminationConditionV2(TerminationState::LOSE, loseNode)) { + parseTerminationConditionV1(TerminationState::LOSE, loseNode); } } auto endNode = terminationNode["End"]; if (endNode.IsDefined()) { spdlog::debug("Parsing end conditions."); - for (std::size_t c = 0; c < endNode.size(); c++) { - auto commandIt = validateCommandPairNode(endNode[c]); - auto commandName = commandIt->first.as(); - auto commandArguments = singleOrListNodeToList(commandIt->second); - - terminationGenerator_->defineTerminationCondition(TerminationState::NONE, commandName, commandArguments); + if (!parseTerminationConditionV2(TerminationState::NONE, endNode)) { + parseTerminationConditionV1(TerminationState::NONE, endNode); } } } void GDYFactory::setMaxSteps(uint32_t maxSteps) { - terminationGenerator_->defineTerminationCondition(TerminationState::LOSE, "gt", {"_steps", std::to_string(maxSteps)}); + terminationGenerator_->defineTerminationCondition(TerminationState::LOSE, "gt", 0, 0, {"_steps", std::to_string(maxSteps)}); } void GDYFactory::parseGlobalVariables(YAML::Node variablesNode) { diff --git a/src/Griddly/Core/GDY/GDYFactory.hpp b/src/Griddly/Core/GDY/GDYFactory.hpp index 7ce748447..b7b936995 100644 --- a/src/Griddly/Core/GDY/GDYFactory.hpp +++ b/src/Griddly/Core/GDY/GDYFactory.hpp @@ -85,6 +85,9 @@ class GDYFactory { void parseGlobalVariables(YAML::Node variablesNode); + bool parseTerminationConditionV2(TerminationState state, YAML::Node conditionNode); + void parseTerminationConditionV1(TerminationState state, YAML::Node conditionNode); + void parseTerminationConditions(YAML::Node terminationNode); void parseIsometricSpriteObserverConfig(YAML::Node observerConfigNode); diff --git a/src/Griddly/Core/GDY/Objects/Object.cpp b/src/Griddly/Core/GDY/Objects/Object.cpp index a6b417686..69b994610 100644 --- a/src/Griddly/Core/GDY/Objects/Object.cpp +++ b/src/Griddly/Core/GDY/Objects/Object.cpp @@ -124,8 +124,12 @@ PreconditionFunction Object::instantiatePrecondition(std::string commandName, Be condition = [](int32_t a, int32_t b) { return a == b; }; } else if (commandName == "gt") { condition = [](int32_t a, int32_t b) { return a > b; }; + } else if (commandName == "gte") { + condition = [](int32_t a, int32_t b) { return a >= b; }; } else if (commandName == "lt") { condition = [](int32_t a, int32_t b) { return a < b; }; + } else if (commandName == "lte") { + condition = [](int32_t a, int32_t b) { return a <= b; }; } else if (commandName == "neq") { condition = [](int32_t a, int32_t b) { return a != b; }; } else { @@ -152,8 +156,12 @@ BehaviourFunction Object::instantiateConditionalBehaviour(std::string commandNam condition = [](int32_t a, int32_t b) { return a == b; }; } else if (commandName == "gt") { condition = [](int32_t a, int32_t b) { return a > b; }; + } else if (commandName == "gte") { + condition = [](int32_t a, int32_t b) { return a >= b; }; } else if (commandName == "lt") { condition = [](int32_t a, int32_t b) { return a < b; }; + } else if (commandName == "lte") { + condition = [](int32_t a, int32_t b) { return a <= b; }; } else if (commandName == "neq") { condition = [](int32_t a, int32_t b) { return a != b; }; } else { @@ -204,8 +212,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou if (commandName == "reward") { auto value = commandArguments["0"].as(0); return [this, value](std::shared_ptr action) -> BehaviourResult { - - // if the object has a player Id, the reward will be given to that object's player, + // if the object has a player Id, the reward will be given to that object's player, // otherwise the reward will be given to the player which has performed the action auto rewardPlayer = getPlayerId() == 0 ? action->getOriginatingPlayerId() : getPlayerId(); @@ -238,6 +245,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou auto b = variablePointers["1"]; return [this, a, b](std::shared_ptr action) -> BehaviourResult { *a->resolve_ptr(action) += b->resolve(action); + grid_->invalidateLocation(getLocation()); return {}; }; } @@ -248,6 +256,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou auto b = variablePointers["1"]; return [this, a, b](std::shared_ptr action) -> BehaviourResult { *a->resolve_ptr(action) -= b->resolve(action); + grid_->invalidateLocation(getLocation()); return {}; }; } @@ -259,7 +268,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou return [this, a, b](std::shared_ptr action) -> BehaviourResult { spdlog::debug("set"); *a->resolve_ptr(action) = b->resolve(action); - + grid_->invalidateLocation(getLocation()); return {}; }; } @@ -270,7 +279,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou return [this, a](std::shared_ptr action) -> BehaviourResult { spdlog::debug("incr"); (*a->resolve_ptr(action)) += 1; - + grid_->invalidateLocation(getLocation()); return {}; }; } @@ -281,7 +290,7 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou return [this, a](std::shared_ptr action) -> BehaviourResult { spdlog::debug("decr"); (*a->resolve_ptr(action)) -= 1; - + grid_->invalidateLocation(getLocation()); return {}; }; } @@ -367,7 +376,6 @@ BehaviourFunction Object::instantiateBehaviour(std::string commandName, Behaviou // Resolve source object return [this, actionName, delay, randomize, actionId, actionExecutor](std::shared_ptr action) -> BehaviourResult { - InputMapping fallbackInputMapping; fallbackInputMapping.vectorToDest = action->getVectorToDest(); fallbackInputMapping.orientationVector = action->getOrientationVector(); @@ -468,7 +476,23 @@ void Object::addActionDstBehaviour( bool Object::isValidAction(std::shared_ptr action) const { auto actionName = action->getActionName(); auto destinationObject = action->getDestinationObject(); - auto destinationObjectName = destinationObject == nullptr ? "_empty" : destinationObject->getObjectName(); + + std::string destinationObjectName; + if (destinationObject == nullptr) { + auto width = grid_->getWidth(); + auto height = grid_->getHeight(); + + // Check that the destination of the action is not outside the grid + auto destinationLocation = action->getDestinationLocation(); + if (destinationLocation.x >= width || destinationLocation.x < 0 || + destinationLocation.y >= height || destinationLocation.y < 0) { + return false; + } + + destinationObjectName = "_empty"; + } else { + destinationObjectName = destinationObject->getObjectName(); + } spdlog::debug("Checking preconditions for action [{0}] -> {1} -> {2}", getObjectName(), actionName, destinationObjectName); diff --git a/src/Griddly/Core/GDY/TerminationGenerator.cpp b/src/Griddly/Core/GDY/TerminationGenerator.cpp index 7ab390b47..4f197e4ba 100644 --- a/src/Griddly/Core/GDY/TerminationGenerator.cpp +++ b/src/Griddly/Core/GDY/TerminationGenerator.cpp @@ -6,13 +6,15 @@ namespace griddly { -void TerminationGenerator::defineTerminationCondition(TerminationState state, std::string commandName, std::vector commandArguments) { +void TerminationGenerator::defineTerminationCondition(TerminationState state, std::string commandName, int32_t reward, int32_t opposingReward, std::vector commandArguments) { spdlog::debug("Adding termination condition definition {0} [{1}, {2}]", commandName, commandArguments[0], commandArguments[1]); TerminationConditionDefinition tcd; tcd.commandName = commandName; tcd.commandArguments = commandArguments; tcd.state = state; + tcd.reward = reward; + tcd.opposingReward = opposingReward; terminationConditionDefinitions_.push_back(tcd); } diff --git a/src/Griddly/Core/GDY/TerminationGenerator.hpp b/src/Griddly/Core/GDY/TerminationGenerator.hpp index 518c22032..9bd0c2744 100644 --- a/src/Griddly/Core/GDY/TerminationGenerator.hpp +++ b/src/Griddly/Core/GDY/TerminationGenerator.hpp @@ -13,7 +13,7 @@ class Player; class TerminationGenerator { public: - virtual void defineTerminationCondition(TerminationState state, std::string commandName, std::vector commandArguments); + virtual void defineTerminationCondition(TerminationState state, std::string commandName, int32_t reward, int32_t opposingReward, std::vector commandArguments); virtual std::shared_ptr newInstance(std::shared_ptr grid, std::vector> players); private: diff --git a/src/Griddly/Core/GDY/TerminationHandler.cpp b/src/Griddly/Core/GDY/TerminationHandler.cpp index 0eb152808..463fec8cb 100644 --- a/src/Griddly/Core/GDY/TerminationHandler.cpp +++ b/src/Griddly/Core/GDY/TerminationHandler.cpp @@ -27,7 +27,7 @@ TerminationHandler::TerminationHandler(std::shared_ptr grid, std::vector> variablePointers) { +TerminationFunction TerminationHandler::instantiateTerminationCondition(TerminationState state, std::string commandName, uint32_t playerId, int32_t reward, int32_t opposingReward, std::vector> variablePointers) { spdlog::debug("Adding termination condition={0} for player {1}", commandName, playerId); std::function condition; @@ -35,13 +35,19 @@ TerminationFunction TerminationHandler::instantiateTerminationCondition(Terminat condition = [](int32_t a, int32_t b) { return a == b; }; } else if (commandName == "gt") { condition = [](int32_t a, int32_t b) { return a > b; }; + } else if (commandName == "gte") { + condition = [](int32_t a, int32_t b) { return a >= b; }; } else if (commandName == "lt") { condition = [](int32_t a, int32_t b) { return a < b; }; + } else if (commandName == "lte") { + condition = [](int32_t a, int32_t b) { return a <= b; }; + } else if (commandName == "neq") { + condition = [](int32_t a, int32_t b) { return a != b; }; } else { throw std::invalid_argument(fmt::format("Unknown or badly defined condition command {0}.", commandName)); } - return [this, variablePointers, condition, playerId, state, commandName]() { + return [this, variablePointers, condition, playerId, state, reward, opposingReward, commandName]() { auto a = *(variablePointers[0]); auto b = *(variablePointers[1]); @@ -56,24 +62,27 @@ TerminationFunction TerminationHandler::instantiateTerminationCondition(Terminat } std::unordered_map playerTerminationStates; + std::unordered_map playerTerminationRewards; for (auto p : players_) { auto pid = p->getId(); if (pid == playerId || state == TerminationState::NONE) { playerTerminationStates[pid] = state; + playerTerminationRewards[pid] = state == TerminationState::NONE ? 0 : reward; } else { playerTerminationStates[pid] = oppositeState; + playerTerminationRewards[pid] = oppositeState == TerminationState::NONE ? 0 :opposingReward; } } return TerminationResult{ - true, playerTerminationStates}; + true, playerTerminationRewards, playerTerminationStates}; } return TerminationResult(); }; } -void TerminationHandler::resolveTerminationConditions(TerminationState state, std::string commandName, std::vector terminationVariables) { +void TerminationHandler::resolveTerminationConditions(TerminationState state, std::string commandName, int32_t reward, int32_t opposingReward, std::vector terminationVariables) { // Termination variables grows with the number of players in the game auto resolvedVariableSets = findVariables(terminationVariables); @@ -99,7 +108,7 @@ void TerminationHandler::resolveTerminationConditions(TerminationState state, st if(conditionArguments.size() > 1 && playerId == 0) { continue; } - terminationFunctions_.push_back(instantiateTerminationCondition(state, commandName, playerId, resolvedVariables)); + terminationFunctions_.push_back(instantiateTerminationCondition(state, commandName, playerId, reward, opposingReward, resolvedVariables)); } } @@ -107,8 +116,10 @@ void TerminationHandler::addTerminationCondition(TerminationConditionDefinition auto terminationState = terminationConditionDefinition.state; auto commandName = terminationConditionDefinition.commandName; auto commandArguments = terminationConditionDefinition.commandArguments; + auto reward = terminationConditionDefinition.reward; + auto opposingReward = terminationConditionDefinition.opposingReward; - resolveTerminationConditions(terminationState, commandName, commandArguments); + resolveTerminationConditions(terminationState, commandName, reward, opposingReward, commandArguments); } std::vector>> TerminationHandler::findVariables(std::vector variableArgs) { diff --git a/src/Griddly/Core/GDY/TerminationHandler.hpp b/src/Griddly/Core/GDY/TerminationHandler.hpp index 139326f30..b5a135aff 100644 --- a/src/Griddly/Core/GDY/TerminationHandler.hpp +++ b/src/Griddly/Core/GDY/TerminationHandler.hpp @@ -20,12 +20,15 @@ enum class TerminationState { struct TerminationResult { bool terminated = false; + std::unordered_map rewards; std::unordered_map playerStates; }; struct TerminationConditionDefinition { TerminationState state = TerminationState::NONE; std::string commandName; + int32_t reward; + int32_t opposingReward; std::vector commandArguments; }; @@ -38,8 +41,8 @@ class TerminationHandler { virtual void addTerminationCondition(TerminationConditionDefinition terminationConditionDefinition); private: - TerminationFunction instantiateTerminationCondition(TerminationState state, std::string commandName, uint32_t playerId, std::vector> variablePointers); - void resolveTerminationConditions(TerminationState state, std::string commandName, std::vector terminationVariables); + TerminationFunction instantiateTerminationCondition(TerminationState state, std::string commandName, uint32_t playerId, int32_t reward, int32_t opposingReward, std::vector> variablePointers); + void resolveTerminationConditions(TerminationState state, std::string commandName, int32_t reward, int32_t opposingReward, std::vector terminationVariables); std::vector>> findVariables(std::vector variables); std::vector terminationFunctions_; diff --git a/src/Griddly/Core/GameProcess.cpp b/src/Griddly/Core/GameProcess.cpp index 4c4ec8e23..17b4e202c 100644 --- a/src/Griddly/Core/GameProcess.cpp +++ b/src/Griddly/Core/GameProcess.cpp @@ -124,7 +124,7 @@ void GameProcess::init(bool isCloned) { isInitialized_ = true; } -uint8_t* GameProcess::resetObservers() { +void GameProcess::resetObservers() { auto playerAvatarObjects = grid_->getPlayerAvatarObjects(); for (auto& p : players_) { @@ -135,19 +135,16 @@ uint8_t* GameProcess::resetObservers() { } } - if (observer_ == nullptr) { - return nullptr; + if(observer_ != nullptr) { + observer_->reset(); } - - return observer_->reset(); } -uint8_t* GameProcess::reset() { +void GameProcess::reset() { if (!isInitialized_) { throw std::runtime_error("Cannot reset game process before initialization."); } - spdlog::debug("Resetting player count."); grid_->setPlayerCount(gdyFactory_->getPlayerCount()); @@ -158,14 +155,12 @@ uint8_t* GameProcess::reset() { levelGenerator_->reset(grid_); spdlog::debug("Resetting Observers."); - auto observation = resetObservers(); + resetObservers(); spdlog::debug("Resetting Termination Handler."); terminationHandler_ = std::shared_ptr(gdyFactory_->createTerminationHandler(grid_, players_)); requiresReset_ = false; - - return observation; } ObserverConfig GameProcess::getObserverConfig(ObserverType observerType) const { @@ -219,6 +214,12 @@ std::shared_ptr GameProcess::getObserver() { return observer_; } +int32_t GameProcess::getAccumulatedRewards(uint32_t playerId) { + int32_t reward = accumulatedRewards_[playerId]; + accumulatedRewards_[playerId] = 0; + return reward; +} + std::unordered_map> GameProcess::getAvailableActionNames(uint32_t playerId) const { std::unordered_map> availableActionNames; diff --git a/src/Griddly/Core/GameProcess.hpp b/src/Griddly/Core/GameProcess.hpp index 0c68ecc11..9fda11877 100644 --- a/src/Griddly/Core/GameProcess.hpp +++ b/src/Griddly/Core/GameProcess.hpp @@ -15,7 +15,6 @@ class Player; struct ActionResult { std::unordered_map playerStates; bool terminated; - int32_t reward; }; struct ObjectInfo { @@ -50,10 +49,12 @@ class GameProcess : public std::enable_shared_from_this { virtual void init(bool isCloned=false); - virtual uint8_t* reset(); + virtual void reset(); bool isInitialized(); + virtual int32_t getAccumulatedRewards(uint32_t playerId); + virtual std::string getProcessName() const; std::shared_ptr getGrid(); @@ -97,8 +98,11 @@ class GameProcess : public std::enable_shared_from_this { // track whether this environment has finished or not, if it requires a reset, we can reset it bool requiresReset_ = true; + // Tracks the rewards currently accumulated per player + std::unordered_map accumulatedRewards_; + private: - uint8_t* resetObservers(); + void resetObservers(); ObserverConfig getObserverConfig(ObserverType observerType) const; diff --git a/src/Griddly/Core/Observers/BlockObserver.cpp b/src/Griddly/Core/Observers/BlockObserver.cpp index eb1704857..fb96b91e3 100644 --- a/src/Griddly/Core/Observers/BlockObserver.cpp +++ b/src/Griddly/Core/Observers/BlockObserver.cpp @@ -16,9 +16,9 @@ ObserverType BlockObserver::getObserverType() const { return ObserverType::BLOCK_2D; } -void BlockObserver::init(ObserverConfig observerConfig) { - VulkanGridObserver::init(observerConfig); - +void BlockObserver::lazyInit() { + VulkanObserver::lazyInit(); + device_->initRenderMode(vk::RenderMode::SHAPES); for (auto blockDef : blockDefinitions_) { diff --git a/src/Griddly/Core/Observers/BlockObserver.hpp b/src/Griddly/Core/Observers/BlockObserver.hpp index 6ab884683..f57204934 100644 --- a/src/Griddly/Core/Observers/BlockObserver.hpp +++ b/src/Griddly/Core/Observers/BlockObserver.hpp @@ -28,13 +28,12 @@ class BlockObserver : public VulkanGridObserver { virtual ObserverType getObserverType() const override; - void init(ObserverConfig observerConfig) override; - - private: void renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation renderOrientation) const override; std::unordered_map blockConfigs_; const std::unordered_map blockDefinitions_; + + void lazyInit() override; }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp index c0b3b7303..fba649ad9 100644 --- a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp +++ b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp @@ -33,7 +33,6 @@ void IsometricSpriteObserver::resetShape() { isoOriginOffset_ = {gridHeight_ * tileSize.x / 2, tileSize.y / 2}; observationShape_ = {3, pixelWidth_, pixelHeight_}; - observationStrides_ = {1, 4, 4 * pixelWidth_}; } std::vector IsometricSpriteObserver::calculateDirtyRectangles(std::unordered_set updatedLocations) const { diff --git a/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp b/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp index ed722f0c2..ce9fef069 100644 --- a/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp +++ b/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp @@ -24,6 +24,7 @@ class IsometricSpriteObserver : public SpriteObserver { private: glm::vec2 isoOriginOffset_; + }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/Observer.cpp b/src/Griddly/Core/Observers/Observer.cpp index 2ec6498de..e6f4ddf05 100644 --- a/src/Griddly/Core/Observers/Observer.cpp +++ b/src/Griddly/Core/Observers/Observer.cpp @@ -8,8 +8,27 @@ Observer::Observer(std::shared_ptr grid) : grid_(grid) { } void Observer::init(ObserverConfig observerConfig) { + + spdlog::debug("Initializing observer."); + + if (observerState_ != ObserverState::NONE) { + throw std::runtime_error("Cannot initialize an already initialized Observer"); + } + observerConfig_ = observerConfig; + observerState_ = ObserverState::INITIALISED; +} + +void Observer::reset() { + spdlog::debug("Resetting observer."); + if (observerState_ == ObserverState::NONE) { + throw std::runtime_error("Observer not initialized"); + } resetShape(); + + spdlog::debug("Observation Shape ({0}, {1}, {2})", observationShape_[0], observationShape_[1], observationShape_[2]); + + observerState_ = ObserverState::RESET; } void Observer::setAvatar(std::shared_ptr avatarObject) { diff --git a/src/Griddly/Core/Observers/Observer.hpp b/src/Griddly/Core/Observers/Observer.hpp index 6ee334d4a..5a6899cdc 100644 --- a/src/Griddly/Core/Observers/Observer.hpp +++ b/src/Griddly/Core/Observers/Observer.hpp @@ -38,6 +38,10 @@ enum class ObserverType { NONE, ISOMETRIC, VECTOR }; +enum class ObserverState { + NONE, INITIALISED, RESET, READY +}; + class Observer { public: Observer(std::shared_ptr grid); @@ -46,8 +50,8 @@ class Observer { * The data is returned as a byte array for consistency across observers and * interfaces */ - virtual uint8_t* update() const = 0; - virtual uint8_t* reset() = 0; + virtual uint8_t* update() = 0; + virtual void reset(); virtual std::vector getShape() const; virtual std::vector getStrides() const; @@ -81,5 +85,7 @@ class Observer { ObserverConfig observerConfig_; std::vector observationShape_; std::vector observationStrides_; + + ObserverState observerState_ = ObserverState::NONE; }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/SpriteObserver.cpp b/src/Griddly/Core/Observers/SpriteObserver.cpp index 12c684192..9acbe05b5 100644 --- a/src/Griddly/Core/Observers/SpriteObserver.cpp +++ b/src/Griddly/Core/Observers/SpriteObserver.cpp @@ -66,9 +66,8 @@ vk::SpriteData SpriteObserver::loadImage(std::string imageFilename) { return {std::move(spriteData), (uint32_t)outputWidth, (uint32_t)outputHeight, (uint32_t)4}; } -/** loads the sprites needed for rendering **/ -void SpriteObserver::init(ObserverConfig observerConfig) { - VulkanGridObserver::init(observerConfig); +void SpriteObserver::lazyInit() { + VulkanObserver::lazyInit(); device_->initRenderMode(vk::RenderMode::SPRITES); diff --git a/src/Griddly/Core/Observers/SpriteObserver.hpp b/src/Griddly/Core/Observers/SpriteObserver.hpp index 4dd6cee86..a6ca8aa3d 100644 --- a/src/Griddly/Core/Observers/SpriteObserver.hpp +++ b/src/Griddly/Core/Observers/SpriteObserver.hpp @@ -30,8 +30,6 @@ class SpriteObserver : public VulkanGridObserver { virtual ObserverType getObserverType() const override; - void init(ObserverConfig observerConfig) override; - protected: void renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation orientation) const override; void render(vk::VulkanRenderContext& ctx) const override; @@ -40,6 +38,8 @@ class SpriteObserver : public VulkanGridObserver { private: vk::SpriteData loadImage(std::string imageFilename); + + void lazyInit() override; }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/VectorObserver.cpp b/src/Griddly/Core/Observers/VectorObserver.cpp index 16f417391..83adfb91d 100644 --- a/src/Griddly/Core/Observers/VectorObserver.cpp +++ b/src/Griddly/Core/Observers/VectorObserver.cpp @@ -14,6 +14,13 @@ void VectorObserver::init(ObserverConfig observerConfig) { Observer::init(observerConfig); } +void VectorObserver::reset() { + Observer::reset(); + + // there are no additional steps until this observer can be used. + observerState_ = ObserverState::READY; +} + ObserverType VectorObserver::getObserverType() const { return ObserverType::VECTOR; } @@ -32,7 +39,6 @@ void VectorObserver::resetShape() { observationChannels_ = grid_->getObjectIds().size(); // Always in order objects, player, orientation, variables. - if (observerConfig_.includePlayerId) { channelsBeforePlayerCount_ = observationChannels_; observationChannels_ += observerConfig_.playerCount + 1; // additional one-hot for "no-player" @@ -60,11 +66,6 @@ void VectorObserver::resetShape() { trackAvatar_ = avatarObject_ != nullptr; } -uint8_t* VectorObserver::reset() { - resetShape(); - return update(); -}; - void VectorObserver::renderLocation(glm::ivec2 objectLocation, glm::ivec2 outputLocation, bool resetLocation) const { auto memPtr = observation_.get() + observationChannels_ * (gridWidth_ * outputLocation.y + outputLocation.x); @@ -143,7 +144,12 @@ void VectorObserver::renderLocation(glm::ivec2 objectLocation, glm::ivec2 output } } -uint8_t* VectorObserver::update() const { +uint8_t* VectorObserver::update() { + + if (observerState_ != ObserverState::READY) { + throw std::runtime_error("Observer not ready, must be initialized and reset before update() can be called."); + } + if (trackAvatar_) { auto avatarLocation = avatarObject_->getLocation(); auto avatarOrientation = avatarObject_->getObjectOrientation(); diff --git a/src/Griddly/Core/Observers/VectorObserver.hpp b/src/Griddly/Core/Observers/VectorObserver.hpp index 4d21dcd0c..9378e47ee 100644 --- a/src/Griddly/Core/Observers/VectorObserver.hpp +++ b/src/Griddly/Core/Observers/VectorObserver.hpp @@ -10,8 +10,8 @@ class VectorObserver : public Observer { void init(ObserverConfig observerConfig) override; - uint8_t* update() const override; - uint8_t* reset() override; + uint8_t* update() override; + void reset() override; void resetShape() override; ObserverType getObserverType() const override; diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp index a5cda36ac..8356c10cf 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp @@ -143,6 +143,12 @@ void VulkanDevice::initDevice(bool useGPU) { } else { spdlog::error("No devices supporting vulkan present for rendering."); } + + isInitialized_ = true; +} + +bool VulkanDevice::isInitialized() const { + return isInitialized_; } void VulkanDevice::initRenderMode(RenderMode mode) { @@ -188,6 +194,7 @@ std::vector VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint break; } + spdlog::debug("Render Surface Strides ({0}, {1}, {2}).", imageStrides[0],imageStrides[1],imageStrides[2]); return imageStrides; } diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp index e0382ab2f..cfe9d5575 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.hpp @@ -111,6 +111,8 @@ class VulkanDevice { uint8_t* endRender(VulkanRenderContext& renderContext, std::vector dirtyRectangles); + bool isInitialized() const; + private: std::vector getAvailablePhysicalDevices(); VulkanPhysicalDeviceInfo getPhysicalDeviceInfo(VkPhysicalDevice& device); @@ -206,5 +208,7 @@ class VulkanDevice { const glm::ivec2 tileSize_; const std::string shaderPath_; + + bool isInitialized_ = false; }; } // namespace vk \ No newline at end of file diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp index daadf8be7..d52ff6801 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.cpp @@ -18,9 +18,22 @@ VulkanObserver::VulkanObserver(std::shared_ptr grid, ResourceConfig resour VulkanObserver::~VulkanObserver() { } -void VulkanObserver::init(ObserverConfig observerConfig) { +/** + * Only load vulkan if update() called, allows many environments with vulkan-based global observers to be used. + * But only loads them if global observations are requested, for example for creating videos + * + * This a) allows significantly more enviroments to be loaded (if only one of them is being used to create videos) and b) + */ +void VulkanObserver::lazyInit() { + + if (observerState_ != ObserverState::RESET) { + throw std::runtime_error("Cannot initialize Vulkan Observer when it is not in RESET state."); + } + + spdlog::debug("Vulkan lazy initialization...."); + gridBoundary_ = glm::ivec2(grid_->getWidth(), grid_->getHeight()); - observerConfig_ = observerConfig; + auto imagePath = resourceConfig_.imagePath; auto shaderPath = resourceConfig_.shaderPath; @@ -29,31 +42,21 @@ void VulkanObserver::init(ObserverConfig observerConfig) { instance_ = std::shared_ptr(new vk::VulkanInstance(configuration)); } - std::unique_ptr vulkanDevice(new vk::VulkanDevice(instance_, observerConfig.tileSize, shaderPath)); + std::unique_ptr vulkanDevice(new vk::VulkanDevice(instance_, observerConfig_.tileSize, shaderPath)); device_ = std::move(vulkanDevice); - device_->initDevice(false); - resetShape(); } -uint8_t* VulkanObserver::reset() { - resetShape(); - resetRenderSurface(); - - auto ctx = device_->beginRender(); - - render(ctx); - - // Only update the rectangles that have changed to save bandwidth/processing speed - std::vector dirtyRectangles = { - {{0, 0}, - {pixelWidth_, pixelHeight_}}}; - - return device_->endRender(ctx, dirtyRectangles); -} +uint8_t* VulkanObserver::update() { + if (observerState_ == ObserverState::RESET) { + lazyInit(); + observerState_ = ObserverState::READY; + } else if(observerState_ != ObserverState::READY) { + throw std::runtime_error("Observer is not in READY state, cannot render"); + } + -uint8_t* VulkanObserver::update() const { auto ctx = device_->beginRender(); render(ctx); @@ -79,6 +82,17 @@ uint8_t* VulkanObserver::update() const { void VulkanObserver::resetRenderSurface() { spdlog::debug("Initializing Render Surface. Grid width={0}, height={1}. Pixel width={2}. height={3}", gridWidth_, gridHeight_, pixelWidth_, pixelHeight_); observationStrides_ = device_->resetRenderSurface(pixelWidth_, pixelHeight_); + + // On surface reset, render entire image contents. + // Subsequent calls to update, do fast diff updates. + auto ctx = device_->beginRender(); + render(ctx); + + std::vector dirtyRectangles = { + {{0, 0}, + {pixelWidth_, pixelHeight_}}}; + + device_->endRender(ctx, dirtyRectangles); } void VulkanObserver::release() { diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp index ee62763e2..dde339d10 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanObserver.hpp @@ -26,11 +26,8 @@ class VulkanObserver : public Observer { ~VulkanObserver(); void print(std::shared_ptr observation) override; - void init(ObserverConfig observerConfig) override; - - virtual uint8_t* update() const override; - virtual uint8_t* reset() override; + virtual uint8_t* update() override; void release() override; protected: @@ -45,6 +42,11 @@ class VulkanObserver : public Observer { uint32_t pixelWidth_; uint32_t pixelHeight_; + /** + * We dont actually want to initialize vulkan on the device unless observations are specifically requested for this environment + */ + virtual void lazyInit() = 0; + private: static std::shared_ptr instance_; }; diff --git a/src/Griddly/Core/Observers/VulkanGridObserver.cpp b/src/Griddly/Core/Observers/VulkanGridObserver.cpp index 4b126daa1..aaf20a366 100644 --- a/src/Griddly/Core/Observers/VulkanGridObserver.cpp +++ b/src/Griddly/Core/Observers/VulkanGridObserver.cpp @@ -16,6 +16,9 @@ VulkanGridObserver::~VulkanGridObserver() { } void VulkanGridObserver::resetShape() { + + spdlog::debug("Resetting grid observer shape."); + gridWidth_ = observerConfig_.overrideGridWidth > 0 ? observerConfig_.overrideGridWidth : grid_->getWidth(); gridHeight_ = observerConfig_.overrideGridHeight > 0 ? observerConfig_.overrideGridHeight : grid_->getHeight(); diff --git a/src/Griddly/Core/Players/Player.cpp b/src/Griddly/Core/Players/Player.cpp index ead9e22cc..e6d51af77 100644 --- a/src/Griddly/Core/Players/Player.cpp +++ b/src/Griddly/Core/Players/Player.cpp @@ -47,7 +47,7 @@ void Player::reset() { void Player::setAvatar(std::shared_ptr avatarObject) { avatarObject_ = avatarObject; - if(observerTracksAvatar_) { + if (observerTracksAvatar_) { observer_->setAvatar(avatarObject); } } @@ -65,12 +65,7 @@ std::shared_ptr Player::getObserver() const { } ActionResult Player::performActions(std::vector> actions, bool updateTicks) { - auto actionResult = gameProcess_->performActions(id_, actions, updateTicks); - - // Update the player's score - *score_ += actionResult.reward; - - return actionResult; + return gameProcess_->performActions(id_, actions, updateTicks); } uint8_t* Player::observe() { diff --git a/src/Griddly/Core/TurnBasedGameProcess.cpp b/src/Griddly/Core/TurnBasedGameProcess.cpp index 0f8e039e4..eca4e6635 100644 --- a/src/Griddly/Core/TurnBasedGameProcess.cpp +++ b/src/Griddly/Core/TurnBasedGameProcess.cpp @@ -22,16 +22,17 @@ TurnBasedGameProcess::~TurnBasedGameProcess() { ActionResult TurnBasedGameProcess::performActions(uint32_t playerId, std::vector> actions, bool updateTicks) { spdlog::debug("Performing turn based actions for player {0}", playerId); - if(requiresReset_) { + if (requiresReset_) { throw std::runtime_error("Environment is in a terminated state and requires resetting."); } std::unordered_map terminationState; - int32_t reward = 0; - auto stepRewards = grid_->performActions(playerId, actions); // rewards resulting from player actions + for (auto valueIt : stepRewards) { + spdlog::debug("Accumulating step reward for player {0}. {1} += {2}", valueIt.first, accumulatedRewards_[valueIt.first], valueIt.second); + } accumulateRewards(accumulatedRewards_, stepRewards); if (updateTicks) { @@ -39,6 +40,9 @@ ActionResult TurnBasedGameProcess::performActions(uint32_t playerId, std::vector auto delayedRewards = grid_->update(); // rewards could come from delayed actions that are run at a particular time step + for (auto valueIt : delayedRewards) { + spdlog::debug("Accumulating reward for player {0}. {1} += {2}", valueIt.first, accumulatedRewards_[valueIt.first], valueIt.second); + } accumulateRewards(accumulatedRewards_, delayedRewards); auto terminationResult = terminationHandler_->isTerminated(); @@ -46,18 +50,17 @@ ActionResult TurnBasedGameProcess::performActions(uint32_t playerId, std::vector terminationState = terminationResult.playerStates; requiresReset_ = terminationResult.terminated; + for (auto valueIt : terminationResult.rewards) { + spdlog::debug("Accumulating reward for player {0}. {1} += {2}", valueIt.first, accumulatedRewards_[valueIt.first], valueIt.second); + } + accumulateRewards(accumulatedRewards_, terminationResult.rewards); + if (requiresReset_ && autoReset_) { reset(); } } - if (accumulatedRewards_[playerId] != 0) { - reward = accumulatedRewards_[playerId]; - // reset reward for this player as they are being returned here - accumulatedRewards_[playerId] = 0; - } - - return {terminationState, requiresReset_, reward}; + return {terminationState, requiresReset_}; } // This is only used in tests diff --git a/src/Griddly/Core/TurnBasedGameProcess.hpp b/src/Griddly/Core/TurnBasedGameProcess.hpp index 1ee6fd0e5..376f75916 100644 --- a/src/Griddly/Core/TurnBasedGameProcess.hpp +++ b/src/Griddly/Core/TurnBasedGameProcess.hpp @@ -25,6 +25,5 @@ class TurnBasedGameProcess : public GameProcess { private: static const std::string name_; - std::unordered_map accumulatedRewards_; }; } // namespace griddly \ No newline at end of file diff --git a/tests/resources/loadEnvironment.yaml b/tests/resources/loadEnvironment.yaml index b0a15dd63..8e093a2c0 100644 --- a/tests/resources/loadEnvironment.yaml +++ b/tests/resources/loadEnvironment.yaml @@ -7,13 +7,6 @@ Environment: - Name: global_variable2 InitialValue: 0 PerPlayer: true - Termination: - Lose: - - eq: [base:count, 0] # If the player has no bases - Win: - - eq: [_score, 10] # Player wins if score get to this value - End: - - eq: [_steps, 100] # Max steps of 100 in this environment Player: Mode: SINGLE # MULTI, RTS Levels: diff --git a/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp b/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp index b90aa6134..4d324e727 100644 --- a/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp +++ b/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp @@ -46,18 +46,9 @@ TEST(GDYFactoryTest, loadEnvironment) { std::string objectName = "object"; - EXPECT_CALL(*mockObjectGeneratorPtr, getObjectNameFromMapChar) + EXPECT_CALL(*mockObjectGeneratorPtr, getObjectNameFromMapChar(Eq('W'))) .WillRepeatedly(ReturnRef(objectName)); - EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::LOSE), Eq("eq"), Eq(std::vector{"base:count", "0"}))) - .Times(1); - - EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::WIN), Eq("eq"), Eq(std::vector{"_score", "10"}))) - .Times(1); - - EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::NONE), Eq("eq"), Eq(std::vector{"_steps", "100"}))) - .Times(1); - gdyFactory->loadEnvironment(environmentNode); ASSERT_EQ(gdyFactory->getName(), "Test Environment"); @@ -73,7 +64,6 @@ TEST(GDYFactoryTest, loadEnvironment) { EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockObjectGeneratorPtr.get())); } - TEST(GDYFactoryTest, loadEnvironment_VectorObserverConfig_playerId) { auto mockObjectGeneratorPtr = std::shared_ptr(new MockObjectGenerator()); auto mockTerminationGeneratorPtr = std::shared_ptr(new MockTerminationGenerator()); @@ -186,7 +176,7 @@ TEST(GDYFactoryTest, loadEnvironment_VectorObserverConfig_playerId_rotation_vari ASSERT_EQ(gdyFactory->getName(), "Test"); ASSERT_EQ(gdyFactory->getLevelCount(), 0); -auto config = gdyFactory->getVectorObserverConfig(); + auto config = gdyFactory->getVectorObserverConfig(); ASSERT_EQ(config.includePlayerId, true); ASSERT_EQ(config.includeRotation, true); @@ -354,6 +344,94 @@ TEST(GDYFactoryTest, loadEnvironment_ObserverNoAvatar) { EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockObjectGeneratorPtr.get())); } +TEST(GDYFactoryTest, loadEnvironment_termination_v1) { + //auto mockObjectGeneratorPtr = std::shared_ptr(new MockObjectGenerator()); + auto mockTerminationGeneratorPtr = std::shared_ptr(new MockTerminationGenerator()); + auto gdyFactory = std::shared_ptr(new GDYFactory(nullptr, mockTerminationGeneratorPtr, {})); + auto yamlString = R"( + Environment: + Name: Test + Termination: + Lose: + - eq: [var1, -10] + - eq: [var2, -10] + Win: + - gt: [var2, 10] + End: + - lt: [var3, -1] +)"; + + auto environmentNode = loadFromStringAndGetNode(std::string(yamlString), "Environment"); + + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::LOSE), Eq("eq"), Eq(0), Eq(0), Eq(std::vector{"var1", "-10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::LOSE), Eq("eq"), Eq(0), Eq(0), Eq(std::vector{"var2", "-10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::WIN), Eq("gt"), Eq(0), Eq(0), Eq(std::vector{"var2", "10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::NONE), Eq("lt"), Eq(0), Eq(0), Eq(std::vector{"var3", "-1"}))) + .Times(1); + + gdyFactory->loadEnvironment(environmentNode); + + EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockTerminationGeneratorPtr.get())); +} + +TEST(GDYFactoryTest, loadEnvironment_termination_v2) { + //auto mockObjectGeneratorPtr = std::shared_ptr(new MockObjectGenerator()); + auto mockTerminationGeneratorPtr = std::shared_ptr(new MockTerminationGenerator()); + auto gdyFactory = std::shared_ptr(new GDYFactory(nullptr, mockTerminationGeneratorPtr, {})); + auto yamlString = R"( + Environment: + Name: Test + Termination: + Lose: + - Conditions: + - eq: [var1, -10] + Reward: -5 + OpposingReward: 5 + - Conditions: + - eq: [var2, -10] + Reward: -15 + OpposingReward: 15 + Win: + - Conditions: + - gte: [var2, -10] + Reward: 15 + OpposingReward: -15 + - Conditions: + - gt: [var2, 10] + End: + - Conditions: + - eq: [var1, -10] + Reward: -5 + OpposingReward: 5 + - Conditions: + - lt: [var3, -1] +)"; + + auto environmentNode = loadFromStringAndGetNode(std::string(yamlString), "Environment"); + + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::LOSE), Eq("eq"), Eq(-5), Eq(5), Eq(std::vector{"var1", "-10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::LOSE), Eq("eq"), Eq(-15), Eq(15), Eq(std::vector{"var2", "-10"}))) + .Times(1); + + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::WIN), Eq("gte"), Eq(15), Eq(-15), Eq(std::vector{"var2", "-10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::WIN), Eq("gt"), Eq(0), Eq(0), Eq(std::vector{"var2", "10"}))) + .Times(1); + + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::NONE), Eq("eq"), Eq(-5), Eq(5), Eq(std::vector{"var1", "-10"}))) + .Times(1); + EXPECT_CALL(*mockTerminationGeneratorPtr, defineTerminationCondition(Eq(TerminationState::NONE), Eq("lt"), Eq(0), Eq(0), Eq(std::vector{"var3", "-1"}))) + .Times(1); + + gdyFactory->loadEnvironment(environmentNode); + + EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockTerminationGeneratorPtr.get())); +} + TEST(GDYFactoryTest, loadObjects) { auto mockObjectGeneratorPtr = std::shared_ptr(new MockObjectGenerator()); auto mockTerminationGeneratorPtr = std::shared_ptr(new MockTerminationGenerator()); @@ -793,8 +871,6 @@ MATCHER_P(InputMappingMatcherEq, expectedActionInputsDefinitions, "") { if (expectedInputMapping.description != actualInputMapping.description) { return false; } - - } } @@ -897,10 +973,7 @@ TEST(GDYFactoryTest, action_input_map_to_grid) { gdyFactory->loadActions(actionsNode); std::unordered_map expectedInputMappings{ - {"spawn", {{}, - false, - false, - true}}}; + {"spawn", {{}, false, false, true}}}; ASSERT_THAT(gdyFactory->getActionInputsDefinitions(), InputMappingMatcherEq(expectedInputMappings)); } @@ -980,6 +1053,6 @@ TEST(GDYFactoryTest, action_input_internal_mapping) { true}}}; ASSERT_THAT(gdyFactory->getActionInputsDefinitions(), InputMappingMatcherEq(expectedInputMappings)); -} // namespace griddly +} } // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp b/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp index 317f342a7..41768926d 100644 --- a/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp +++ b/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp @@ -335,6 +335,10 @@ std::shared_ptr setupObject(std::string objectname, std::unordered_map setupObject(std::string objectname, std::unordered_map> initialVariables, std::shared_ptr mockGridPtr) { + return setupObject(1, objectname, {0, 0}, initialVariables, mockGridPtr); +} + BehaviourResult addCommandsAndExecute(ActionBehaviourType type, std::shared_ptr action, std::string commandName, BehaviourCommandArguments commandArgumentMap, CommandList conditionalCommands, std::shared_ptr srcObjectPtr, std::shared_ptr dstObjectPtr) { switch (type) { case ActionBehaviourType::DESTINATION: { @@ -440,8 +444,9 @@ TEST(ObjectTest, command_reward_default_to_action_player_id) { } TEST(ObjectTest, command_set) { - auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}); - auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); auto srcResult = addCommandsAndExecute(ActionBehaviourType::SOURCE, mockActionPtr, "set", {{"0", _Y("test_param")}, {"1", _Y("5")}}, srcObjectPtr, dstObjectPtr); @@ -453,12 +458,13 @@ TEST(ObjectTest, command_set) { ASSERT_EQ(*srcObjectPtr->getVariableValue("test_param"), 5); ASSERT_EQ(*dstObjectPtr->getVariableValue("test_param"), 5); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_add) { - auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}); - auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); auto srcResult = addCommandsAndExecute(ActionBehaviourType::SOURCE, mockActionPtr, "add", {{"0", _Y("test_param")}, {"1", _Y("5")}}, srcObjectPtr, dstObjectPtr); @@ -470,12 +476,13 @@ TEST(ObjectTest, command_add) { ASSERT_EQ(*srcObjectPtr->getVariableValue("test_param"), 25); ASSERT_EQ(*dstObjectPtr->getVariableValue("test_param"), 25); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_sub) { - auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}); - auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); auto srcResult = addCommandsAndExecute(ActionBehaviourType::SOURCE, mockActionPtr, "sub", {{"0", _Y("test_param")}, {"1", _Y("5")}}, srcObjectPtr, dstObjectPtr); @@ -487,12 +494,13 @@ TEST(ObjectTest, command_sub) { ASSERT_EQ(*srcObjectPtr->getVariableValue("test_param"), 15); ASSERT_EQ(*dstObjectPtr->getVariableValue("test_param"), 15); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_incr) { - auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}); - auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); auto srcResult = addCommandsAndExecute(ActionBehaviourType::SOURCE, mockActionPtr, "incr", {{"0", _Y("test_param")}}, srcObjectPtr, dstObjectPtr); @@ -504,12 +512,13 @@ TEST(ObjectTest, command_incr) { ASSERT_EQ(*srcObjectPtr->getVariableValue("test_param"), 21); ASSERT_EQ(*dstObjectPtr->getVariableValue("test_param"), 21); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_decr) { - auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}); - auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"test_param", _V(20)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"test_param", _V(20)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); auto srcResult = addCommandsAndExecute(ActionBehaviourType::SOURCE, mockActionPtr, "decr", {{"0", _Y("test_param")}}, srcObjectPtr, dstObjectPtr); @@ -521,7 +530,7 @@ TEST(ObjectTest, command_decr) { ASSERT_EQ(*srcObjectPtr->getVariableValue("test_param"), 19); ASSERT_EQ(*dstObjectPtr->getVariableValue("test_param"), 19); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_mov_dest) { @@ -1151,9 +1160,10 @@ TEST(ObjectTest, command_eq) { //* Arguments: [resource, 1] //* Commands: //* - decr: resource - - auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}); - auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}); + + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); @@ -1166,7 +1176,7 @@ TEST(ObjectTest, command_eq) { ASSERT_EQ(*srcObjectPtr->getVariableValue("resource"), 1); ASSERT_EQ(*dstObjectPtr->getVariableValue("resource"), 0); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_eq_qualifiers) { @@ -1184,9 +1194,10 @@ TEST(ObjectTest, command_eq_qualifiers) { //* Arguments: [src.resource, 1] //* Commands: //* - decr: resource - - auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}); - auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}); + + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); @@ -1199,7 +1210,7 @@ TEST(ObjectTest, command_eq_qualifiers) { ASSERT_EQ(*srcObjectPtr->getVariableValue("resource"), 1); ASSERT_EQ(*dstObjectPtr->getVariableValue("resource"), 0); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_lt) { @@ -1218,8 +1229,9 @@ TEST(ObjectTest, command_lt) { //* Commands: //* - decr: resource - auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}); - auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(0)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(1)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); @@ -1231,6 +1243,8 @@ TEST(ObjectTest, command_lt) { ASSERT_EQ(*srcObjectPtr->getVariableValue("resource"), 1); ASSERT_EQ(*dstObjectPtr->getVariableValue("resource"), 0); + + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_gt) { @@ -1249,8 +1263,9 @@ TEST(ObjectTest, command_gt) { //* Commands: //* - decr: resource - auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(1)}}); - auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(2)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(1)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(2)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); @@ -1263,7 +1278,7 @@ TEST(ObjectTest, command_gt) { ASSERT_EQ(*srcObjectPtr->getVariableValue("resource"), 2); ASSERT_EQ(*dstObjectPtr->getVariableValue("resource"), 1); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, command_neq) { @@ -1282,8 +1297,9 @@ TEST(ObjectTest, command_neq) { //* Commands: //* - decr: resource - auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(1)}}); - auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(2)}}); + auto mockGridPtr = mockGrid(); + auto srcObjectPtr = setupObject("srcObject", {{"resource", _V(1)}}, mockGridPtr); + auto dstObjectPtr = setupObject("dstObject", {{"resource", _V(2)}}, mockGridPtr); auto mockActionPtr = setupAction("action", srcObjectPtr, dstObjectPtr); @@ -1296,7 +1312,7 @@ TEST(ObjectTest, command_neq) { ASSERT_EQ(*srcObjectPtr->getVariableValue("resource"), 2); ASSERT_EQ(*dstObjectPtr->getVariableValue("resource"), 1); - verifyMocks(mockActionPtr); + verifyMocks(mockActionPtr, mockGridPtr); } TEST(ObjectTest, isValidAction) { @@ -1321,7 +1337,6 @@ TEST(ObjectTest, isValidAction) { ASSERT_EQ(*srcObject->getVariableValue("counter"), 5); ASSERT_TRUE(preconditionResult); - verifyMocks(mockActionPtr); } TEST(ObjectTest, isValidActionNotDefinedForAction) { diff --git a/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp b/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp index 9a732e373..e11a1cf49 100644 --- a/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp +++ b/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp @@ -48,6 +48,8 @@ TEST(TerminationHandlerTest, terminateOnPlayerScore) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"_score", "10"}; tcd.state = TerminationState::WIN; terminationHandlerPtr->addTerminationCondition(tcd); @@ -56,6 +58,7 @@ TEST(TerminationHandlerTest, terminateOnPlayerScore) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::WIN), Pair(2, TerminationState::LOSE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 1), Pair(2, -1))); } TEST(TerminationHandlerTest, terminateOnPlayerObjects0) { @@ -95,6 +98,8 @@ TEST(TerminationHandlerTest, terminateOnPlayerObjects0) { // Player with 0 bases will end the game and "lose" TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"base:count", "0"}; tcd.state = TerminationState::LOSE; terminationHandlerPtr->addTerminationCondition(tcd); @@ -103,6 +108,7 @@ TEST(TerminationHandlerTest, terminateOnPlayerObjects0) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::WIN), Pair(2, TerminationState::LOSE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, -1), Pair(2, 1))); } TEST(TerminationHandlerTest, terminateOnGlobalVariable) { @@ -138,9 +144,10 @@ TEST(TerminationHandlerTest, terminateOnGlobalVariable) { auto terminationHandlerPtr = std::shared_ptr(new TerminationHandler(mockGridPtr, players)); - // Player with 0 bases will end the game and "lose" TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"variable_name", "20"}; terminationHandlerPtr->addTerminationCondition(tcd); @@ -148,6 +155,7 @@ TEST(TerminationHandlerTest, terminateOnGlobalVariable) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::NONE), Pair(2, TerminationState::NONE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 0), Pair(2, 0))); } TEST(TerminationHandlerTest, terminateOnPlayerGlobalVariable) { @@ -190,6 +198,8 @@ TEST(TerminationHandlerTest, terminateOnPlayerGlobalVariable) { // Player with variable_name == 20 will win and the other player will lose TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.state = TerminationState::WIN; tcd.commandArguments = {"variable_name", "0"}; terminationHandlerPtr->addTerminationCondition(tcd); @@ -198,6 +208,7 @@ TEST(TerminationHandlerTest, terminateOnPlayerGlobalVariable) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::WIN), Pair(2, TerminationState::LOSE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 1), Pair(2, -1))); } TEST(TerminationHandlerTest, terminateOnMaxTicks) { @@ -237,6 +248,8 @@ TEST(TerminationHandlerTest, terminateOnMaxTicks) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"_steps", "100"}; tcd.state = TerminationState::NONE; terminationHandlerPtr->addTerminationCondition(tcd); @@ -245,6 +258,7 @@ TEST(TerminationHandlerTest, terminateOnMaxTicks) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::NONE), Pair(2, TerminationState::NONE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 0), Pair(2, 0))); } TEST(TerminationHandlerTest, singlePlayer_differentId_win) { @@ -270,6 +284,8 @@ TEST(TerminationHandlerTest, singlePlayer_differentId_win) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"environment_objects:count", "0"}; tcd.state = TerminationState::WIN; terminationHandlerPtr->addTerminationCondition(tcd); @@ -278,6 +294,7 @@ TEST(TerminationHandlerTest, singlePlayer_differentId_win) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::WIN))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, -1))); } TEST(TerminationHandlerTest, singlePlayer_differentId_lose) { @@ -303,6 +320,8 @@ TEST(TerminationHandlerTest, singlePlayer_differentId_lose) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = -1; + tcd.opposingReward = 1; tcd.commandArguments = {"environment_objects:count", "0"}; tcd.state = TerminationState::LOSE; terminationHandlerPtr->addTerminationCondition(tcd); @@ -311,6 +330,7 @@ TEST(TerminationHandlerTest, singlePlayer_differentId_lose) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::LOSE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 1))); } TEST(TerminationHandlerTest, singlePlayer_sameId_lose) { @@ -336,6 +356,8 @@ TEST(TerminationHandlerTest, singlePlayer_sameId_lose) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = -1; + tcd.opposingReward = 1; tcd.commandArguments = {"player_objects:count", "0"}; tcd.state = TerminationState::LOSE; terminationHandlerPtr->addTerminationCondition(tcd); @@ -344,6 +366,7 @@ TEST(TerminationHandlerTest, singlePlayer_sameId_lose) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::LOSE))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, -1))); } TEST(TerminationHandlerTest, singlePlayer_sameId_win) { @@ -369,6 +392,8 @@ TEST(TerminationHandlerTest, singlePlayer_sameId_win) { TerminationConditionDefinition tcd; tcd.commandName = "eq"; + tcd.reward = 1; + tcd.opposingReward = -1; tcd.commandArguments = {"player_objects:count", "0"}; tcd.state = TerminationState::WIN; terminationHandlerPtr->addTerminationCondition(tcd); @@ -377,6 +402,7 @@ TEST(TerminationHandlerTest, singlePlayer_sameId_win) { ASSERT_TRUE(terminationResult.terminated); ASSERT_THAT(terminationResult.playerStates, UnorderedElementsAre(Pair(1, TerminationState::WIN))); + ASSERT_THAT(terminationResult.rewards, UnorderedElementsAre(Pair(1, 1))); } } // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/GameProcessTest.cpp b/tests/src/Griddly/Core/GameProcessTest.cpp index 1e90105b9..ddb77b651 100644 --- a/tests/src/Griddly/Core/GameProcessTest.cpp +++ b/tests/src/Griddly/Core/GameProcessTest.cpp @@ -389,9 +389,6 @@ TEST(GameProcessTest, reset) { auto mockObservationPtr = new uint8_t[3]{0, 1, 2}; - EXPECT_CALL(*mockObserverPtr, reset()) - .WillOnce(Return(mockObservationPtr)); - EXPECT_CALL(*mockGDYFactoryPtr, getPlayerObserverDefinition()) .WillOnce(Return(PlayerObserverDefinition{4, 8, 0, 0, false, false})); @@ -408,12 +405,7 @@ TEST(GameProcessTest, reset) { gameProcessPtr->addPlayer(mockPlayerPtr); gameProcessPtr->init(); - - auto observation = gameProcessPtr->reset(); - - auto resetObservationPointer = std::vector(observation, observation + 3); - - ASSERT_THAT(resetObservationPointer, ElementsAreArray(mockObservationPtr, 3)); + gameProcessPtr->reset(); ASSERT_EQ(gameProcessPtr->getNumPlayers(), 1); ASSERT_TRUE(gameProcessPtr->isInitialized()); @@ -479,10 +471,7 @@ TEST(GameProcessTest, resetNoGlobalObserver) { gameProcessPtr->addPlayer(mockPlayerPtr); gameProcessPtr->init(); - - auto observation = gameProcessPtr->reset(); - - ASSERT_EQ(observation, nullptr); + gameProcessPtr->reset(); ASSERT_EQ(gameProcessPtr->getNumPlayers(), 1); ASSERT_TRUE(gameProcessPtr->isInitialized()); @@ -612,7 +601,7 @@ TEST(GameProcessTest, performActions) { ASSERT_FALSE(result.terminated); - ASSERT_EQ(result.reward, 14); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(1), 14); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockObserverPtr.get())); @@ -707,9 +696,9 @@ TEST(GameProcessTest, performActionsMultiAgentRewards) { ASSERT_FALSE(result2.terminated); ASSERT_FALSE(result3.terminated); - ASSERT_EQ(result1.reward, 10); - ASSERT_EQ(result2.reward, -5); - ASSERT_EQ(result3.reward, 15); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(player1Id), 10); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(player2Id), -5); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(player3Id), 15); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockObserverPtr.get())); @@ -780,7 +769,9 @@ TEST(GameProcessTest, performActionsDelayedReward) { ASSERT_FALSE(result.terminated); - ASSERT_EQ(result.reward, 19); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(1), 19); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(2), 3); + ASSERT_EQ(gameProcessPtr->getAccumulatedRewards(5), 3); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockPlayerPtr.get())); diff --git a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp index 504a23abf..31799c921 100644 --- a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp @@ -1,8 +1,8 @@ #include "Griddly/Core/Observers/BlockObserver.hpp" #include "Mocks/Griddly/Core/MockGrid.hpp" -#include "ObserverTestData.hpp" #include "ObserverRTSTestData.hpp" +#include "ObserverTestData.hpp" #include "VulkanObserverTest.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -11,11 +11,11 @@ using ::testing::AnyNumber; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::Eq; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Pair; using ::testing::Return; using ::testing::ReturnRef; -using ::testing::Invoke; namespace griddly { @@ -128,7 +128,6 @@ void runBlockObserverTest(ObserverConfig observerConfig, std::string expectedOutputFilename, bool trackAvatar, bool writeOutputFile = false) { - ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; observerConfig.tileSize = glm::ivec2(20, 20); ObserverTestData testEnvironment = ObserverTestData(observerConfig, DiscreteOrientation(avatarDirection), trackAvatar); @@ -136,30 +135,28 @@ void runBlockObserverTest(ObserverConfig observerConfig, std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(testEnvironment.mockGridPtr, resourceConfig, getMockBlockDefinitions())); blockObserver->init(observerConfig); + blockObserver->reset(); if (trackAvatar) { blockObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } - auto resetObservation = blockObserver->reset(); + auto updateObservation = blockObserver->update(); ASSERT_EQ(blockObserver->getTileSize(), glm::ivec2(20, 20)); ASSERT_EQ(blockObserver->getShape(), expectedObservationShape); ASSERT_EQ(blockObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(blockObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = blockObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); } size_t dataLength = 4 * blockObserver->getShape()[1] * blockObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); @@ -180,25 +177,23 @@ void runBlockObserverRTSTest(ObserverConfig observerConfig, std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSBlockDefinitions())); blockObserver->init(observerConfig); + blockObserver->reset(); - auto resetObservation = blockObserver->reset(); + auto updateObservation = blockObserver->update(); ASSERT_EQ(blockObserver->getShape(), expectedObservationShape); ASSERT_EQ(blockObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(blockObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = blockObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, blockObserver->getStrides()[2], blockObserver->getShape()[1], blockObserver->getShape()[2]); } size_t dataLength = 4 * blockObserver->getShape()[1] * blockObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(blockObserver->getShape(), blockObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); diff --git a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp index 63c7e57b2..4611df387 100644 --- a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp @@ -82,26 +82,24 @@ void runIsometricSpriteObserverRTSTest(ObserverConfig observerConfig, std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSIsometricSpriteDefinitions())); isometricObserver->init(observerConfig); - - auto resetObservation = isometricObserver->reset(); + isometricObserver->reset(); + + auto updateObservation = isometricObserver->update(); ASSERT_EQ(isometricObserver->getTileSize(), glm::ivec2(32, 48)); ASSERT_EQ(isometricObserver->getShape(), expectedObservationShape); ASSERT_EQ(isometricObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(isometricObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = isometricObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); } size_t dataLength = 4 * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); @@ -171,28 +169,27 @@ void runIsometricSpriteObserverTest(ObserverConfig observerConfig, std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockIsometricSpriteDefinitions())); isometricObserver->init(observerConfig); + isometricObserver->reset(); if (trackAvatar) { isometricObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } - auto resetObservation = isometricObserver->reset(); + auto updateObservation = isometricObserver->update(); + ASSERT_EQ(isometricObserver->getShape(), expectedObservationShape); ASSERT_EQ(isometricObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(isometricObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = isometricObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, isometricObserver->getStrides()[2], isometricObserver->getShape()[1], isometricObserver->getShape()[2]); } size_t dataLength = 4 * isometricObserver->getShape()[1] * isometricObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(isometricObserver->getShape(), isometricObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); diff --git a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp index 5d64d2a32..f448eb364 100644 --- a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp @@ -93,26 +93,24 @@ void runSpriteObserverRTSTest(ObserverConfig observerConfig, std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSSpriteDefinitions())); spriteObserver->init(observerConfig); + spriteObserver->reset(); - auto resetObservation = spriteObserver->reset(); - + auto updateObservation = spriteObserver->update(); + ASSERT_EQ(spriteObserver->getTileSize(), glm::ivec2(50, 50)); ASSERT_EQ(spriteObserver->getShape(), expectedObservationShape); ASSERT_EQ(spriteObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(spriteObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = spriteObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); } size_t dataLength = 4 * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); @@ -193,28 +191,27 @@ void runSpriteObserverTest(ObserverConfig observerConfig, std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockSpriteDefinitions())); spriteObserver->init(observerConfig); + spriteObserver->reset(); if (trackAvatar) { spriteObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } - auto resetObservation = spriteObserver->reset(); + auto updateObservation = spriteObserver->update(); + ASSERT_EQ(spriteObserver->getShape(), expectedObservationShape); ASSERT_EQ(spriteObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(spriteObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = spriteObserver->update(); - if (writeOutputFile) { std::string testName(::testing::UnitTest::GetInstance()->current_test_info()->name()); - write_image(testName + ".png", resetObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); + write_image(testName + ".png", updateObservation, spriteObserver->getStrides()[2], spriteObserver->getShape()[1], spriteObserver->getShape()[2]); } size_t dataLength = 4 * spriteObserver->getShape()[1] * spriteObserver->getShape()[2]; auto expectedImageData = loadExpectedImage(expectedOutputFilename); - ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), resetObservation)); ASSERT_THAT(expectedImageData.get(), ObservationResultMatcher(spriteObserver->getShape(), spriteObserver->getStrides(), updateObservation)); testEnvironment.verifyAndClearExpectations(); diff --git a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp index 181ffe814..78fa01481 100644 --- a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp @@ -34,20 +34,19 @@ void runVectorObserverTest(ObserverConfig observerConfig, if (trackAvatar) { vectorObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } - auto resetObservation = vectorObserver->reset(); + + vectorObserver->reset(); + + auto updateObservation = vectorObserver->update(); ASSERT_EQ(vectorObserver->getTileSize(), glm::ivec2(1, 1)); ASSERT_EQ(vectorObserver->getShape(), expectedObservationShape); ASSERT_EQ(vectorObserver->getStrides(), expectedObservationStride); - auto updateObservation = vectorObserver->update(); - size_t dataLength = vectorObserver->getShape()[0] * vectorObserver->getShape()[1] * vectorObserver->getShape()[2]; - auto resetObservationPointer = std::vector(resetObservation, resetObservation + dataLength); auto updateObservationPointer = std::vector(updateObservation, updateObservation + dataLength); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedData, dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedData, dataLength)); testEnvironment.verifyAndClearExpectations(); @@ -65,21 +64,20 @@ void runVectorObserverRTSTest(ObserverConfig observerConfig, vectorObserver->init(observerConfig); - auto resetObservation = vectorObserver->reset(); + vectorObserver->reset(); + + auto updateObservation = vectorObserver->update(); ASSERT_EQ(vectorObserver->getTileSize(), glm::ivec2(1, 1)); ASSERT_EQ(vectorObserver->getShape(), expectedObservationShape); ASSERT_EQ(vectorObserver->getStrides()[0], expectedObservationStride[0]); ASSERT_EQ(vectorObserver->getStrides()[1], expectedObservationStride[1]); - auto updateObservation = vectorObserver->update(); size_t dataLength = vectorObserver->getShape()[0] * vectorObserver->getShape()[1] * vectorObserver->getShape()[2]; - auto resetObservationPointer = std::vector(resetObservation, resetObservation + dataLength); auto updateObservationPointer = std::vector(updateObservation, updateObservation + dataLength); - ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedData, dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedData, dataLength)); testEnvironment.verifyAndClearExpectations(); diff --git a/tests/src/Griddly/Core/Players/PlayerTest.cpp b/tests/src/Griddly/Core/Players/PlayerTest.cpp index d060c221a..90cf965ae 100644 --- a/tests/src/Griddly/Core/Players/PlayerTest.cpp +++ b/tests/src/Griddly/Core/Players/PlayerTest.cpp @@ -44,14 +44,11 @@ TEST(PlayerTest, performActions) { EXPECT_CALL(*mockGameProcessPtr, performActions(Eq(playerId), Eq(actionsList), Eq(true))) .Times(1) - .WillOnce(Return(ActionResult{{}, false, 10})); + .WillOnce(Return(ActionResult{{}, false})); auto actionResult = player->performActions(actionsList); - auto reward = actionResult.reward; auto terminated = actionResult.terminated; - ASSERT_THAT(reward, 10); - EXPECT_EQ(*player->getScore(), 10); EXPECT_FALSE(terminated); EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGameProcessPtr.get())); @@ -74,15 +71,12 @@ TEST(PlayerTest, performActions_terminated) { EXPECT_CALL(*mockGameProcessPtr, performActions(Eq(playerId), Eq(actionsList), Eq(true))) .Times(1) - .WillOnce(Return(ActionResult{{{1, TerminationState::WIN}}, true, 10})); + .WillOnce(Return(ActionResult{{{1, TerminationState::WIN}}, true})); auto actionResult = player->performActions(actionsList); - auto reward = actionResult.reward; auto terminated = actionResult.terminated; auto states = actionResult.playerStates; - ASSERT_THAT(reward, 10); - EXPECT_EQ(*player->getScore(), 10); EXPECT_EQ(states, (std::unordered_map{{1, TerminationState::WIN}})); EXPECT_TRUE(terminated); diff --git a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp index a2fe76ba9..3058b7b39 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp +++ b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp @@ -10,7 +10,7 @@ class MockTerminationGenerator : public TerminationGenerator { public: MockTerminationGenerator() : TerminationGenerator(){}; - MOCK_METHOD(void, defineTerminationCondition, (TerminationState state, std::string commandName, std::vector commandParameters), ()); + MOCK_METHOD(void, defineTerminationCondition, (TerminationState state, std::string commandName, int32_t reward, int32_t opposingReward, std::vector commandParameters), ()); MOCK_METHOD(std::shared_ptr, newInstance, (std::shared_ptr grid, std::vector> players), ()); }; } // namespace griddly \ No newline at end of file diff --git a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp index df1dd1a88..71f29b54e 100644 --- a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp +++ b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp @@ -10,8 +10,8 @@ class MockObserver : public Observer { ~MockObserver() {} MOCK_METHOD(void, init, (ObserverConfig observerConfig), ()); - MOCK_METHOD(uint8_t*, update, (), (const)); - MOCK_METHOD(uint8_t*, reset, (), ()); + MOCK_METHOD(uint8_t*, update, (), ()); + MOCK_METHOD(void, reset, (), ()); MOCK_METHOD(void, resetShape, (), ()); MOCK_METHOD(std::vector, getShape, (), (const));