├── cmake.lock ├── examples ├── __init__.py ├── example_02 │ ├── __init__.py │ └── scenario_01.py ├── example_03 │ ├── __init__.py │ ├── scenario_test.py │ ├── scenario182norewards.py │ └── scenario182.py ├── example_04 │ ├── __init__.py │ └── random_agent.py ├── example_05 │ ├── __init__.py │ ├── torch │ │ └── __init__.py │ └── wrappers.py ├── requirements.txt ├── example_01 │ └── basic_01.py └── old │ ├── util.py │ └── test.py ├── DeepRTS ├── python │ ├── ml │ │ ├── __init__.py │ │ └── agent.py │ ├── assets │ │ ├── __init__.py │ │ ├── fonts │ │ │ └── arial.ttf │ │ ├── audio │ │ │ └── song_1.ogg │ │ ├── textures │ │ │ ├── farm.png │ │ │ ├── tree.png │ │ │ ├── archer.png │ │ │ ├── footman.png │ │ │ ├── grass.png │ │ │ ├── peasant.png │ │ │ ├── tiles.png │ │ │ ├── barracks.png │ │ │ ├── gimp │ │ │ │ ├── farm.xcf │ │ │ │ ├── archer.xcf │ │ │ │ ├── footman.xcf │ │ │ │ ├── peasant.xcf │ │ │ │ ├── barracks.xcf │ │ │ │ └── town_hall.xcf │ │ │ ├── orc │ │ │ │ ├── grunt.png │ │ │ │ ├── peon.png │ │ │ │ ├── axethrower.png │ │ │ │ └── buildings.png │ │ │ ├── town_hall.png │ │ │ ├── game_frame.png │ │ │ └── human │ │ │ │ ├── archer.png │ │ │ │ ├── footman.png │ │ │ │ ├── peasant.png │ │ │ │ └── buildings.png │ │ ├── maps │ │ │ ├── README.MD │ │ │ ├── 10x10-2p-ffa-Eblil.json │ │ │ ├── 15x15-2p-ffa-Cresal.json │ │ │ ├── 15x15-1p-ffa-Utha-Lava.json │ │ │ ├── 21x21-2p-ffa-Eflines.json │ │ │ ├── 21x21-1p-scenario-Gondor.json │ │ │ └── 21x21-2p-ffa-FindGold-Vastrana.json │ │ └── tile_properties.json │ ├── tests │ │ ├── __init__.py │ │ └── test_deeprts.py │ ├── __init__.py │ ├── config.py │ └── game.py ├── _version.py └── __init__.py ├── requirements.txt ├── docs ├── logo.png ├── pages │ ├── mcts │ │ ├── implementation.md │ │ └── mcts.gif │ ├── dqn │ │ └── results_1 │ │ │ ├── 14.03.17-dqn-noconf-2000-frames.png │ │ │ ├── 15.03.17-dqn-noconf-12000-frames.png │ │ │ └── results_1.md │ ├── presentations.md │ ├── monte_carlo_methods.md │ └── performance_log.md ├── images │ ├── 10x10-2-FFA.png │ ├── 15x15-2-FFA.png │ ├── 21x21-2-FFA.png │ ├── 31x31-2-FFA.png │ ├── 31x31-4-FFA.png │ ├── 31x31-6-FFA.png │ └── deeprts_gif.gif ├── api │ └── README.md └── PROEJCTS.md ├── .gitmodules ├── vcpkg_dependencies.txt ├── src ├── gamestate │ ├── GameState.cpp │ └── AddUnit.cpp ├── gui │ ├── BaseGUI.cpp │ └── Blend2DGUI.cpp ├── scenario │ ├── criteria │ │ ├── ScenarioCriteria.cpp │ │ ├── DamageDone.cpp │ │ ├── FoodCount.cpp │ │ ├── DamageTaken.cpp │ │ ├── UnitsCreated.cpp │ │ ├── GoldCollect.cpp │ │ ├── StoneCollect.cpp │ │ ├── LumberCollect.cpp │ │ ├── FoodConsumption.cpp │ │ ├── DamageDoneIncrement.cpp │ │ ├── DamageTakenIncrement.cpp │ │ ├── GameEnd.cpp │ │ ├── ResourceIncrement.cpp │ │ ├── NumUnitTypeCreated.cpp │ │ └── UnitIncrement.cpp │ ├── scenarios │ │ ├── GoldCollectFifteen.cpp │ │ ├── LavaMaze.cpp │ │ └── GeneralAIOneVersusOne.cpp │ └── Scenario.cpp ├── state │ ├── Idle.cpp │ ├── Despawned.cpp │ ├── BaseState.cpp │ ├── Dead.cpp │ ├── Building.cpp │ ├── Spawning.cpp │ ├── StateManager.cpp │ ├── Combat.cpp │ ├── Walking.cpp │ └── Harvesting.cpp ├── main.cpp ├── Map.cpp └── ResourceLoader.cpp ├── include └── DeepRTS │ ├── defs.h │ ├── unit │ └── Footman.h │ ├── util │ ├── Position.h │ ├── String.h │ ├── PriorityQueue.hpp │ ├── Pathfinder.h │ └── ColorConverter.hpp │ ├── gui │ ├── Blend2DSprites.h │ ├── BaseGUI.h │ └── PyGUI.h │ ├── gamestate │ ├── GameState.h │ ├── StateChange.h │ └── AddUnit.h │ ├── scenario │ ├── scenarios │ │ ├── LavaMaze.h │ │ ├── GeneralAIOneVersusOne.h │ │ └── GoldCollectFifteen.h │ ├── criterias │ │ ├── GameEnd.h │ │ ├── FoodCount.h │ │ ├── GoldCollect.h │ │ ├── StoneCollect.h │ │ ├── DamageDone.h │ │ ├── LumberCollect.h │ │ ├── DamageTaken.h │ │ ├── UnitsCreated.h │ │ ├── FoodConsumption.h │ │ ├── DamageDoneIncrement.h │ │ ├── DamageTakenIncrement.h │ │ ├── UnitIncrement.h │ │ ├── ScenarioCriteria.h │ │ ├── NumUnitTypeCreated.h │ │ └── ResourceIncrement.h │ └── Scenario.h │ ├── state │ ├── Dead.h │ ├── Combat.h │ ├── Building.h │ ├── Idle.h │ ├── Walking.h │ ├── Spawning.h │ ├── Harvesting.h │ ├── Despawned.h │ ├── BaseState.h │ └── StateManager.h │ ├── Map.h │ ├── UnitManager.h │ ├── Tilemap.h │ ├── ResourceLoader.h │ └── Constants.h ├── bindings ├── UnitManager.cpp ├── Tilemap.cpp ├── Map.cpp ├── Random.cpp ├── trampolines │ ├── PyPlayer.h │ ├── PyScenarioCriteria.h │ └── PyGame.h ├── BaseState.cpp ├── utilities │ └── ndarray_converter.h ├── Tile.cpp ├── DeepRTS.cpp ├── Player.cpp ├── Config.cpp ├── Game.cpp ├── Unit.cpp └── Constants.cpp ├── Dockerfile ├── .github └── workflows │ └── test_vcpkg_install.yaml ├── .travis.yml ├── pyproject.toml ├── Doxyfile.in ├── .vscode └── tasks.json ├── LICENCE.md ├── vcpkg_install.sh ├── .gitignore ├── setup.py └── README.md /cmake.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DeepRTS/python/ml/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/example_02/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/example_03/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/example_04/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/example_05/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/example_05/torch/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/__init__.py: -------------------------------------------------------------------------------- 1 | # TEST -------------------------------------------------------------------------------- /DeepRTS/python/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from DeepRTS.python.test import * -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pybind11 2 | pygame==2.0.0 3 | numpy 4 | cython 5 | gym -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/pages/mcts/implementation.md: -------------------------------------------------------------------------------- 1 | # MCTS Implementation 2 | 3 | ![](./mcts.gif) 4 | -------------------------------------------------------------------------------- /docs/pages/mcts/mcts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/pages/mcts/mcts.gif -------------------------------------------------------------------------------- /docs/images/10x10-2-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/10x10-2-FFA.png -------------------------------------------------------------------------------- /docs/images/15x15-2-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/15x15-2-FFA.png -------------------------------------------------------------------------------- /docs/images/21x21-2-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/21x21-2-FFA.png -------------------------------------------------------------------------------- /docs/images/31x31-2-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/31x31-2-FFA.png -------------------------------------------------------------------------------- /docs/images/31x31-4-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/31x31-4-FFA.png -------------------------------------------------------------------------------- /docs/images/31x31-6-FFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/31x31-6-FFA.png -------------------------------------------------------------------------------- /docs/images/deeprts_gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/images/deeprts_gif.gif -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/api/html"] 2 | path = docs/api/html 3 | url = git@github.com:cair/deep-rts.git 4 | -------------------------------------------------------------------------------- /vcpkg_dependencies.txt: -------------------------------------------------------------------------------- 1 | spdlog 2 | effolkronium-random 3 | xtensor[xsimd] 4 | nlohmann-json 5 | opencv 6 | blend2d 7 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/fonts/arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/fonts/arial.ttf -------------------------------------------------------------------------------- /docs/api/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | Looking for live code documentation? [Click Here!](https://cair.github.io/deep-rts) -------------------------------------------------------------------------------- /DeepRTS/python/assets/audio/song_1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/audio/song_1.ogg -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/farm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/farm.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/tree.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/archer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/archer.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/footman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/footman.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/grass.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/peasant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/peasant.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/tiles.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/barracks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/barracks.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/farm.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/farm.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/orc/grunt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/orc/grunt.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/orc/peon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/orc/peon.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/town_hall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/town_hall.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/game_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/game_frame.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/archer.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/archer.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/footman.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/footman.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/peasant.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/peasant.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/human/archer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/human/archer.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/barracks.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/barracks.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/gimp/town_hall.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/gimp/town_hall.xcf -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/human/footman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/human/footman.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/human/peasant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/human/peasant.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/orc/axethrower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/orc/axethrower.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/orc/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/orc/buildings.png -------------------------------------------------------------------------------- /src/gamestate/GameState.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 23.03.18. 3 | // 4 | 5 | #include "gamestate/GameState.h" 6 | using namespace DeepRTS; 7 | -------------------------------------------------------------------------------- /DeepRTS/python/__init__.py: -------------------------------------------------------------------------------- 1 | from DeepRTS.python.config import Config 2 | from DeepRTS.python.gui import GUI 3 | from DeepRTS.python.game import Game 4 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/textures/human/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/DeepRTS/python/assets/textures/human/buildings.png -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/README.MD: -------------------------------------------------------------------------------- 1 | # Maps of Deep RTS 2 | 3 | 4 | ### Name Generator 5 | 1. https://www.fantasynamegenerators.com/country_names.php 6 | -------------------------------------------------------------------------------- /include/DeepRTS/defs.h: -------------------------------------------------------------------------------- 1 | 2 | // XTENSOR does not compile properly because of pow10 errors. This "fixes it" 3 | #ifdef __APPLE__ 4 | #undef _GNU_SOURCE 5 | #endif 6 | -------------------------------------------------------------------------------- /docs/pages/dqn/results_1/14.03.17-dqn-noconf-2000-frames.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/pages/dqn/results_1/14.03.17-dqn-noconf-2000-frames.png -------------------------------------------------------------------------------- /docs/pages/dqn/results_1/15.03.17-dqn-noconf-12000-frames.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cair/deep-rts/HEAD/docs/pages/dqn/results_1/15.03.17-dqn-noconf-12000-frames.png -------------------------------------------------------------------------------- /src/gui/BaseGUI.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/5/21. 3 | // 4 | #include "gui/BaseGUI.h" 5 | #include "Game.h" 6 | using namespace DeepRTS; 7 | 8 | BaseGUI::BaseGUI(Game &game) 9 | : game(game){ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /DeepRTS/_version.py: -------------------------------------------------------------------------------- 1 | # file generated by setuptools_scm 2 | # don't change, don't track in version control 3 | __version__ = version = '3.0rc2.dev24+gde873ac.d20230510' 4 | __version_tuple__ = version_tuple = (3, 0, 'dev24', 'gde873ac.d20230510') 5 | -------------------------------------------------------------------------------- /examples/requirements.txt: -------------------------------------------------------------------------------- 1 | ray[rllib] 2 | torch 3 | requests 4 | setproctitle 5 | psutil 6 | tensorflow-gpu 7 | tensorboard 8 | plotly 9 | git+https://github.com/vitchyr/viskit.git 10 | aiohttp 11 | tensorboardX 12 | pygments 13 | pandas 14 | uvicorn 15 | pygame -------------------------------------------------------------------------------- /include/DeepRTS/unit/Footman.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/5/21. 3 | // 4 | 5 | #ifndef DEEPRTS_FOOTMAN_H 6 | #define DEEPRTS_FOOTMAN_H 7 | #include "Unit.h" 8 | #include "Player.h" 9 | 10 | class Footman: public Unit{ 11 | Footman(Player& player); 12 | }; 13 | 14 | 15 | #endif //DEEPRTS_FOOTMAN_H 16 | -------------------------------------------------------------------------------- /include/DeepRTS/util/Position.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 3/16/17. 3 | // 4 | 5 | #ifndef DEEPRTS_POSITION_H 6 | #define DEEPRTS_POSITION_H 7 | 8 | struct Position { 9 | Position(){}; 10 | Position(int x, int y): x(x), y(y){}; 11 | 12 | int x; 13 | int y; 14 | }; 15 | 16 | #endif //DEEPRTS_POSITION_H 17 | -------------------------------------------------------------------------------- /src/scenario/criteria/ScenarioCriteria.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/ScenarioCriteria.h" 6 | 7 | DeepRTS::Criteria::ScenarioCriteria::ScenarioCriteria(int rewardSuccess, int rewardFailure) 8 | : rewardSuccess(rewardSuccess) 9 | , rewardFailure(rewardFailure){ 10 | 11 | } 12 | 13 | -------------------------------------------------------------------------------- /DeepRTS/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from DeepRTS import Engine 3 | except ImportError: 4 | import Engine 5 | 6 | try: 7 | from DeepRTS.Engine import Map, UnitManager, Constants, Player 8 | from DeepRTS.Engine import Constants 9 | except ImportError: 10 | from Engine import Map, UnitManager, Constants, Player, Constants 11 | 12 | -------------------------------------------------------------------------------- /include/DeepRTS/gui/Blend2DSprites.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/5/21. 3 | // 4 | 5 | #ifndef DEEPRTS_BLEND2DSPRITES_H 6 | #define DEEPRTS_BLEND2DSPRITES_H 7 | namespace DeepRTS { 8 | 9 | class BaseSprite { 10 | 11 | }; 12 | 13 | 14 | class FootmanSprite { 15 | 16 | }; 17 | 18 | } 19 | 20 | 21 | #endif //DEEPRTS_BLEND2DSPRITES_H 22 | -------------------------------------------------------------------------------- /include/DeepRTS/gamestate/GameState.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 23.03.18. 3 | // 4 | 5 | #ifndef DEEPRTS_GAMESTATE_H 6 | #define DEEPRTS_GAMESTATE_H 7 | #include "StateChange.h" 8 | #include 9 | 10 | namespace DeepRTS { 11 | 12 | class GameState { 13 | std::list changes; 14 | }; 15 | } 16 | 17 | #endif //DEEPRTS_GAMESTATE_H 18 | -------------------------------------------------------------------------------- /src/state/Idle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #include "state/Idle.h" 6 | #include "Player.h" 7 | using namespace DeepRTS; 8 | 9 | void Idle::update(Unit & unit){ 10 | (void)(unit); 11 | } 12 | 13 | void Idle::init(Unit & unit) { 14 | (void)(unit); 15 | } 16 | 17 | void Idle::end(Unit & unit) { 18 | (void)(unit); 19 | } 20 | -------------------------------------------------------------------------------- /src/state/Despawned.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 25.02.2017. 3 | // 4 | 5 | #include "state/Despawned.h" 6 | using namespace DeepRTS; 7 | 8 | 9 | void Despawned::update(Unit & unit){ 10 | (void)(unit); 11 | } 12 | 13 | void Despawned::end(Unit & unit){ 14 | (void)(unit); 15 | } 16 | 17 | void Despawned::init(Unit & unit){ 18 | (void)(unit); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/state/BaseState.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #include "state/BaseState.h" 6 | using namespace DeepRTS; 7 | 8 | void BaseState::update(Unit& unit){ 9 | (void)(unit); 10 | } 11 | 12 | void BaseState::init(Unit& unit) { 13 | (void)(unit); 14 | } 15 | 16 | void BaseState::end(Unit& unit){ 17 | (void)(unit); 18 | } 19 | 20 | BaseState::~BaseState() = default; -------------------------------------------------------------------------------- /include/DeepRTS/gamestate/StateChange.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 23.03.18. 3 | // 4 | 5 | #ifndef DEEPRTS_STATECHANGE_H 6 | #define DEEPRTS_STATECHANGE_H 7 | namespace DeepRTS { 8 | 9 | class Game; 10 | 11 | class StateChange { 12 | public: 13 | virtual void apply(Game *game) { 14 | 15 | } 16 | 17 | virtual void apply_reverse(Game *game) { 18 | 19 | } 20 | }; 21 | } 22 | #endif //DEEPRTS_STATECHANGE_H 23 | -------------------------------------------------------------------------------- /DeepRTS/python/tests/test_deeprts.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from DeepRTS import python 3 | from DeepRTS import Engine 4 | 5 | 6 | class TestDeepRTSGame(unittest.TestCase): 7 | 8 | def setUp(self) -> None: 9 | self.game = python.Game( 10 | python.Config.Map.FIFTEEN, 11 | n_players=1, 12 | engine_config=None, 13 | gui_config=None, 14 | ) 15 | 16 | def test_1(self): 17 | self.assertTrue(self.game.players) -------------------------------------------------------------------------------- /bindings/UnitManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | namespace py = pybind11; 3 | 4 | #include "../include/DeepRTS/Player.h" 5 | #include "../include/DeepRTS/UnitManager.h" 6 | 7 | using DeepRTS::UnitManager; 8 | 9 | 10 | void init_UnitManager(py::module &m) { 11 | py::class_(m, "UnitManager") 12 | // static Unit constructUnit(Constants::Unit unitType, Player &player); 13 | .def("construct_unit", &UnitManager::constructUnit); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/scenarios/LavaMaze.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/11/21. 3 | // 4 | 5 | #ifndef DEEPRTS_LAVAMAZE_H 6 | #define DEEPRTS_LAVAMAZE_H 7 | 8 | #include 9 | 10 | namespace DeepRTS::Scenarios{ 11 | 12 | class LavaMaze: public Scenario{ 13 | 14 | public: 15 | LavaMaze(); 16 | [[maybe_unused]] ActionSequenceContainer optimalStrategy() override; 17 | Config getConfig(); 18 | }; 19 | 20 | } 21 | 22 | #endif //DEEPRTS_LAVAMAZE_H 23 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/scenarios/GeneralAIOneVersusOne.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_GENERALAIONEVERSUSONE_H 6 | #define DEEPRTS_GENERALAIONEVERSUSONE_H 7 | #include "scenario/Scenario.h" 8 | 9 | namespace DeepRTS::Scenarios{ 10 | 11 | class GeneralAIOneVersusOne: public Scenario{ 12 | 13 | public: 14 | GeneralAIOneVersusOne(); 15 | 16 | 17 | Config getConfig(); 18 | }; 19 | 20 | 21 | 22 | } 23 | 24 | #endif //DEEPRTS_GENERALAIONEVERSUSONE_H 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update && apt-get install -y apt-utils python3 python3-pip git xvfb build-essential cmake 4 | 5 | RUN git clone https://github.com/UIA-CAIR/DeepRTS.git drts --recurse-submodules 6 | RUN pip3 install -e drts 7 | 8 | RUN cat drts/coding/requirements.txt | xargs -n 1 pip3 install; exit 0 9 | RUN cat drts/requirements.txt | xargs -n 1 pip3 install; exit 0 10 | 11 | RUN Xvfb :99 -ac & 12 | 13 | ENV SDL_VIDEODRIVER dummy 14 | 15 | RUN python3 drts/coding/main.py 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/state/Dead.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 27.02.2017. 3 | // 4 | 5 | #include "state/Dead.h" 6 | #include "unit/Unit.h" 7 | #include "Game.h" 8 | using namespace DeepRTS; 9 | 10 | void Dead::update(Unit & unit){ 11 | unit.despawn(); 12 | unit.player_.removeUnit(unit); 13 | unit.player_.setState(unit.player_.evaluatePlayerState()); 14 | unit.player_.getGame().isTerminal(); 15 | } 16 | 17 | void Dead::end(Unit & unit){ 18 | (void)(unit); 19 | } 20 | 21 | void Dead::init(Unit & unit){ 22 | (void)(unit); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/scenarios/GoldCollectFifteen.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_GOLDCOLLECTFIFTEEN_H 6 | #define DEEPRTS_GOLDCOLLECTFIFTEEN_H 7 | 8 | #include 9 | 10 | namespace DeepRTS::Scenarios{ 11 | 12 | class GoldCollectFifteen: public Scenario{ 13 | 14 | public: 15 | GoldCollectFifteen(); 16 | [[maybe_unused]] ActionSequenceContainer optimalStrategy() override; 17 | 18 | 19 | 20 | }; 21 | 22 | 23 | 24 | } 25 | #endif //DEEPRTS_GOLDCOLLECTFIFTEEN_H 26 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Dead.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 25.02.2017. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "../Constants.h" 8 | #include "BaseState.h" 9 | namespace DeepRTS { 10 | 11 | class Unit; 12 | 13 | class Dead : public BaseState { 14 | public: 15 | Dead() : BaseState(Constants::State::Dead) { 16 | name = "Dead"; 17 | } 18 | 19 | void update(Unit &unit) override; 20 | 21 | void init(Unit &unit) override; 22 | 23 | void end(Unit &unit) override; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /docs/pages/presentations.md: -------------------------------------------------------------------------------- 1 | # Project Presentation 2 | This page contains all external presentation material relevant to this project 3 | 4 | | Title | Date| Presentation Location 5 | | ------------- |:-------------:|-----------:| 6 | | [Applying machine learning to AI in RTS Games](https://github.com/perara/WarC2Sim/blob/gh-pages/Applying_machine_learning_to_AI_in_RTS_Games.pdf) | 03.02.2017 | University of Agder, MSc Meetings 7 | | [Deep RTS Paper](https://arxiv.org/abs/1808.05032) | Summer 2018 | University of Agder, MSc Meetings 8 | 9 | 10 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Combat.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 25.02.2017. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "../Constants.h" 8 | #include "BaseState.h" 9 | namespace DeepRTS { 10 | 11 | class Unit; 12 | 13 | class Combat : public BaseState { 14 | public: 15 | Combat() : BaseState(Constants::State::Combat) { 16 | name = "Combat"; 17 | } 18 | 19 | void update(Unit &unit) override; 20 | 21 | void init(Unit &unit) override; 22 | 23 | void end(Unit &unit) override; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Building.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 25.02.2017. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "../Constants.h" 8 | #include "BaseState.h" 9 | namespace DeepRTS { 10 | 11 | class Unit; 12 | 13 | class Building : public BaseState { 14 | public: 15 | Building() : BaseState(Constants::State::Building) { 16 | name = "Building"; 17 | } 18 | 19 | void update(Unit &unit) override; 20 | 21 | void init(Unit &unit) override; 22 | 23 | void end(Unit &unit) override; 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /src/gamestate/AddUnit.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 23.03.18. 3 | // 4 | 5 | #include "../../include/DeepRTS/gamestate/AddUnit.h" 6 | #include "unit/Unit.h" 7 | #include "../../include/DeepRTS/Game.h" 8 | using namespace DeepRTS; 9 | 10 | 11 | void AddUnit::apply(Game * game){ 12 | auto &player = game->players.at(player_id); 13 | player.addUnit((Constants::Unit)type); 14 | } 15 | 16 | void AddUnit::apply_reverse(Game* game){ 17 | auto &player = game->players.at(player_id); 18 | auto &unit = game->getUnit(id); 19 | player.removeUnit(unit); 20 | } 21 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Idle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_IDLE_H 6 | #define WARC2SIM_IDLE_H 7 | 8 | 9 | #include "BaseState.h" 10 | namespace DeepRTS { 11 | 12 | class Idle : public BaseState { 13 | 14 | public: 15 | Idle() : BaseState(Constants::State::Idle) { 16 | name = "Idle"; 17 | } 18 | 19 | void update(Unit &unit) override; 20 | 21 | void init(Unit &unit) override; 22 | 23 | void end(Unit &unit) override; 24 | 25 | }; 26 | 27 | } 28 | #endif //WARC2SIM_IDLE_H 29 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Walking.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | #pragma once 5 | 6 | #include "BaseState.h" 7 | 8 | 9 | #include "util/JPS.h" 10 | 11 | namespace DeepRTS { 12 | 13 | 14 | class Tilemap; 15 | 16 | class Game; 17 | 18 | class Walking : public BaseState { 19 | JPS::Searcher search; 20 | 21 | public: 22 | explicit Walking(Game &game); 23 | 24 | void update(Unit &unit) override; 25 | 26 | void init(Unit &unit) override; 27 | 28 | void end(Unit &unit) override; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /bindings/Tilemap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace py = pybind11; 4 | 5 | #include "../include/DeepRTS/Map.h" 6 | #include "../include/DeepRTS/Tilemap.h" 7 | #include "../include/DeepRTS/Game.h" 8 | 9 | using DeepRTS::Tilemap; 10 | using DeepRTS::Game; 11 | using DeepRTS::Map; 12 | void init_Tilemap(py::module &m) { 13 | py::class_(m, "Tilemap") 14 | .def(py::init()) 15 | .def_readonly("tiles", &Tilemap::tiles) 16 | .def("get_tile", &Tilemap::getTile, py::return_value_policy::reference); 17 | } -------------------------------------------------------------------------------- /.github/workflows/test_vcpkg_install.yaml: -------------------------------------------------------------------------------- 1 | name: Validate VCPKG install script 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | test: 11 | name: Run Script 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, macos-latest, windows-latest] 16 | 17 | steps: 18 | - name: Check out code 19 | uses: actions/checkout@v2 20 | 21 | - name: Install Dependencies and Run Script 22 | run: | 23 | chmod +x vcpkg/vcpkg_install.sh 24 | ./vcpkg/vcpkg_install.sh 25 | -------------------------------------------------------------------------------- /include/DeepRTS/gamestate/AddUnit.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 23.03.18. 3 | // 4 | 5 | #ifndef DEEPRTS_ADDUNIT_H 6 | #define DEEPRTS_ADDUNIT_H 7 | 8 | 9 | #include "StateChange.h" 10 | namespace DeepRTS { 11 | 12 | class Game; 13 | 14 | class AddUnit : StateChange { 15 | int id; 16 | int type; 17 | int player_id; 18 | 19 | AddUnit(int id, int type, int player_id) : id(id), type(type), player_id(player_id) {} 20 | 21 | 22 | void apply(Game *game); 23 | 24 | void apply_reverse(Game *game); 25 | }; 26 | 27 | } 28 | #endif //DEEPRTS_ADDUNIT_H 29 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Spawning.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_SPAWNING_H 6 | #define WARC2SIM_SPAWNING_H 7 | 8 | 9 | 10 | #include "BaseState.h" 11 | namespace DeepRTS { 12 | 13 | class Spawning : public BaseState { 14 | 15 | public: 16 | Spawning() : BaseState(Constants::State::Spawning) { 17 | name = "Spawning"; 18 | } 19 | 20 | void update(Unit &unit) override; 21 | 22 | void init(Unit &unit) override; 23 | 24 | void end(Unit &unit) override; 25 | }; 26 | } 27 | 28 | #endif //WARC2SIM_SPAWNING_H 29 | -------------------------------------------------------------------------------- /include/DeepRTS/gui/BaseGUI.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/5/21. 3 | // 4 | 5 | #ifndef DEEPRTS_BASEGUI_H 6 | #define DEEPRTS_BASEGUI_H 7 | 8 | #include 9 | namespace DeepRTS { 10 | 11 | class Game; 12 | 13 | class Tile; 14 | 15 | 16 | class BaseGUI { 17 | 18 | protected: 19 | const Game &game; 20 | public: 21 | cv::Mat renderData; 22 | 23 | explicit BaseGUI(Game &game); 24 | 25 | virtual const cv::Mat &render() const = 0; 26 | 27 | virtual void onTileChange(const Tile &) = 0; 28 | }; 29 | } 30 | 31 | #endif //DEEPRTS_BASEGUI_H 32 | -------------------------------------------------------------------------------- /docs/PROEJCTS.md: -------------------------------------------------------------------------------- 1 | # Projects using Deep RTS 2 | This list aims towards keeping track of projects/efforts that use Deep RTS in research. Want your project included on the list? Send a pull request! :) 3 | 4 | ### Github Repositories 5 | 1. https://github.com/maswin/DeepRTS 6 | 2. https://github.com/keyber/DeepRTS 7 | 3. https://github.com/csci-599-applied-ml-for-games/DeepRTS 8 | 4. https://github.com/csci-599-applied-ml-for-games/DeepRL-For-RTS 9 | 5. https://github.com/ykrmm/RL_RealTimeStrategy 10 | 6. https://github.com/marcocspc/deep-rts 11 | 12 | ### Research Papers 13 | 1. https://ieeexplore.ieee.org/abstract/document/9477938 14 | -------------------------------------------------------------------------------- /bindings/Map.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 04.02.18. 3 | // 4 | 5 | #include 6 | #include 7 | namespace py = pybind11; 8 | 9 | #include 10 | #include "../include/DeepRTS/Map.h" 11 | using DeepRTS::Map; 12 | 13 | 14 | void init_Map(py::module &m) { 15 | py::class_(m, "Map") 16 | .def(py::init()) 17 | .def_readonly("tile_width", &Map::TILE_WIDTH) 18 | .def_readonly("tile_height", &Map::TILE_HEIGHT) 19 | .def_readonly("map_width", &Map::MAP_WIDTH) 20 | .def_readonly("map_height", &Map::MAP_HEIGHT); 21 | } -------------------------------------------------------------------------------- /bindings/Random.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 11/7/19. 3 | // 4 | 5 | #include 6 | #include 7 | namespace py = pybind11; 8 | 9 | 10 | void init_Random(py::module &m) { 11 | using Random = effolkronium::random_static; 12 | Random::get(0, 1); 13 | py::class_>(m, "Random") 14 | //.def(py::init([](){ return std::unique_ptr(&Random::getInstance()); })); 15 | .def_static("get", [](int a, int b){ 16 | return Random::get(a, b); 17 | }); 18 | 19 | 20 | 21 | } -------------------------------------------------------------------------------- /bindings/trampolines/PyPlayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 23.02.2017. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "../../include/DeepRTS/Player.h" 8 | using DeepRTS::Player; 9 | 10 | using namespace DeepRTS; 11 | 12 | class PyPlayer: public Player { 13 | using Player::Player; 14 | 15 | [[nodiscard]] Constants::PlayerState evaluatePlayerState() const override { 16 | PYBIND11_OVERRIDE(Constants::PlayerState, Player, evaluatePlayerState , ); 17 | } 18 | 19 | [[nodiscard]] double getScore() const override { 20 | PYBIND11_OVERRIDE(int, Player, getScore, ); 21 | } 22 | 23 | 24 | 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /src/scenario/criteria/DamageDone.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/DamageDone.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::DamageDone::DamageDone(int damageDone, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , damageDone(damageDone){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::DamageDone::evaluate(const Player &player) { 14 | isValid = player.sDamageDone >= damageDone; 15 | return isValid; 16 | } 17 | 18 | int DeepRTS::Criteria::DamageDone::reward() const { 19 | return (isValid) ? rewardSuccess : rewardFailure; 20 | } 21 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Harvesting.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 26.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_HARVESTING_H 6 | #define WARC2SIM_HARVESTING_H 7 | 8 | 9 | #include "BaseState.h" 10 | namespace DeepRTS { 11 | 12 | class Unit; 13 | 14 | class Harvesting : public BaseState { 15 | public: 16 | Harvesting() : BaseState(Constants::State::Harvesting) { 17 | name = "Harvesting"; 18 | } 19 | 20 | void update(Unit &unit) override; 21 | 22 | void init(Unit &unit) override; 23 | 24 | void end(Unit &unit) override; 25 | }; 26 | } 27 | #endif //WARC2SIM_HARVESTING_H 28 | -------------------------------------------------------------------------------- /examples/example_04/random_agent.py: -------------------------------------------------------------------------------- 1 | from DeepRTS.contrib.agents.agent import BaseAgent 2 | from DeepRTS.Engine import Random 3 | 4 | 5 | class RandomAgent(BaseAgent): 6 | 7 | def __init__(self, env): 8 | super(RandomAgent, self).__init__(env=env) 9 | 10 | def get_state(self): 11 | return self.env.get_state(image=False, copy=False) 12 | 13 | def get_action(self, obs): 14 | return Random.action() - 1 15 | 16 | def state_preprocess(self, obs): 17 | return obs 18 | # return obs.swapaxes(0, 1).copy() 19 | 20 | def memorize(self, obs, obs1, action, reward, terminal, info): 21 | pass 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | os: linux 3 | dist: bionic 4 | git: 5 | depth: false 6 | services: 7 | - xvfb 8 | 9 | matrix: 10 | include: 11 | - python: 3.5 12 | - python: 3.6 13 | - python: 3.7 14 | - python: 3.8 15 | 16 | before_script: 17 | - python -m pip install -U pip 18 | - python -m pip install -U pytest 19 | - python -m pip install -r requirements.txt 20 | install: 21 | - python -m pip install . 22 | script: 23 | - pytest --pyargs DeepRTS 24 | 25 | 26 | 27 | notifications: 28 | webhooks: https://discordapp.com/api/webhooks/299549422986067968/0TjN9PW6LcP7Nc-gqFg5nh21mDsww9Qp6vG_F8734A2d_iwPVNRUdx_xUi-xo86pvDHW/travis 29 | -------------------------------------------------------------------------------- /src/scenario/criteria/FoodCount.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/FoodCount.h" 6 | #include "Player.h" 7 | 8 | DeepRTS::Criteria::FoodCount::FoodCount(int foodCountLimit, int rewardSuccess, int rewardFailure) 9 | : ScenarioCriteria(rewardSuccess, rewardFailure) 10 | , foodCountLimit(foodCountLimit){ 11 | 12 | } 13 | 14 | bool DeepRTS::Criteria::FoodCount::evaluate(const Player &player) { 15 | isValid = player.food >= foodCountLimit; 16 | return isValid; 17 | } 18 | 19 | int DeepRTS::Criteria::FoodCount::reward() const { 20 | return (isValid) ? rewardSuccess : rewardFailure; 21 | } 22 | -------------------------------------------------------------------------------- /include/DeepRTS/state/Despawned.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 25.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_DESPAWNED_H 6 | #define WARC2SIM_DESPAWNED_H 7 | 8 | 9 | #include "../Constants.h" 10 | #include "BaseState.h" 11 | namespace DeepRTS { 12 | 13 | class Unit; 14 | 15 | class Despawned : public BaseState { 16 | public: 17 | Despawned() : BaseState(Constants::State::Despawned) { 18 | name = "Despawned"; 19 | } 20 | 21 | void update(Unit &unit) override; 22 | 23 | void init(Unit &unit) override; 24 | 25 | void end(Unit &unit) override; 26 | }; 27 | 28 | } 29 | #endif //WARC2SIM_DESPAWNED_H 30 | -------------------------------------------------------------------------------- /src/scenario/criteria/DamageTaken.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/DamageTaken.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::DamageTaken::DamageTaken(int damageTakenLimit, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , damageTakenLimit(damageTakenLimit){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::DamageTaken::evaluate(const Player &player) { 14 | isValid = player.sDamageTaken >= damageTakenLimit; 15 | return isValid; 16 | } 17 | 18 | int DeepRTS::Criteria::DamageTaken::reward() const { 19 | return (isValid) ? rewardSuccess : rewardFailure; 20 | } 21 | -------------------------------------------------------------------------------- /src/scenario/criteria/UnitsCreated.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/UnitsCreated.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::UnitsCreated::UnitsCreated(int unitsCreatedLimit, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , unitsCreatedLimit(unitsCreatedLimit){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::UnitsCreated::evaluate(const Player &player) { 14 | isValid = player.sUnitsCreated >= unitsCreatedLimit; 15 | return isValid; 16 | } 17 | 18 | int DeepRTS::Criteria::UnitsCreated::reward() const { 19 | return (isValid) ? rewardSuccess : rewardFailure; 20 | } 21 | -------------------------------------------------------------------------------- /examples/example_05/wrappers.py: -------------------------------------------------------------------------------- 1 | import gym 2 | import numpy as np 3 | 4 | 5 | class ImageToPyTorch(gym.ObservationWrapper): 6 | def __init__(self, env): 7 | super(ImageToPyTorch, self).__init__(env) 8 | self.original_shape = self.observation_space.shape 9 | self.observation_space = gym.spaces.Box( 10 | low=0.0, 11 | high=1.0, 12 | shape=( 13 | self.original_shape[-1], 14 | self.original_shape[0], 15 | self.original_shape[1] 16 | ), 17 | dtype=np.float32 18 | ) 19 | 20 | def observation(self, observation): 21 | return np.moveaxis(observation, 2, 0) -------------------------------------------------------------------------------- /src/scenario/criteria/GoldCollect.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/GoldCollect.h" 6 | #include "Player.h" 7 | 8 | 9 | DeepRTS::Criteria::GoldCollect::GoldCollect(int goldCollectedLimit, int rewardSuccess, int rewardFailure) 10 | : ScenarioCriteria(rewardSuccess, rewardFailure) 11 | , goldCollectedLimit(goldCollectedLimit){ 12 | } 13 | 14 | bool DeepRTS::Criteria::GoldCollect::evaluate(const Player &player) { 15 | isValid = player.sGatheredGold >= goldCollectedLimit; 16 | return isValid; 17 | } 18 | 19 | int DeepRTS::Criteria::GoldCollect::reward() const { 20 | return (isValid) ? rewardSuccess : rewardFailure; 21 | } 22 | -------------------------------------------------------------------------------- /src/scenario/criteria/StoneCollect.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/StoneCollect.h" 6 | #include "Player.h" 7 | 8 | DeepRTS::Criteria::StoneCollect::StoneCollect(int stoneCollectLimit, int rewardSuccess, int rewardFailure) 9 | : ScenarioCriteria(rewardSuccess, rewardFailure) 10 | , stoneCollectLimit(stoneCollectLimit){ 11 | 12 | } 13 | 14 | bool DeepRTS::Criteria::StoneCollect::evaluate(const Player &player) { 15 | isValid = player.sGatheredStone > stoneCollectLimit; 16 | return isValid; 17 | } 18 | 19 | int DeepRTS::Criteria::StoneCollect::reward() const { 20 | return (isValid) ? rewardSuccess : rewardFailure; 21 | } 22 | -------------------------------------------------------------------------------- /bindings/BaseState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace py = pybind11; 4 | 5 | #include "../include/DeepRTS/state/BaseState.h" 6 | #include "../include/DeepRTS/state/Walking.h" 7 | #include "../include/DeepRTS/Constants.h" 8 | using DeepRTS::BaseState; 9 | 10 | void init_BaseState(py::module &m) { 11 | 12 | //py::class_, BaseState>(m, "Walking") 13 | // .def(py::init()); 14 | 15 | 16 | py::class_>(m, "BaseState") 17 | //.def(py::init()) 18 | .def_readonly("id", &BaseState::id) 19 | .def_readonly("name", &BaseState::name); 20 | } 21 | -------------------------------------------------------------------------------- /src/scenario/criteria/LumberCollect.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/LumberCollect.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::LumberCollect::LumberCollect(int lumberCollectLimit, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , lumberCollectLimit(lumberCollectLimit){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::LumberCollect::evaluate(const Player &player) { 14 | isValid = player.sGatheredLumber >= lumberCollectLimit; 15 | return isValid; 16 | } 17 | 18 | int DeepRTS::Criteria::LumberCollect::reward() const { 19 | return (isValid) ? rewardSuccess : rewardFailure; 20 | } 21 | -------------------------------------------------------------------------------- /src/scenario/criteria/FoodConsumption.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/FoodConsumption.h" 6 | #include "Player.h" 7 | 8 | DeepRTS::Criteria::FoodConsumption::FoodConsumption(int foodConsumptionLimit, int rewardSuccess, int rewardFailure) 9 | : ScenarioCriteria(rewardSuccess, rewardFailure) 10 | , foodConsumptionLimit(foodConsumptionLimit){ 11 | 12 | } 13 | 14 | bool DeepRTS::Criteria::FoodConsumption::evaluate(const Player &player) { 15 | isValid = player.foodConsumption >= foodConsumptionLimit; 16 | return isValid; 17 | } 18 | 19 | int DeepRTS::Criteria::FoodConsumption::reward() const { 20 | return (isValid) ? rewardSuccess : rewardFailure; 21 | } 22 | -------------------------------------------------------------------------------- /include/DeepRTS/state/BaseState.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #pragma once 6 | 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include "../Constants.h" 13 | 14 | namespace DeepRTS { 15 | 16 | class Unit; 17 | 18 | class BaseState { 19 | 20 | 21 | public: 22 | Constants::State id = Constants::State::Base; 23 | std::string name = "**ERR**"; 24 | 25 | BaseState(Constants::State id) : id(id) { 26 | }; 27 | 28 | virtual ~BaseState() = 0; 29 | 30 | virtual void update(Unit &unit); 31 | 32 | virtual void init(Unit &unit); 33 | 34 | virtual void end(Unit &unit); 35 | }; 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/example_03/scenario_test.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | if __name__ == "__main__": 7 | x = Scenario( 8 | python.Game("15x15-2v2.json", n_players=2), 9 | Scenario.GOLD_COLLECT(1), 10 | Scenario.STONE_COLLECT(1), 11 | Scenario.LUMBER_COLLECT(1), 12 | Scenario.FOOD_CONSUMPTION(1), 13 | Scenario.FOOD_COUNT(1), 14 | Scenario.DAMAGE_DONE(1), 15 | Scenario.DAMAGE_TAKEN(1), 16 | Scenario.UNITS_CREATED(1), 17 | Scenario.NUM_FOOTMAN(1), 18 | Scenario.NUM_PEASANT(1), 19 | Scenario.NUM_ARCHER(1), 20 | Scenario.NUM_FARM(1), 21 | Scenario.NUM_BARRACKS(1), 22 | Scenario.NUM_TOWN_HALL(1) 23 | ) 24 | 25 | print(x.evaluate()) 26 | -------------------------------------------------------------------------------- /src/scenario/criteria/DamageDoneIncrement.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/DamageDoneIncrement.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::DamageDoneIncrement::DamageDoneIncrement(int amount, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , amount(amount){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::DamageDoneIncrement::evaluate(const Player &player) { 14 | isValid = player.sDamageDone > lastValue; 15 | lastValue = player.sDamageDone; 16 | return player.sDamageDone >= amount; 17 | } 18 | 19 | int DeepRTS::Criteria::DamageDoneIncrement::reward() const { 20 | return (isValid) ? rewardSuccess : rewardFailure; 21 | } 22 | -------------------------------------------------------------------------------- /include/DeepRTS/util/String.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 1/11/21. 3 | // 4 | 5 | #ifndef DEEPRTS_STRING_H 6 | #define DEEPRTS_STRING_H 7 | #include 8 | #include 9 | #include 10 | #include 11 | class StringUtil{ 12 | 13 | 14 | public: 15 | static std::vector split(const std::string& str,const std::string& sep){ 16 | char* cstr=const_cast(str.c_str()); 17 | char* current; 18 | std::vector arr; 19 | current=strtok(cstr,sep.c_str()); 20 | while(current!=NULL){ 21 | arr.emplace_back(current); 22 | current=strtok(NULL,sep.c_str()); 23 | } 24 | return arr; 25 | } 26 | }; 27 | 28 | #endif //DEEPRTS_STRING_H 29 | -------------------------------------------------------------------------------- /src/scenario/criteria/DamageTakenIncrement.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/DamageTakenIncrement.h" 6 | #include "Player.h" 7 | 8 | DeepRTS::Criteria::DamageTakenIncrement::DamageTakenIncrement(int amount, int rewardSuccess, int rewardFailure) 9 | : ScenarioCriteria(rewardSuccess, rewardFailure) 10 | , amount(amount){ 11 | 12 | } 13 | 14 | bool DeepRTS::Criteria::DamageTakenIncrement::evaluate(const Player &player) { 15 | isValid = player.sDamageTaken > lastValue; 16 | lastValue = player.sDamageTaken; 17 | return player.sDamageTaken >= amount; 18 | } 19 | 20 | int DeepRTS::Criteria::DamageTakenIncrement::reward() const { 21 | return (isValid) ? rewardSuccess : rewardFailure; 22 | } 23 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/GameEnd.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/9/21. 3 | // 4 | 5 | #ifndef DEEPRTS_GAMEEND_H 6 | #define DEEPRTS_GAMEEND_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class GameEnd: public ScenarioCriteria { 12 | 13 | bool rewardable{}; 14 | public: 15 | explicit GameEnd(int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | [[nodiscard]] int reward() const override; 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new GameEnd(*this)); 21 | } 22 | 23 | }; 24 | 25 | } 26 | 27 | 28 | 29 | #endif //DEEPRTS_GAMEEND_H 30 | -------------------------------------------------------------------------------- /src/scenario/criteria/GameEnd.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/9/21. 3 | // 4 | 5 | #include "scenario/criterias/GameEnd.h" 6 | #include "Player.h" 7 | #include "Game.h" 8 | bool DeepRTS::Criteria::GameEnd::evaluate(const Player &player) { 9 | rewardable = player.getState() == Constants::PlayerState::Playing; 10 | 11 | return std::all_of(player.getGame().players.begin(), player.getGame().players.end(), [](auto&p){ 12 | return p.getState() == Constants::PlayerState::Defeat; 13 | }); 14 | 15 | } 16 | 17 | int DeepRTS::Criteria::GameEnd::reward() const { 18 | return (rewardable) ? rewardSuccess : rewardFailure; 19 | } 20 | 21 | DeepRTS::Criteria::GameEnd::GameEnd(int rewardSuccess, int rewardFailure) 22 | : ScenarioCriteria(rewardSuccess, rewardFailure) 23 | { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/pages/dqn/results_1/results_1.md: -------------------------------------------------------------------------------- 1 | # Deep Q-Network - Initial Results 2 | These are the initial restults when first setting up the python binding 3 | 4 | The following action set were defined: 5 | ```cpp 6 | enum Action { 7 | PreviousUnit = 1, 8 | NextUnit = 2, 9 | RightLeft = 3, 10 | RightRight = 4, 11 | RightUp = 5, 12 | RightDown = 6, 13 | RightUpLeft = 7, 14 | RightUpRight = 8, 15 | RightDownLeft = 9, 16 | RightDownRight = 10, 17 | Build0 = 11, 18 | Build1 = 12, 19 | Build2 = 13, 20 | NoAction = 14 21 | }; 22 | ``` 23 | 24 | ## 2000 Frames, No config of dqn 25 | ![14.03.17-dqn-noconf-2000-frames](14.03.17-dqn-noconf-2000-frames.png) 26 | 27 | ## 12000 Frames, No config of dqn 28 | ![15.03.17-dqn-noconf-12000-frames](15.03.17-dqn-noconf-12000-frames.png) 29 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | requires-python = ">=3.8" 3 | 4 | [build-system] 5 | requires = [ 6 | "setuptools>=41", 7 | "wheel", 8 | "cmake", 9 | "ninja", 10 | "setuptools-git-versioning<2", 11 | "numpy", 12 | "pybind11[global]" 13 | ] 14 | build-backend = "setuptools.build_meta" 15 | 16 | [tool.setuptools-git-versioning] 17 | enabled = true 18 | 19 | [tool.cibuildwheel] 20 | build = "cp3{8,9,10,11}-musl*" 21 | manylinux-x86_64-image = "manylinux_2_28" 22 | 23 | 24 | [tool.cibuildwheel.macos] 25 | archs = ["x86_64", "arm64"] #"universal2", 26 | 27 | repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" 28 | 29 | 30 | [tool.cibuildwheel.linux] 31 | archs = ["x86_64"] 32 | repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel}" 33 | -------------------------------------------------------------------------------- /Doxyfile.in: -------------------------------------------------------------------------------- 1 | OUTPUT_DIRECTORY = @CMAKE_CURRENT_SOURCE_DIR@/docs/api/ 2 | INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include/ @CMAKE_CURRENT_SOURCE_DIR@/src 3 | INPUT += @CMAKE_CURRENT_SOURCE_DIR@/README.md 4 | USE_MDFILE_AS_MAINPAGE = README.md 5 | DOXYFILE_ENCODING = UTF-8 6 | RECURSIVE = YES 7 | PROJECT_NAME = "Deep RTS" 8 | PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/docs/logo.png 9 | EXTRACT_ALL = YES 10 | FILE_PATTERNS = *.c \ 11 | *.cc \ 12 | *.cxx \ 13 | *.cpp \ 14 | *.c++ \ 15 | *.h \ 16 | *.hh \ 17 | *.hxx \ 18 | *.hpp \ 19 | *.h++ 20 | -------------------------------------------------------------------------------- /DeepRTS/python/ml/agent.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | class BaseAgent(abc.ABC): 5 | 6 | def __init__(self, env=None, player=None): 7 | self.env = env 8 | self.player = player 9 | 10 | @abc.abstractmethod 11 | def get_state(self): 12 | raise NotImplementedError() 13 | 14 | @abc.abstractmethod 15 | def get_action(self, obs): 16 | raise NotImplementedError() 17 | 18 | def set_player(self, player): 19 | self.player = player 20 | 21 | def set_env(self, env): 22 | self.env = env 23 | 24 | @abc.abstractmethod 25 | def memorize(self, obs, obs1, action, reward, terminal, info): 26 | raise NotImplementedError() 27 | 28 | @abc.abstractmethod 29 | def state_preprocess(self, obs): 30 | pass 31 | 32 | def save(self, filename): 33 | raise NotImplementedError() 34 | 35 | def load(self, filename): 36 | raise NotImplementedError() -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/FoodCount.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_FOODCOUNT_H 6 | #define DEEPRTS_FOODCOUNT_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | 11 | namespace DeepRTS::Criteria{ 12 | class FoodCount: public ScenarioCriteria { 13 | int foodCountLimit; 14 | bool isValid; 15 | public: 16 | explicit FoodCount(int foodCountLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 17 | 18 | [[nodiscard]] bool evaluate(const Player& player) override; 19 | [[nodiscard]] int reward() const override; 20 | 21 | [[nodiscard]] std::shared_ptr clone() const override{ 22 | return std::shared_ptr(new FoodCount(*this)); 23 | } 24 | }; 25 | 26 | } 27 | 28 | 29 | 30 | #endif //DEEPRTS_FOODCOUNT_H 31 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/GoldCollect.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_GOLDCOLLECT_H 6 | #define DEEPRTS_GOLDCOLLECT_H 7 | #include "ScenarioCriteria.h" 8 | namespace DeepRTS::Criteria{ 9 | class GoldCollect: public ScenarioCriteria { 10 | int goldCollectedLimit; 11 | bool isValid; 12 | public: 13 | explicit GoldCollect(int goldCollectedLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 14 | 15 | [[nodiscard]] bool evaluate(const Player& player) override; 16 | [[nodiscard]] int reward() const override; 17 | [[nodiscard]] std::shared_ptr clone() const override{ 18 | return std::shared_ptr(new GoldCollect(*this)); 19 | } 20 | 21 | }; 22 | 23 | } 24 | 25 | 26 | #endif //DEEPRTS_GOLDCOLLECT_H 27 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/StoneCollect.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_STONECOLLECT_H 6 | #define DEEPRTS_STONECOLLECT_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class StoneCollect: public ScenarioCriteria { 12 | int stoneCollectLimit; 13 | bool isValid; 14 | public: 15 | explicit StoneCollect(int stonerCollectLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | [[nodiscard]] int reward() const override; 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new StoneCollect(*this)); 21 | } 22 | 23 | }; 24 | } 25 | #endif //DEEPRTS_STONECOLLECT_H 26 | -------------------------------------------------------------------------------- /include/DeepRTS/gui/PyGUI.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 06.06.18. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include "BaseGUI.h" 8 | namespace DeepRTS { 9 | 10 | class Tile; 11 | 12 | class PyGUI : public BaseGUI { 13 | private: 14 | pybind11::object gui; 15 | pybind11::object gui_attr_on_tile_change; 16 | 17 | pybind11::object gui_attr_render; 18 | pybind11::object gui_attr_view; 19 | 20 | static void initDependencies(); 21 | 22 | static void initArgv(); 23 | 24 | static void initCython(); 25 | 26 | void initGUI(); 27 | 28 | public: 29 | cv::Mat renderData; // TODO 30 | PyGUI(Game &); 31 | 32 | ~PyGUI(); 33 | 34 | const cv::Mat &render() const override; 35 | 36 | void onTileChange(const Tile &tile); 37 | }; 38 | } -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/DamageDone.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_DAMAGEDONE_H 6 | #define DEEPRTS_DAMAGEDONE_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class DamageDone: public ScenarioCriteria { 12 | int damageDone; 13 | bool isValid; 14 | public: 15 | explicit DamageDone(int damageDone, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | 19 | [[nodiscard]] int reward() const override; 20 | 21 | [[nodiscard]] std::shared_ptr clone() const override{ 22 | return std::shared_ptr(new DamageDone(*this)); 23 | } 24 | 25 | }; 26 | 27 | } 28 | 29 | 30 | 31 | 32 | #endif //DEEPRTS_DAMAGEDONE_H 33 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/LumberCollect.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_LUMBERCOLLECT_H 6 | #define DEEPRTS_LUMBERCOLLECT_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class LumberCollect: public ScenarioCriteria { 12 | int lumberCollectLimit; 13 | bool isValid; 14 | public: 15 | explicit LumberCollect(int lumberCollectLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | [[nodiscard]] int reward() const override; 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new LumberCollect(*this)); 21 | } 22 | }; 23 | } 24 | 25 | 26 | #endif //DEEPRTS_LUMBERCOLLECT_H 27 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/DamageTaken.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_DAMAGETAKEN_H 6 | #define DEEPRTS_DAMAGETAKEN_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | 11 | namespace DeepRTS::Criteria{ 12 | class DamageTaken: public ScenarioCriteria { 13 | int damageTakenLimit; 14 | bool isValid; 15 | public: 16 | explicit DamageTaken(int damageTakenLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 17 | 18 | [[nodiscard]] bool evaluate(const Player& player) override; 19 | [[nodiscard]] int reward() const override; 20 | [[nodiscard]] std::shared_ptr clone() const override{ 21 | return std::shared_ptr(new DamageTaken(*this)); 22 | } 23 | 24 | }; 25 | 26 | } 27 | 28 | 29 | 30 | #endif //DEEPRTS_DAMAGETAKEN_H 31 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: clang++ build active file", 6 | "command": "/usr/bin/clang++", 7 | "args": [ 8 | "-fcolor-diagnostics", 9 | "-fansi-escape-codes", 10 | "-g", 11 | "${file}", 12 | "-o", 13 | "${fileDirname}/${fileBasenameNoExtension}" 14 | ], 15 | "options": { 16 | "cwd": "${fileDirname}" 17 | }, 18 | "problemMatcher": [ 19 | "$gcc" 20 | ], 21 | "group": { 22 | "kind": "build", 23 | "isDefault": true 24 | }, 25 | "detail": "Task generated by Debugger." 26 | } 27 | ], 28 | "version": "2.0.0" 29 | } -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/UnitsCreated.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_UNITSCREATED_H 6 | #define DEEPRTS_UNITSCREATED_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | 11 | namespace DeepRTS::Criteria{ 12 | class UnitsCreated: public ScenarioCriteria { 13 | int unitsCreatedLimit; 14 | bool isValid; 15 | public: 16 | explicit UnitsCreated(int unitsCreatedLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 17 | 18 | [[nodiscard]] bool evaluate(const Player& player) override; 19 | [[nodiscard]] int reward() const override; 20 | [[nodiscard]] std::shared_ptr clone() const override{ 21 | return std::shared_ptr(new UnitsCreated(*this)); 22 | } 23 | 24 | }; 25 | 26 | } 27 | 28 | 29 | 30 | #endif //DEEPRTS_UNITSCREATED_H 31 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/FoodConsumption.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_FOODCONSUMPTION_H 6 | #define DEEPRTS_FOODCONSUMPTION_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class FoodConsumption: public ScenarioCriteria { 12 | int foodConsumptionLimit; 13 | bool isValid; 14 | public: 15 | explicit FoodConsumption(int foodConsumptionLimit, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | [[nodiscard]] int reward() const override; 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new FoodConsumption(*this)); 21 | } 22 | 23 | }; 24 | 25 | } 26 | 27 | 28 | 29 | #endif //DEEPRTS_FOODCONSUMPTION_H 30 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/DamageDoneIncrement.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_DAMAGEDONEINCREMENT_H 6 | #define DEEPRTS_DAMAGEDONEINCREMENT_H 7 | 8 | 9 | #include "ScenarioCriteria.h" 10 | namespace DeepRTS::Criteria{ 11 | class DamageDoneIncrement: public ScenarioCriteria { 12 | int amount; 13 | int lastValue = 0; 14 | 15 | bool isValid; 16 | public: 17 | explicit DamageDoneIncrement(int amount, int rewardSuccess=0.01, int rewardFailure=-0.01); 18 | 19 | [[nodiscard]] bool evaluate(const Player& player) override; 20 | [[nodiscard]] int reward() const override; 21 | [[nodiscard]] std::shared_ptr clone() const override{ 22 | return std::shared_ptr(new DamageDoneIncrement(*this)); 23 | } 24 | }; 25 | 26 | } 27 | 28 | 29 | #endif //DEEPRTS_DAMAGEDONEINCREMENT_H 30 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/DamageTakenIncrement.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_DAMAGETAKENINCREMENT_H 6 | #define DEEPRTS_DAMAGETAKENINCREMENT_H 7 | 8 | #include "ScenarioCriteria.h" 9 | namespace DeepRTS::Criteria{ 10 | class DamageTakenIncrement: public ScenarioCriteria { 11 | int amount; 12 | int lastValue = 0; 13 | bool isValid; 14 | public: 15 | explicit DamageTakenIncrement(int amount, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | 19 | [[nodiscard]] int reward() const override; 20 | [[nodiscard]] std::shared_ptr clone() const override{ 21 | return std::shared_ptr(new DamageTakenIncrement(*this)); 22 | } 23 | 24 | }; 25 | 26 | } 27 | 28 | 29 | 30 | #endif //DEEPRTS_DAMAGETAKENINCREMENT_H 31 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/UnitIncrement.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_UNITINCREMENT_H 6 | #define DEEPRTS_UNITINCREMENT_H 7 | #include "ScenarioCriteria.h" 8 | #include "Constants.h" 9 | namespace DeepRTS::Criteria{ 10 | class UnitIncrement: public ScenarioCriteria { 11 | int lastValue = 0; 12 | bool isValid; 13 | const Constants::Unit unitType; 14 | public: 15 | explicit UnitIncrement(Constants::Unit unitType, int amount, int rewardSuccess=0.01, int rewardFailure=-0.01); 16 | [[nodiscard]] bool evaluate(const Player& player) override; 17 | [[nodiscard]] int reward() const override; 18 | 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new UnitIncrement(*this)); 21 | } 22 | 23 | }; 24 | 25 | } 26 | 27 | 28 | #endif //DEEPRTS_UNITINCREMENT_H 29 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/ScenarioCriteria.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_SCENARIOCRITERIA_H 6 | #define DEEPRTS_SCENARIOCRITERIA_H 7 | #include 8 | #include "ScenarioCriteria.h" 9 | #include 10 | 11 | namespace DeepRTS{ 12 | class Player; 13 | } 14 | 15 | 16 | 17 | 18 | namespace DeepRTS::Criteria { 19 | class ScenarioCriteria { 20 | 21 | protected: 22 | const int rewardSuccess; 23 | const int rewardFailure; 24 | public: 25 | using ScenarioContainer = std::vector>; 26 | ScenarioCriteria(int rewardSuccess=0.01, int rewardFailure=-0.01); 27 | 28 | virtual std::shared_ptr clone() const = 0; 29 | virtual bool evaluate(const Player& player) = 0; 30 | virtual int reward() const = 0; 31 | 32 | 33 | 34 | }; 35 | 36 | } 37 | 38 | #endif //DEEPRTS_SCENARIOCRITERIA_H 39 | -------------------------------------------------------------------------------- /include/DeepRTS/state/StateManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | #pragma once 5 | #include "Spawning.h" 6 | #include "Walking.h" 7 | #include "Idle.h" 8 | #include "Despawned.h" 9 | #include "Harvesting.h" 10 | #include "Building.h" 11 | #include "Combat.h" 12 | #include "Dead.h" 13 | namespace DeepRTS { 14 | 15 | class Game; 16 | 17 | class StateManager { 18 | 19 | public: 20 | explicit StateManager(Game &game); 21 | 22 | std::shared_ptr walkingState; 23 | std::shared_ptr spawnState; 24 | std::shared_ptr idleState; 25 | std::shared_ptr despawnedState; 26 | std::shared_ptr harvestingState; 27 | std::shared_ptr buildingState; 28 | std::shared_ptr combatState; 29 | std::shared_ptr deadState; 30 | 31 | std::shared_ptr getByID(int id) const; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/scenario/scenarios/GoldCollectFifteen.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/scenarios/GoldCollectFifteen.h" 6 | #include "Constants.h" 7 | #include "scenario/criterias/GoldCollect.h" 8 | 9 | DeepRTS::Scenarios::GoldCollectFifteen::GoldCollectFifteen() 10 | : Scenario( 11 | Constants::Map::EBLIL, 12 | Config::defaults(), 13 | { 14 | std::make_shared(10) 15 | } 16 | ){ 17 | addPlayer(); 18 | } 19 | 20 | DeepRTS::Scenarios::Scenario::ActionSequenceContainer DeepRTS::Scenarios::GoldCollectFifteen::optimalStrategy() { 21 | return { 22 | {Constants::MoveRight, "Peasant0"}, 23 | {Constants::MoveRight, "Peasant0"}, 24 | {Constants::MoveRight, "Peasant0"}, 25 | {Constants::MoveRight, "Peasant0"}, 26 | {Constants::MoveDownRight, "Peasant0"}, 27 | {Constants::MoveRight, "Peasant0"}, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/NumUnitTypeCreated.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_NUMUNITTYPECREATED_H 6 | #define DEEPRTS_NUMUNITTYPECREATED_H 7 | 8 | #include "Constants.h" 9 | #include "ScenarioCriteria.h" 10 | 11 | namespace DeepRTS::Criteria{ 12 | class NumUnitTypeCreated: public ScenarioCriteria { 13 | const Constants::Unit unitType; 14 | bool isValid; 15 | const int count; 16 | public: 17 | explicit NumUnitTypeCreated(Constants::Unit unitType, int count, int rewardSuccess=0.01, int rewardFailure=-0.01); 18 | 19 | [[nodiscard]] bool evaluate(const Player& player) override; 20 | [[nodiscard]] int reward() const override; 21 | [[nodiscard]] std::shared_ptr clone() const override{ 22 | return std::shared_ptr(new NumUnitTypeCreated(*this)); 23 | } 24 | 25 | }; 26 | 27 | } 28 | 29 | 30 | 31 | #endif //DEEPRTS_NUMUNITTYPECREATED_H 32 | -------------------------------------------------------------------------------- /include/DeepRTS/util/PriorityQueue.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 26.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_PRIORITYQUEUE_H 6 | #define WARC2SIM_PRIORITYQUEUE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | template 13 | struct PriorityQueue { 14 | typedef std::pair PQElement; 15 | std::priority_queue, 16 | std::greater> elements; 17 | 18 | inline bool empty() const { return elements.empty(); } 19 | 20 | inline void put(T item, priority_t priority) { 21 | elements.emplace(priority, item); 22 | } 23 | 24 | inline T get() { 25 | T best_item = elements.top().second; 26 | elements.pop(); 27 | return best_item; 28 | } 29 | inline void clear() 30 | { 31 | 32 | while(!empty()){ 33 | 34 | elements.pop(); 35 | } 36 | } 37 | 38 | }; 39 | #endif //WARC2SIM_PRIORITYQUEUE_H 40 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/criterias/ResourceIncrement.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_RESOURCEINCREMENT_H 6 | #define DEEPRTS_RESOURCEINCREMENT_H 7 | 8 | #include "ScenarioCriteria.h" 9 | #include "Constants.h" 10 | namespace DeepRTS::Criteria{ 11 | class ResourceIncrement: public ScenarioCriteria { 12 | int lastValue = 0; 13 | bool isValid; 14 | const Constants::Resource resourceType; 15 | public: 16 | explicit ResourceIncrement(Constants::Resource resourceType, int amount, int rewardSuccess=0.01, int rewardFailure=-0.01); 17 | [[nodiscard]] bool evaluate(const Player& player) override; 18 | [[nodiscard]] int reward() const override; 19 | [[nodiscard]] std::shared_ptr clone() const override{ 20 | return std::shared_ptr(new ResourceIncrement(*this)); 21 | } 22 | 23 | 24 | }; 25 | 26 | } 27 | 28 | 29 | 30 | #endif //DEEPRTS_RESOURCEINCREMENT_H 31 | -------------------------------------------------------------------------------- /bindings/trampolines/PyScenarioCriteria.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/8/21. 3 | // 4 | 5 | #ifndef DEEPRTS_PYSCENARIOCRITERIA_H 6 | #define DEEPRTS_PYSCENARIOCRITERIA_H 7 | #include 8 | #include "scenario/criterias/ScenarioCriteria.h" 9 | using DeepRTS::Criteria::ScenarioCriteria; 10 | using DeepRTS::Game; 11 | using DeepRTS::Player; 12 | 13 | class PyScenarioCriteria: public ScenarioCriteria { 14 | using ScenarioCriteria::ScenarioCriteria; 15 | 16 | 17 | 18 | [[nodiscard]] std::shared_ptr clone() const override { 19 | PYBIND11_OVERRIDE_PURE(std::shared_ptr, PyScenarioCriteria, clone, ); 20 | } 21 | 22 | [[nodiscard]] bool evaluate(const Player& player) override { 23 | PYBIND11_OVERRIDE_PURE(bool, PyScenarioCriteria, evaluate, ); 24 | } 25 | 26 | [[nodiscard]] int reward() const override { 27 | PYBIND11_OVERRIDE_PURE(int, PyScenarioCriteria, reward,); 28 | } 29 | }; 30 | 31 | 32 | 33 | 34 | #endif //DEEPRTS_PYSCENARIOCRITERIA_H 35 | -------------------------------------------------------------------------------- /bindings/utilities/ndarray_converter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/8/21. 3 | // 4 | 5 | # ifndef __NDARRAY_CONVERTER_H__ 6 | # define __NDARRAY_CONVERTER_H__ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | class NDArrayConverter { 14 | public: 15 | // must call this first, or the other routines don't work! 16 | static bool init_numpy(); 17 | 18 | static bool toMat(PyObject* o, cv::Mat &m); 19 | static PyObject* toNDArray(const cv::Mat& mat); 20 | }; 21 | 22 | namespace pybind11::detail { 23 | 24 | template <> struct type_caster: public type_caster_base { 25 | using base = type_caster_base; 26 | public: 27 | 28 | bool load(handle src, bool /* convert */) { 29 | return NDArrayConverter::toMat(src.ptr(), *this); 30 | } 31 | 32 | static handle cast(const cv::Mat &m, return_value_policy, handle defval) { 33 | return handle(NDArrayConverter::toNDArray(m)); 34 | } 35 | }; 36 | 37 | 38 | } // namespace pybind11::detail 39 | 40 | # endif 41 | 42 | -------------------------------------------------------------------------------- /examples/example_02/scenario_01.py: -------------------------------------------------------------------------------- 1 | from DeepRTS import Engine 2 | import cv2 3 | 4 | if __name__ == "__main__": 5 | # Minimal example of DeepRTS Scenario 6 | 7 | 8 | 9 | num_episodes = 100000 10 | 11 | config: Engine.Config = Engine.Config().defaults() 12 | config.set_console_caption_enabled(True) 13 | config.set_gui("Blend2DGui") 14 | 15 | game: Engine.Game = Engine.scenario.GoldCollectFifteen() 16 | player0: Engine.Player = game.add_player() 17 | player1: Engine.Player = game.add_player() 18 | 19 | game.set_max_fps(0) # 0 = unlimited 20 | game.start() 21 | 22 | for i in range(num_episodes): 23 | 24 | game.reset() 25 | while not game.is_terminal(): 26 | player0.do_action(Engine.Random.get(Engine.Constants.ACTION_MIN, Engine.Constants.ACTION_MAX)) 27 | player1.do_action(Engine.Random.get(Engine.Constants.ACTION_MIN, Engine.Constants.ACTION_MAX)) 28 | 29 | game.update() 30 | state = game.state 31 | image = game.render() 32 | 33 | cv2.imshow("DeepRTS", image) 34 | cv2.waitKey(1) 35 | game.caption() -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2017 Per-Arne Andersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/DeepRTS/util/Pathfinder.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 26.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_PATHFINDER_H 6 | #define WARC2SIM_PATHFINDER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | namespace DeepRTS { 15 | 16 | 17 | class Tile; 18 | 19 | class Pathfinder { 20 | 21 | public: 22 | static bool aStar(std::vector &constructedPath, Tile *start, Tile *goal); 23 | 24 | static double heuristic(Tile *pTile, Tile *next); 25 | 26 | static double crossover(Tile *pTile, Tile *start, Tile *goal); 27 | 28 | [[maybe_unused]] static Tile *find_closest_walkable_tile(Tile *start, Tile *destination, int range); 29 | 30 | static Tile *find_first_walkable_tile(Tile *start); 31 | 32 | static Tile *find_first_harvestable_tile(Tile *pTile); 33 | 34 | 35 | static std::vector 36 | reconstruct_path(Tile *start, Tile *goal, std::unordered_map &came_from); 37 | 38 | static Tile *find_first_attackable_tile(Tile *start); 39 | }; 40 | 41 | } 42 | 43 | #endif //WARC2SIM_PATHFINDER_H 44 | -------------------------------------------------------------------------------- /src/scenario/scenarios/LavaMaze.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/11/21. 3 | // 4 | #include 5 | #include 6 | #include "scenario/scenarios/LavaMaze.h" 7 | 8 | 9 | DeepRTS::Scenarios::LavaMaze::LavaMaze() 10 | : Scenario( 11 | Constants::Map::GONDOR, 12 | getConfig(), 13 | { 14 | std::make_shared(Constants::Resource::Stone, 1) 15 | }) 16 | { 17 | addPlayer(); 18 | } 19 | 20 | DeepRTS::Scenarios::Scenario::ActionSequenceContainer DeepRTS::Scenarios::LavaMaze::optimalStrategy() { 21 | return Scenario::optimalStrategy(); 22 | } 23 | 24 | DeepRTS::Config DeepRTS::Scenarios::LavaMaze::getConfig(){ 25 | Config config; 26 | config.setBarracks(true); 27 | config.setFootman(true); 28 | config.setInstantTownHall(true); 29 | config.setArcher(true); 30 | config.setStartLumber(0); 31 | config.setStartGold(0); 32 | config.setStartStone(0); 33 | config.setTileDamageModifier(100.0); 34 | config.setTickModifier(config.tickModifier); 35 | config.setInstantBuilding(true); 36 | return config; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /docs/pages/monte_carlo_methods.md: -------------------------------------------------------------------------------- 1 | # Monte Carlo Method 2 | From Wikipedia: 3 | > Monte Carlo methods (or Monte Carlo experiments) are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. Their essential idea is using randomness to solve problems that might be deterministic in principle. They are often used in physical and mathematical problems and are most useful when it is difficult or impossible to use other approaches. Monte Carlo methods are mainly used in three distinct problem classes:[1] optimization, numerical integration, and generating draws from a probability distribution. 4 | 5 | Real Time Strategy as a AI problem has a enormous state and action space, For example in a game like chess we can define the state space as: 6 | 7 | Board: 8x8 = 64 and Pieces: 32 8 | 9 | Which gives us ![](https://wik92733c1bff9c70c0e5d298b4f)=1,832,624,140,942,590,534 states 10 | 11 | This problem is highly related to 12 | [God's Algorithm](https://en.wikipedia.org/wiki/God%27s_algorithm) which refers to any algorithm which produces a solution having the fewest possible moves, the idea being that an omniscient being would know an optimal step from any given configuration. -------------------------------------------------------------------------------- /examples/example_01/basic_01.py: -------------------------------------------------------------------------------- 1 | from DeepRTS import Engine 2 | import cv2 3 | 4 | if __name__ == "__main__": 5 | # Minimal example of DeepRTS in python. 6 | # on my machine, the recorded FPS is: 60772 7 | # if you run purely in C++, the number is 4 001 004 8 | 9 | num_episodes = 100000 10 | 11 | config: Engine.Config = Engine.Config().defaults() 12 | config.set_console_caption_enabled(True) 13 | config.set_gui("Blend2DGui") 14 | 15 | game: Engine.Game = Engine.Game("10x10-2p-ffa-Eblil.json", config) 16 | player0: Engine.Player = game.add_player() 17 | player1: Engine.Player = game.add_player() 18 | 19 | game.set_max_fps(0) # 0 = unlimited 20 | game.start() 21 | 22 | for i in range(num_episodes): 23 | 24 | game.reset() 25 | while not game.is_terminal(): 26 | player0.do_action(Engine.Random.get(Engine.Constants.ACTION_MIN, Engine.Constants.ACTION_MAX)) 27 | player1.do_action(Engine.Random.get(Engine.Constants.ACTION_MIN, Engine.Constants.ACTION_MAX)) 28 | 29 | game.update() 30 | state = game.state 31 | image = game.render() 32 | 33 | # cv2.imshow("DeepRTS", image) 34 | # cv2.waitKey(1) 35 | game.caption() -------------------------------------------------------------------------------- /src/scenario/criteria/ResourceIncrement.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/ResourceIncrement.h" 6 | #include "Player.h" 7 | 8 | DeepRTS::Criteria::ResourceIncrement::ResourceIncrement(Constants::Resource resourceType, int amount, int rewardSuccess, int rewardFailure) 9 | : ScenarioCriteria(rewardSuccess, rewardFailure) 10 | , resourceType(resourceType){ 11 | 12 | } 13 | 14 | bool DeepRTS::Criteria::ResourceIncrement::evaluate(const Player &player) { 15 | bool state; 16 | switch (resourceType) { 17 | case Constants::Stone: 18 | state = player.sGatheredStone > lastValue; 19 | lastValue = player.sGatheredStone; 20 | break; 21 | case Constants::Gold: 22 | state = player.sGatheredGold > lastValue; 23 | lastValue = player.sGatheredGold; 24 | break; 25 | case Constants::Lumber: 26 | state = player.sGatheredLumber > lastValue; 27 | lastValue = player.sGatheredLumber; 28 | break; 29 | } 30 | isValid = state; 31 | return isValid; 32 | } 33 | 34 | int DeepRTS::Criteria::ResourceIncrement::reward() const { 35 | return (isValid) ? rewardSuccess : rewardFailure; 36 | } 37 | -------------------------------------------------------------------------------- /include/DeepRTS/util/ColorConverter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 27.02.2017. 3 | // 4 | 5 | #ifndef WARC2SIM_COLORCONVERTER_H 6 | #define WARC2SIM_COLORCONVERTER_H 7 | 8 | 9 | #include 10 | 11 | class ColorConverter { 12 | 13 | 14 | public: 15 | static sf::Color hsv(double hue, double sat, double val) 16 | { 17 | hue = fmod(hue, 360); 18 | while(hue<0) hue += 360; 19 | 20 | if(sat<0.f) sat = 0.f; 21 | if(sat>1.f) sat = 1.f; 22 | 23 | if(val<0.f) val = 0.f; 24 | if(val>1.f) val = 1.f; 25 | 26 | int h = hue/60; 27 | double f = (hue)/60-h; 28 | double p = val*(1.f-sat); 29 | double q = val*(1.f-sat*f); 30 | double t = val*(1.f-sat*(1-f)); 31 | 32 | switch(h) 33 | { 34 | default: 35 | case 0: 36 | case 6: return sf::Color(val*255, t*255, p*255); 37 | case 1: return sf::Color(q*255, val*255, p*255); 38 | case 2: return sf::Color(p*255, val*255, t*255); 39 | case 3: return sf::Color(p*255, q*255, val*255); 40 | case 4: return sf::Color(t*255, p*255, val*255); 41 | case 5: return sf::Color(val*255, p*255, q*255); 42 | } 43 | } 44 | }; 45 | 46 | 47 | #endif //WARC2SIM_COLORCONVERTER_H 48 | -------------------------------------------------------------------------------- /src/state/Building.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 26.02.2017. 3 | // 4 | 5 | #include "state/Building.h" 6 | #include "unit/Unit.h" 7 | #include "util/Pathfinder.h" 8 | #include "Player.h" 9 | using namespace DeepRTS; 10 | 11 | 12 | void Building::update(Unit & unit){ 13 | Unit &buildEntity = unit.getBuildEntity(); 14 | 15 | unit.buildTimer += 1; 16 | if(unit.buildTimer >= buildEntity.spawnDuration) { 17 | // Building is complete 18 | 19 | if(!unit.tile){ 20 | // Unit has no tile, means unit is despawned 21 | Tile *firstWalkable = Pathfinder::find_first_walkable_tile(buildEntity.tile); 22 | //assert(firstWalkable); 23 | unit.setPosition(*firstWalkable); 24 | unit.transitionState(); 25 | unit.player_.food += unit.foodProduction; 26 | unit.player_.foodConsumption += unit.foodConsumption; 27 | } else { 28 | 29 | // Unit has tile, needs to transition 30 | unit.transitionState(); 31 | 32 | } 33 | 34 | 35 | } 36 | 37 | } 38 | 39 | void Building::end(Unit & unit){ 40 | unit.buildEntityID = -1; 41 | unit.buildTimer = 0; 42 | } 43 | 44 | void Building::init(Unit & unit){ 45 | // Build timer is reset on end. this is so that we can override build time (i.e on spawn) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/state/Spawning.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | 6 | #include "state/Spawning.h" 7 | #include "unit/Unit.h" 8 | #include "util/Pathfinder.h" 9 | #include "Player.h" 10 | using namespace DeepRTS; 11 | 12 | void Spawning::update(Unit& unit){ 13 | 14 | if(unit.spawnTimer < unit.spawnDuration) { 15 | unit.spawnTimer += 1; 16 | return; 17 | } 18 | 19 | // Check if tile is occupied, if it is. We attempt to find a new one 20 | if (!unit.tile && unit.getSpawnTile().getOccupant()) { 21 | if (unit.builtByID != Constants::None) { 22 | Tile *newSpawnTile = Pathfinder::find_first_walkable_tile(unit.getBuiltBy().centerTile()); 23 | unit.spawnTileID = newSpawnTile->id; 24 | } 25 | else { 26 | // Unit must simply wait for tile to be available 27 | return; 28 | } 29 | } 30 | 31 | // Unit can spawn 32 | 33 | unit.transitionState(); 34 | if (unit.structure) { 35 | unit.direction = Constants::Direction::Up; 36 | } 37 | else{ 38 | unit.direction = Constants::Direction::Down; 39 | } 40 | unit.setPosition(unit.getSpawnTile()); 41 | 42 | 43 | } 44 | 45 | void Spawning::init(Unit & unit){ 46 | (void)(unit); 47 | } 48 | 49 | void Spawning::end(Unit & unit){ 50 | unit.builtByID = -1; 51 | } 52 | -------------------------------------------------------------------------------- /include/DeepRTS/scenario/Scenario.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #ifndef DEEPRTS_SCENARIO_H 6 | #define DEEPRTS_SCENARIO_H 7 | 8 | #include 9 | #include "criterias/ScenarioCriteria.h" 10 | namespace DeepRTS{ 11 | class Player; 12 | } 13 | 14 | namespace DeepRTS::Scenarios { 15 | class Scenario: public Game { 16 | public: 17 | 18 | Criteria::ScenarioCriteria::ScenarioContainer criteriaListTemplate; 19 | using ActionSequenceContainer = std::vector>; 20 | 21 | std::array criteriaList; 22 | explicit Scenario( 23 | const std::string& map, 24 | Config config, 25 | Criteria::ScenarioCriteria::ScenarioContainer &&criterias 26 | ); 27 | 28 | void update() override; 29 | 30 | [[nodiscard]] bool evaluate(const Player& player); 31 | [[nodiscard]] int reward(const Player &player); 32 | [[maybe_unused]] virtual ActionSequenceContainer optimalStrategy(); 33 | std::tuple computeOptimalStrategy(Player& player); 34 | std::tuple optimalPlayGameStep(Player &player); 35 | 36 | void reset() override; 37 | 38 | void createCriterionsForPlayers(); 39 | 40 | }; 41 | } 42 | 43 | #endif //DEEPRTS_SCENARIO_H 44 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/10x10-2p-ffa-Eblil.json: -------------------------------------------------------------------------------- 1 | { "height":10, 2 | "layers":[ 3 | { 4 | "data":[142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 270, 270, 270, 270, 270, 102, 102, 102, 142, 142, 270, 17, 270, 270, 270, 102, 102, 102, 142, 142, 270, 270, 270, 270, 270, 102, 102, 102, 142, 142, 270, 270, 270, 270, 270, 270, 270, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 270, 142, 142, 102, 102, 102, 270, 270, 270, 270, 270, 142, 142, 102, 102, 102, 270, 270, 270, 17, 270, 142, 142, 102, 102, 102, 270, 270, 270, 270, 270, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142], 5 | "height":10, 6 | "name":"Rutelag 1", 7 | "offsetx":3, 8 | "offsety":-2, 9 | "opacity":1, 10 | "type":"tilelayer", 11 | "visible":true, 12 | "width":10, 13 | "x":0, 14 | "y":0 15 | }], 16 | "nextobjectid":1, 17 | "orientation":"orthogonal", 18 | "renderorder":"right-down", 19 | "tileheight":32, 20 | "tilesets":[ 21 | { 22 | "columns":19, 23 | "firstgid":1, 24 | "image":"..\/textures\/tiles.png", 25 | "imageheight":659, 26 | "imagewidth":626, 27 | "margin":0, 28 | "name":"tiles", 29 | "spacing":1, 30 | "tilecount":380, 31 | "tileheight":32, 32 | "tilewidth":32 33 | }], 34 | "tilewidth":32, 35 | "version":1, 36 | "width":10 37 | } -------------------------------------------------------------------------------- /DeepRTS/python/config.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Config: 4 | 5 | DEFAULTS = dict( 6 | render=True, 7 | view=False, 8 | inputs=False, 9 | caption=False, 10 | unit_health=True, 11 | unit_outline=True, 12 | unit_animation=True, 13 | audio=False, 14 | audio_volume=50 15 | ) 16 | 17 | class Map: 18 | TEN = "10x10-2v2.json" 19 | FIFTEEN = "15x15-2v2.json" 20 | TWENTYONE = "21x21-2v2.json" 21 | THIRTYONE = "31x31-2v2.json" 22 | THIRTYONE_FOUR = "31x31-4v4.json" 23 | THIRTYONE_SIX = "31x31-6v6.json" 24 | FIND_GOLD = "scenario-find-gold.json" 25 | 26 | def __init__( 27 | self, 28 | render=DEFAULTS["render"], 29 | view=DEFAULTS["view"], 30 | inputs=DEFAULTS["inputs"], 31 | caption=DEFAULTS["caption"], 32 | unit_health=DEFAULTS["unit_health"], 33 | unit_outline=DEFAULTS["unit_outline"], 34 | unit_animation=DEFAULTS["unit_animation"], 35 | audio=DEFAULTS["audio"], 36 | audio_volume=DEFAULTS["audio_volume"] 37 | ): 38 | self.input = inputs 39 | self.render = render 40 | self.view = view 41 | self.caption = caption 42 | self.unit_health = unit_health 43 | self.unit_animation = unit_animation 44 | self.unit_outline = unit_outline 45 | self.audio = audio 46 | self.audio_volume = audio_volume 47 | -------------------------------------------------------------------------------- /docs/pages/performance_log.md: -------------------------------------------------------------------------------- 1 | # Performance Log of DeepRTS 2 | | Version | Date | UPS | maxfps | Reason | 3 | |-------|----------|-------------|----------|------| 4 | |Early game version| 27.01.17| x25 500| 1| Fewer game logics| 5 | |Pure python|03.02.17|x13 000| 1 | First "full" version| 6 | |100% Cython| 13.02.17| x17 000| 1| Converted all files to Cython, nothing more| 7 | |Pure python| 14.02.17| x20 000| 1| Went back to python because of suboptimal results 8 | |Dict impl| 14.02.17 | x25 000 | 1 | Improved game engine by using dict as data container for Player/Unit. Faster load/save 9 | |Player.pyx| 14.02.17 | x37 000 | 1 | Static Typing on all fields (Classes defined as object) 10 | |Game.pyx | 14.02.17 | x45 000 | 1 | Static Typing on all fields (Classes defined as object) 11 | |States| 15.02.17 | x55 000 | 1 | Static Typing on all states 12 | |Units| 15.02.17 | x77 000 | 1 | Static Typing on all units 13 | |Partial Conversion | 16.02.17 | x180 000 | 1 | Most code rewritten to Cython. Still much optimization potential 14 | |Cython 1.0 | 24.02.17 | x500 000 | 1 | Full Cython stack. However, all stacktrace gone 15 | |C++ | 27.02.17 | x2 700 000 | 60 | Early version of the game in C++ 16 | |C++ | 10.03.17 | x8 500 000 | 60 | Version 1.0 (Heap) 17 | |C++ | 13.03.17 | x52 000 000 | 60 | Version 1.1 (Stack) (NoGui) (Simple Engine) 18 | |C++ | 06.09.21 | x6 500 000 | x6 500 000 | Version 3.0 (Stack) (NoGui) (Full Engine)) 19 | |C++ | 06.09.21 | x3 000 000 | x3 000 000 | Version 3.0 (Stack) (GUI) (Full Engine)) 20 | These tests were done on 2x Intel(R) Xeon(R) CPU X5660 @ 2.80GHz where tests ran on a single core 21 | -------------------------------------------------------------------------------- /bindings/Tile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | namespace py = pybind11; 3 | 4 | #include 5 | #include "../include/DeepRTS/Tile.h" 6 | #include "../include/DeepRTS/Tilemap.h" 7 | #include "unit/Unit.h" 8 | using DeepRTS::Tile; 9 | using DeepRTS::Tilemap; 10 | void init_Tile(py::module &m) { 11 | py::class_(m, "Tile") 12 | .def(py::init()) 13 | .def_readonly("id", &Tile::id) 14 | .def_readonly("stone_yield", &Tile::stoneYield) 15 | .def_readonly("lumber_yield", &Tile::lumberYield) 16 | .def_readonly("gold_yield", &Tile::goldYield) 17 | .def_readonly("x", &Tile::x) 18 | .def_readonly("y", &Tile::y) 19 | .def_readonly("height", &Tile::height) 20 | .def_readonly("width", &Tile::width) 21 | 22 | 23 | .def("is_walkable", &Tile::isWalkable) 24 | .def("is_harvestable", &Tile::isHarvestable) 25 | .def("is_buildable", &Tile::isBuildable) 26 | .def("is_attackable", &Tile::isAttackable) 27 | .def("get_occupant", &Tile::getOccupant) // TODO - does not work 28 | .def("get_occupant_id", &Tile::getOccupantID) 29 | .def("has_occupant", &Tile::hasOccupant) 30 | .def("get_resources", &Tile::getResources) 31 | .def("get_type_id", &Tile::getTypeId) 32 | .def("is_depleted", &Tile::isDepleted) 33 | .def("get_name", &Tile::getName); 34 | 35 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Config.h" 4 | #include "Game.h" 5 | #include 6 | #include 7 | #include "scenario/scenarios/GoldCollectFifteen.h" 8 | #include "scenario/scenarios/LavaMaze.h" 9 | 10 | using Random = effolkronium::random_static; 11 | using DeepRTS::Config; 12 | using DeepRTS::Player; 13 | using DeepRTS::Scenarios::GoldCollectFifteen; 14 | int main() { 15 | //auto webServer = Webserver("0.0.0.0", 4300, true); 16 | //webServer.start(); 17 | Config config = Config::defaults(); 18 | config.setConsoleCaptionEnabled(true); 19 | config.setGUI(""); 20 | 21 | // auto g = Game("10x10-2v2.json", config); 22 | 23 | auto g = DeepRTS::Scenarios::LavaMaze(); 24 | 25 | Player &player0 = g.addPlayer(); 26 | Player &player1 = g.addPlayer(); 27 | 28 | g.setMaxFPS(0); 29 | g.start(); 30 | 31 | int EPISODES = 100000; 32 | 33 | g.getUnitByNameID("Test1"); 34 | 35 | 36 | for(auto episode=0; episode < EPISODES; episode++) 37 | { 38 | 39 | while(!g.isTerminal()) 40 | { 41 | 42 | player0.do_action(Random::get(DeepRTS::Constants::ACTION_MIN, DeepRTS::Constants::ACTION_MAX)); 43 | player1.do_action(Random::get(DeepRTS::Constants::ACTION_MIN, DeepRTS::Constants::ACTION_MAX)); 44 | 45 | g.update(); 46 | auto image = g.render(); 47 | g.caption(); 48 | 49 | 50 | cv::imshow("Title", image); 51 | cv::waitKey(1); 52 | 53 | 54 | 55 | } 56 | 57 | g.reset(); 58 | 59 | 60 | } 61 | } 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/state/StateManager.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #include "state/StateManager.h" 6 | #include "Game.h" 7 | 8 | using namespace DeepRTS; 9 | 10 | StateManager::StateManager(Game &game) 11 | { 12 | walkingState = std::shared_ptr(new Walking(game)); 13 | spawnState = std::shared_ptr(new Spawning()); 14 | idleState = std::shared_ptr(new Idle()); 15 | despawnedState = std::shared_ptr(new Despawned()); 16 | harvestingState = std::shared_ptr(new Harvesting()); 17 | buildingState = std::shared_ptr(new Building()); 18 | combatState = std::shared_ptr(new Combat()); 19 | deadState = std::shared_ptr(new Dead()); 20 | 21 | } 22 | 23 | 24 | std::shared_ptr StateManager::getByID(int id) const{ 25 | switch(id) { 26 | case Constants::State::Building: 27 | return buildingState; 28 | case Constants::State::Spawning: 29 | return spawnState; 30 | case Constants::State::Walking: 31 | return walkingState; 32 | case Constants::State::Idle: 33 | return idleState; 34 | case Constants::State::Despawned: 35 | return despawnedState; 36 | case Constants::State::Harvesting: 37 | return harvestingState; 38 | case Constants::State::Combat: 39 | return combatState; 40 | case Constants::State::Dead: 41 | return deadState; 42 | default: 43 | throw std::runtime_error( "Incorrect id of State. Expected a know state type!" ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/scenario/criteria/NumUnitTypeCreated.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/NumUnitTypeCreated.h" 6 | #include "Player.h" 7 | 8 | bool DeepRTS::Criteria::NumUnitTypeCreated::evaluate(const Player &player) { 9 | switch (unitType) { 10 | case Constants::Peasant: 11 | isValid = player.num_peasant >= count; 12 | break; 13 | case Constants::Peon: 14 | isValid = player.num_peasant >= count; // TODO 15 | break; 16 | case Constants::TownHall: 17 | isValid = player.num_town_hall >= count; 18 | break; 19 | case Constants::Barracks: 20 | isValid = player.num_barrack >= count; 21 | break; 22 | case Constants::Footman: 23 | isValid = player.num_footman >= count; 24 | break; 25 | case Constants::Farm: 26 | isValid = player.num_farm >= count; 27 | break; 28 | case Constants::Archer: 29 | isValid = player.num_archer >= count; 30 | break; 31 | case Constants::None: 32 | throw std::runtime_error("Unhandled unit type in NumUnitTypeCreated criteria"); 33 | } 34 | return isValid; 35 | } 36 | 37 | DeepRTS::Criteria::NumUnitTypeCreated::NumUnitTypeCreated(Constants::Unit unitType, int count, int rewardSuccess, int rewardFailure) 38 | : ScenarioCriteria(rewardSuccess, rewardFailure) 39 | , unitType(unitType) 40 | , count(count){} 41 | 42 | int DeepRTS::Criteria::NumUnitTypeCreated::reward() const { 43 | return (isValid) ? rewardSuccess : rewardFailure; 44 | } 45 | -------------------------------------------------------------------------------- /bindings/DeepRTS.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 28.01.18. 3 | // 4 | #include 5 | #include 6 | #ifndef EMBEDDED 7 | #include "utilities/ndarray_converter.h" 8 | #endif 9 | 10 | namespace py = pybind11; 11 | 12 | void init_Constants(py::module &); 13 | void init_BaseState(py::module &); 14 | void init_UnitManager(py::module &); 15 | void init_Unit(py::module &); 16 | void init_Tilemap(py::module &); 17 | void init_Tile(py::module &); 18 | void init_Player(py::module &); 19 | void init_Game(py::module &); 20 | void init_Map(py::module &); 21 | void init_Config(py::module &); 22 | void init_Random(py::module &); 23 | void init_Webserver(py::module &); 24 | void init_scenarios(py::module &); 25 | void init_version(py::module &m) { 26 | #ifdef VERSION_INFO 27 | m.attr("__version__") = VERSION_INFO; 28 | #else 29 | m.attr("__version__") = "dev"; 30 | #endif 31 | } 32 | 33 | 34 | #ifndef EMBEDDED 35 | 36 | 37 | 38 | PYBIND11_MODULE(libdeeprts, m) { 39 | NDArrayConverter::init_numpy(); 40 | m.doc() = "DeepRTS Game Engine Library"; 41 | init_Random(m); 42 | init_Constants(m); 43 | init_BaseState(m); 44 | init_Unit(m); 45 | init_Map(m); 46 | init_Tile(m); 47 | init_Tilemap(m); 48 | init_Game(m); 49 | init_Player(m); 50 | init_version(m); 51 | init_Config(m); 52 | init_UnitManager(m); 53 | init_scenarios(m); 54 | } 55 | #else 56 | PYBIND11_EMBEDDED_MODULE(libdeeprts, m){ 57 | m.doc() = "DeepRTS Game Engine Library"; 58 | init_Random(m); 59 | init_Constants(m); 60 | init_BaseState(m); 61 | init_Unit(m); 62 | init_Map(m); 63 | init_Tile(m); 64 | init_Tilemap(m); 65 | init_Game(m); 66 | init_Player(m); 67 | init_version(m); 68 | init_Config(m); 69 | init_UnitManager(m); 70 | init_scenarios(m); 71 | } 72 | #endif -------------------------------------------------------------------------------- /src/scenario/criteria/UnitIncrement.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/criterias/UnitIncrement.h" 6 | #include "Player.h" 7 | DeepRTS::Criteria::UnitIncrement::UnitIncrement(Constants::Unit unitType, int amount, int rewardSuccess, int rewardFailure) 8 | : ScenarioCriteria(rewardSuccess, rewardFailure) 9 | , unitType(unitType){ 10 | 11 | } 12 | 13 | bool DeepRTS::Criteria::UnitIncrement::evaluate(const Player &player) { 14 | bool state = false; 15 | switch (unitType) { 16 | case Constants::Peasant: 17 | state = player.num_peasant > lastValue; 18 | lastValue = player.num_peasant; 19 | break; 20 | case Constants::Peon: 21 | state = player.num_peasant > lastValue; 22 | lastValue = player.num_peasant; 23 | break; 24 | case Constants::TownHall: 25 | state = player.num_town_hall > lastValue; 26 | lastValue = player.num_town_hall; 27 | break; 28 | case Constants::Barracks: 29 | state = player.num_barrack > lastValue; 30 | lastValue = player.num_barrack; 31 | break; 32 | case Constants::Footman: 33 | state = player.num_footman > lastValue; 34 | lastValue = player.num_footman; 35 | break; 36 | case Constants::Farm: 37 | state = player.num_farm > lastValue; 38 | lastValue = player.num_farm; 39 | break; 40 | case Constants::Archer: 41 | state = player.num_archer > lastValue; 42 | lastValue = player.num_archer; 43 | break; 44 | case Constants::None: 45 | throw std::runtime_error("Incorrect unit type"); 46 | } 47 | 48 | isValid = state; 49 | return isValid; 50 | } 51 | 52 | int DeepRTS::Criteria::UnitIncrement::reward() const { 53 | return (isValid) ? rewardSuccess : rewardFailure; 54 | } 55 | -------------------------------------------------------------------------------- /examples/old/util.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | 4 | import gym 5 | import numpy as np 6 | 7 | 8 | def get_available_gpus(): 9 | from tensorflow_core.python.client import device_lib 10 | local_device_protos = device_lib.list_local_devices() 11 | return [x.name for x in local_device_protos if x.device_type == 'GPU'] 12 | 13 | def gpu_count(): 14 | return len(get_available_gpus()) 15 | 16 | class TensorBoardTool: 17 | 18 | def __init__(self, dir_path): 19 | 20 | self.dir_path = dir_path 21 | 22 | def run(self): 23 | from tensorboard import default 24 | from tensorboard import program 25 | # Remove http messages 26 | log = logging.getLogger('werkzeug').setLevel(logging.ERROR) 27 | # Start tensorboard server 28 | 29 | tb = program.TensorBoard(default.get_plugins()) # , default.get_assets_zip_provider() 30 | tb.configure(argv=[None, '--logdir', self.dir_path]) 31 | url = tb.launch() 32 | sys.stdout.write('TensorBoard at %s \n' % url) 33 | 34 | 35 | class LimitedDiscrete(gym.spaces.Space): 36 | 37 | def __init__(self, min_, max_): 38 | 39 | self.min = min_ 40 | self.max = max_ 41 | self.n = max_ 42 | super(LimitedDiscrete, self).__init__((), np.int64) 43 | self.__class__ = gym.spaces.Discrete 44 | 45 | def sample(self): 46 | return self.np_random.randint(self.min, self.max) 47 | 48 | def contains(self, x): 49 | if isinstance(x, int): 50 | as_int = x 51 | elif isinstance(x, (np.generic, np.ndarray)) and (x.dtype.kind in np.typecodes['AllInteger'] and x.shape == ()): 52 | as_int = int(x) 53 | else: 54 | return False 55 | return self.min <= as_int < self.max 56 | 57 | def __repr__(self): 58 | return "Discrete(%d-%d)" % (self.min, self.max) 59 | 60 | def __eq__(self, other): 61 | return isinstance(other, LimitedDiscrete) and self.min == other.min and self.max == other.max 62 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/15x15-2p-ffa-Cresal.json: -------------------------------------------------------------------------------- 1 | { "height":15, 2 | "infinite":false, 3 | "layers":[ 4 | { 5 | "data":[52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 17, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 17, 270, 270, 270, 102, 102, 270, 52, 52, 270, 142, 142, 270, 270, 270, 270, 270, 270, 270, 102, 102, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52], 6 | "height":15, 7 | "name":"Rutelag 1", 8 | "offsetx":3, 9 | "offsety":-2, 10 | "opacity":1, 11 | "type":"tilelayer", 12 | "visible":true, 13 | "width":15, 14 | "x":0, 15 | "y":0 16 | }], 17 | "nextobjectid":1, 18 | "orientation":"orthogonal", 19 | "renderorder":"right-down", 20 | "tiledversion":"1.1.2", 21 | "tileheight":32, 22 | "tilesets":[ 23 | { 24 | "columns":19, 25 | "firstgid":1, 26 | "image":"..\/textures\/tiles.png", 27 | "imageheight":659, 28 | "imagewidth":626, 29 | "margin":0, 30 | "name":"tiles", 31 | "spacing":1, 32 | "tilecount":380, 33 | "tileheight":32, 34 | "tilewidth":32 35 | }], 36 | "tilewidth":32, 37 | "type":"map", 38 | "version":1, 39 | "width":15 40 | } -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/15x15-1p-ffa-Utha-Lava.json: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":15, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 89, 89, 335, 335, 335, 335, 335, 335, 335, 335, 335, 120, 120, 52, 52, 89, 89, 335, 335, 335, 335, 335, 335, 335, 335, 335, 120, 120, 52, 52, 89, 89, 335, 335, 335, 335, 17, 335, 335, 335, 335, 120, 120, 52, 52, 89, 89, 335, 335, 335, 335, 335, 335, 335, 335, 335, 120, 120, 52, 52, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 52, 52, 373, 373, 373, 335, 335, 373, 373, 373, 335, 335, 373, 373, 373, 52, 52, 373, 373, 373, 335, 335, 373, 373, 373, 335, 335, 373, 373, 373, 52, 52, 373, 373, 373, 335, 335, 373, 373, 373, 335, 335, 373, 373, 373, 52, 52, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 52, 52, 120, 120, 335, 335, 335, 335, 335, 335, 335, 335, 335, 89, 89, 52, 52, 120, 120, 335, 335, 335, 335, 17, 335, 335, 335, 335, 89, 89, 52, 52, 120, 120, 335, 335, 335, 335, 335, 335, 335, 335, 335, 89, 89, 52, 52, 120, 120, 335, 335, 335, 335, 335, 335, 335, 335, 335, 89, 89, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52], 7 | "height":15, 8 | "id":1, 9 | "name":"Rutelag 1", 10 | "offsetx":3, 11 | "offsety":-2, 12 | "opacity":1, 13 | "type":"tilelayer", 14 | "visible":true, 15 | "width":15, 16 | "x":0, 17 | "y":0 18 | }], 19 | "nextlayerid":2, 20 | "nextobjectid":1, 21 | "orientation":"orthogonal", 22 | "renderorder":"right-down", 23 | "tiledversion":"1.7.2", 24 | "tileheight":32, 25 | "tilesets":[ 26 | { 27 | "columns":19, 28 | "firstgid":1, 29 | "image":"..\/textures\/tiles.png", 30 | "imageheight":659, 31 | "imagewidth":626, 32 | "margin":0, 33 | "name":"tiles", 34 | "spacing":1, 35 | "tilecount":380, 36 | "tileheight":32, 37 | "tilewidth":32 38 | }], 39 | "tilewidth":32, 40 | "type":"map", 41 | "version":"1.6", 42 | "width":15 43 | } -------------------------------------------------------------------------------- /bindings/trampolines/PyGame.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 23.02.2017. 3 | // 4 | 5 | #pragma once 6 | #include 7 | #include "../../include/DeepRTS/Game.h" 8 | #include "unit/Unit.h" 9 | using DeepRTS::Game; 10 | using DeepRTS::Unit; 11 | using DeepRTS::Game; 12 | using DeepRTS::Tile; 13 | 14 | class PyGame: public Game { 15 | using Game::Game; 16 | 17 | /*PyGame(std::string map_name): Game(map_name){ 18 | 19 | }*/ 20 | 21 | 22 | const cv::Mat& _render() const override { 23 | PYBIND11_OVERLOAD(const cv::Mat&, Game, _render, ); 24 | } 25 | 26 | void _caption()const override { 27 | PYBIND11_OVERLOAD(void, Game, _caption, ); 28 | } 29 | 30 | void _update() override { 31 | PYBIND11_OVERLOAD(void, Game, _update, ); 32 | } 33 | 34 | void _reset() override { 35 | PYBIND11_OVERLOAD(void, Game, _reset, ); 36 | } 37 | 38 | void _onUnitCreate(const Unit & unit)const override { 39 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_unit_create", _onUnitCreate, unit); 40 | } 41 | 42 | void _onUnitDestroy(const Unit & unit)const override { 43 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_unit_destroy", _onUnitDestroy, unit); 44 | } 45 | 46 | void _onTileChange(const Tile & tile)const override { 47 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_tile_change", _onTileChange, tile); 48 | } 49 | 50 | void _onEpisodeStart()const override { 51 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_episode_start", _onEpisodeStart, ); 52 | } 53 | 54 | void _onEpisodeEnd()const override { 55 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_episode_end", _onEpisodeEnd, ); 56 | } 57 | 58 | void _onResourceGather(const Tile& tile, const Unit& unit)const override { 59 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_resource_gather", _onResourceGather, tile, unit); 60 | } 61 | 62 | void _onResourceDepleted(const Tile& tile, const Unit& unit)const override { 63 | PYBIND11_OVERLOAD_NAME(void, Game, "_on_resource_depleted", _onResourceDepleted, tile, unit); 64 | } 65 | 66 | 67 | 68 | }; 69 | -------------------------------------------------------------------------------- /src/scenario/scenarios/GeneralAIOneVersusOne.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "scenario/scenarios/GeneralAIOneVersusOne.h" 9 | #include "Config.h" 10 | 11 | using DeepRTS::Config; 12 | 13 | DeepRTS::Scenarios::GeneralAIOneVersusOne::GeneralAIOneVersusOne() 14 | : Scenario( 15 | Constants::Map::VASTRANA, 16 | getConfig(), 17 | { 18 | std::make_shared(Constants::Resource::Lumber, 10000), 19 | std::make_shared(Constants::Resource::Gold, 10000), 20 | std::make_shared(Constants::Resource::Stone, 10000), 21 | std::make_shared(Constants::Resource::Food, 10000), 22 | std::make_shared(Constants::Unit::TownHall, 10000), 23 | std::make_shared(Constants::Unit::Barracks, 10000), 24 | std::make_shared(Constants::Unit::Farm, 10000), 25 | std::make_shared(Constants::Unit::Peasant, 10000), 26 | std::make_shared(Constants::Unit::Archer, 10000), 27 | std::make_shared(Constants::Unit::Footman, 10000), 28 | std::make_shared(10000) 29 | } 30 | ){ 31 | addPlayer(); 32 | addPlayer(); 33 | } 34 | 35 | Config DeepRTS::Scenarios::GeneralAIOneVersusOne::getConfig(){ 36 | Config config; 37 | config.setBarracks(true); 38 | config.setFootman(true); 39 | config.setInstantTownHall(true); 40 | config.setArcher(true); 41 | config.setStartLumber(1000); 42 | config.setStartGold(1000); 43 | config.setStartStone(1000); 44 | config.setTickModifier(config.tickModifier); 45 | config.setInstantBuilding(true); 46 | return config; 47 | } 48 | -------------------------------------------------------------------------------- /include/DeepRTS/Map.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 04.02.18. 3 | // 4 | 5 | #ifndef DEEPRTS_MAP_H 6 | #define DEEPRTS_MAP_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | namespace DeepRTS { 14 | 15 | struct TileData { 16 | int depleteTile; 17 | std::string name; 18 | bool walkable; 19 | bool harvestable; 20 | double walk_modifier; 21 | int resources; 22 | double lumber_yield; 23 | double gold_yield; 24 | double stone_yield; 25 | double damage_modifier; 26 | 27 | TileData() = default; 28 | 29 | TileData( 30 | int depleteTile, 31 | std::string name, 32 | bool walkable, 33 | double walk_modifier, 34 | bool harvestable, 35 | int resources, 36 | double lumber_yield, 37 | double gold_yield, 38 | double stone_yield, 39 | double damage_modifier) : depleteTile(depleteTile), name(std::move(name)), walkable(walkable), 40 | harvestable(harvestable), 41 | walk_modifier(walk_modifier), resources(resources), 42 | lumber_yield(lumber_yield), gold_yield(gold_yield), 43 | stone_yield(stone_yield), damage_modifier(damage_modifier) { 44 | 45 | } 46 | }; 47 | 48 | 49 | class Map { 50 | 51 | public: 52 | 53 | explicit Map(const std::string &map_file); 54 | 55 | std::string mapFile; 56 | 57 | /// A tile's Width 58 | int TILE_WIDTH; 59 | 60 | /// A tile's Height 61 | int TILE_HEIGHT; 62 | 63 | /// The Map Width (Num of tiles in width) 64 | int MAP_WIDTH; 65 | 66 | /// The Map Height (Num of tiles in height) 67 | int MAP_HEIGHT; 68 | 69 | std::vector tileIDs; 70 | 71 | std::map tilesData; 72 | 73 | }; 74 | 75 | } 76 | #endif //DEEPRTS_MAP_H 77 | -------------------------------------------------------------------------------- /include/DeepRTS/UnitManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | #pragma once 5 | 6 | #include "unit/Unit.h" 7 | #include "Constants.h" 8 | namespace DeepRTS { 9 | 10 | class Player; 11 | 12 | /// The unit manager is used to construct units in the game. 13 | /// The unit manager functions usually takes in a player object as reference, and returns a unit object which is added to the player 14 | /// API is due to change. 15 | class UnitManager { 16 | 17 | public: 18 | 19 | /// Construct a unit of type unitType for Player object player 20 | /// \param unitType The unit type 21 | /// \param player The player 22 | /// \return The newly constructed unit 23 | static Unit constructUnit(Constants::Unit unitType, Player &player); 24 | 25 | /// Update the unit count of a specified unit for player p 26 | /// \param p the player reference 27 | /// \param unitType the unit type 28 | /// \param n the count you wish to add. 29 | static void updateUnitCount(Player &p, Constants::Unit unitType, int n); 30 | 31 | /// Construct a town hall unit for player 32 | /// \param player player reference 33 | /// \return Town-Hall unit 34 | static Unit constructTownHall(Player &player); 35 | 36 | /// Construct a peasant unit for player 37 | /// \param player player reference 38 | /// \return Peasant unit 39 | static Unit constructPeasant(Player &player); 40 | 41 | /// Construct a farm unit for player 42 | /// \param player player reference 43 | /// \return Farm unit 44 | static Unit constructFarm(Player &player); 45 | 46 | /// Construct a barracks unit for player 47 | /// \param player player reference 48 | /// \return Barracks unit 49 | static Unit constructBarracks(Player &player); 50 | 51 | /// Construct a footman unit for player 52 | /// \param player player reference 53 | /// \return Footman Unit 54 | static Unit constructFootman(Player &player); 55 | 56 | /// Create a archer unit for player 57 | /// \param player player reference 58 | /// \return Archer unit 59 | static Unit constructArcher(Player &player); 60 | }; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/state/Combat.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 27.02.2017. 3 | // 4 | 5 | #include "state/Combat.h" 6 | #include "unit/Unit.h" 7 | #include "Player.h" 8 | #include "Game.h" 9 | #include // std::max 10 | using namespace DeepRTS; 11 | 12 | void Combat::update(Unit & unit){ 13 | 14 | unit.combatTimer = std::min(unit.combatInterval, unit.combatTimer + 1.0); 15 | if(unit.combatTimer >= unit.combatInterval) { 16 | Unit *combatTarget = unit.getCombatTarget(); 17 | 18 | 19 | // If combat target are despawn in some way (Building, Dead, Despawned) stop attacking... 20 | if (!combatTarget || !combatTarget->tile) { 21 | 22 | unit.combatTargetID = -1; 23 | unit.combatTimer = unit.combatInterval; 24 | unit.transitionState(); 25 | return; 26 | } 27 | 28 | int distance = unit.distance(*combatTarget); 29 | if(distance > unit.damageRange) { 30 | // Too far away, Walk 31 | 32 | // Only walk distance difference steps before transition back to attack 33 | int diff = distance - unit.damageRange; 34 | unit.stepsLeft = diff; 35 | 36 | unit.walkingGoalID = combatTarget->tile->id; 37 | unit.transitionState(unit.stateManager->walkingState); 38 | unit.enqueueState(unit.stateManager->combatState); 39 | 40 | } else { 41 | // Can attack 42 | int myDamage = unit.getDamage(*combatTarget); 43 | combatTarget->afflictDamage(myDamage); 44 | unit.player_.sDamageDone += myDamage; 45 | combatTarget->player_.sDamageTaken += myDamage; 46 | unit.combatTimer = 0; 47 | unit.animationCounter++; 48 | unit.game->_onUnitAttack(unit); 49 | 50 | 51 | if(combatTarget->isDead()){ 52 | unit.combatTargetID = Constants::None; 53 | unit.combatTimer = unit.combatInterval; 54 | unit.transitionState(); 55 | return; 56 | } 57 | 58 | if(combatTarget->state->id == Constants::State::Idle) { 59 | combatTarget->attack(*unit.tile); 60 | } 61 | 62 | } 63 | 64 | 65 | } 66 | 67 | } 68 | 69 | void Combat::end(Unit & unit){ 70 | (void)(unit); 71 | } 72 | 73 | void Combat::init(Unit & unit){ 74 | Position dir = unit.distanceVector(*unit.getCombatTarget()->tile); 75 | unit.setDirection(dir); 76 | 77 | 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /include/DeepRTS/Tilemap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | #pragma once 5 | 6 | 7 | #include "Constants.h" 8 | #include "Tile.h" 9 | #include "Map.h" 10 | #include 11 | namespace DeepRTS { 12 | 13 | class Game; 14 | 15 | /// The tilemap class specifies the map of the game 16 | /// This class is created from loading the map in the Map class 17 | class Tilemap { 18 | 19 | public: 20 | /// Reference to the game object 21 | Game &game; 22 | 23 | /// The constructor. 24 | /// \param map A reference to the map object 25 | /// \param game A reference to the game 26 | Tilemap(Map &map, Game &game); 27 | 28 | /// List of spawn tiles (Tiles that players can spawn on) 29 | std::vector spawnTiles; 30 | 31 | /// Get all tiles in the tilemap 32 | /// \return 33 | std::vector &getTiles(); 34 | 35 | /// Get the corresponding spawn tile for a specific player ID (each player is locked to a spawn position) 36 | /// \param playerID 37 | /// \return Tile reference 38 | Tile &getSpawnTile(int playerID); 39 | 40 | /// Get a list of tiles that are neighbour to the input tile 41 | /// \param tile The input tile reference 42 | /// \param type Which type of tiles you wish to retrieve 43 | /// \return List of neighbors tiles 44 | std::vector neighbors(Tile &tile, Constants::Pathfinding type); 45 | 46 | /// Get tiles in an area around a tile 47 | /// \param source The source tile reference 48 | /// \param width Width of the area 49 | /// \param height Height of the area 50 | /// \return List of Tile pointers of the surrounding area of the source tile 51 | std::vector getTileArea(Tile &source, uint32_t width, uint32_t height); 52 | 53 | /// Get a tile on position X and Y 54 | /// \param x integer X position 55 | /// \param y integer Y position 56 | /// \return Tile reference 57 | Tile &getTile(uint32_t x, uint32_t y); 58 | 59 | /// List of all tiles in the tilemap 60 | std::vector tiles; 61 | 62 | /// Reset the tilemap 63 | void reset(); 64 | 65 | /// The implicit convertion is used in the JPS pathfinding. The call avaluates if the path is viable in a trajectory. 66 | /// \param x 67 | /// \param y 68 | /// \return 69 | bool operator()(unsigned x, unsigned y) const; 70 | }; 71 | 72 | } -------------------------------------------------------------------------------- /bindings/Player.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace py = pybind11; 4 | 5 | #include "../include/DeepRTS/Player.h" 6 | #include "unit/Unit.h" 7 | #include "../include/DeepRTS/Game.h" 8 | #include "./trampolines/PyPlayer.h" 9 | using DeepRTS::Player; 10 | 11 | 12 | void init_Player(py::module &m) { 13 | py::class_(m, "Player") 14 | .def(py::init()) 15 | .def_readonly("statistic_gathered_gold", &Player::sGatheredGold) 16 | .def_readonly("statistic_gathered_lumber", &Player::sGatheredLumber) 17 | .def_readonly("statistic_gathered_stone", &Player::sGatheredStone) 18 | .def_readonly("statistic_damage_done", &Player::sDamageDone) 19 | .def_readonly("statistic_damage_taken", &Player::sDamageTaken) 20 | .def_readonly("statistic_units_created", &Player::sUnitsCreated) 21 | .def_readonly("num_archer", &Player::num_archer) 22 | .def_readonly("num_barrack", &Player::num_barrack) 23 | .def_readonly("num_farm", &Player::num_farm) 24 | .def_readonly("num_footman", &Player::num_footman) 25 | .def_readonly("num_peasant", &Player::num_peasant) 26 | .def_readonly("num_town_hall", &Player::num_town_hall) 27 | 28 | .def_readonly("stone", &Player::stone) 29 | .def_readonly("gold", &Player::gold) 30 | .def_readonly("lumber", &Player::lumber) 31 | .def_readonly("food_consumption", &Player::foodConsumption) 32 | .def_readonly("food", &Player::food) 33 | 34 | 35 | .def("get_name", &Player::getName) 36 | .def("set_name", &Player::setName) 37 | .def("set_state", &Player::setState) 38 | .def("evaluate_player_state", &Player::evaluatePlayerState) 39 | .def("get_score", &Player::getScore) 40 | 41 | .def("get_id", &Player::getId) 42 | .def("do_action", &Player::do_action) 43 | .def("do_manual_action", &Player::do_manual_action) 44 | 45 | .def("set_targeted_unit_id", &Player::setTargetedUnitID) 46 | 47 | .def("right_click", (void (Player::*)(int, int)) &Player::rightClick) 48 | .def("get_targeted_unit", &Player::getTargetedUnit, py::return_value_policy::reference) 49 | .def("left_click", &Player::leftClick) 50 | .def("spawn_unit", &Player::spawnUnitNearSpawnPoint) 51 | .def("add_unit", &Player::addUnit); 52 | 53 | //.def("right_click", &Player::rightClick); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /bindings/Config.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 24.02.18. 3 | // 4 | #include 5 | namespace py = pybind11; 6 | #include "../include/DeepRTS/Config.h" 7 | using DeepRTS::Config; 8 | 9 | void init_Config(py::module &m) { 10 | py::class_(m, "Config") 11 | .def(py::init<>()) 12 | 13 | .def("set_tick_modifier", &Config::setTickModifier) 14 | .def("set_instant_town_hall", &Config::setInstantTownHall) 15 | .def("set_instant_building", &Config::setInstantBuilding) 16 | .def("set_harvest_forever", &Config::setHarvestForever) 17 | .def("set_auto_attack", &Config::setAutoAttack) 18 | .def("set_food_limit", &Config::setFoodLimit) 19 | .def("set_farm", &Config::setFarm) 20 | .def("set_barracks", &Config::setBarracks) 21 | .def("set_footman", &Config::setFootman) 22 | .def("set_archer", &Config::setArcher) 23 | .def("set_console_caption_enabled", &Config::setConsoleCaptionEnabled) 24 | .def("set_start_gold", &Config::setStartGold) 25 | .def("set_start_lumber", &Config::setStartLumber) 26 | .def("set_start_stone", &Config::setStartStone) 27 | .def("set_start_food", &Config::setStartFood) 28 | .def("set_terminal_signal", &Config::setTerminalSignal) 29 | .def("set_pomdp", &Config::setPOMDP) 30 | .def("set_gui", &Config::setGUI) 31 | 32 | 33 | // Properties 34 | .def_readonly("tick_modifier", &Config::tickModifier) 35 | .def_readonly("town_hall", &Config::instantTownHall) 36 | .def_readonly("instant_building", &Config::instantBuilding) 37 | .def_readonly("harvest_forever", &Config::harvestForever) 38 | .def_readonly("auto_attack", &Config::autoAttack) 39 | .def_readonly("food_limit", &Config::foodLimit) 40 | .def_readonly("farm_enabled", &Config::farmEnabled) 41 | .def_readonly("barracks_enabled", &Config::barracksEnabled) 42 | .def_readonly("footman_enabled", &Config::footmanEnabled) 43 | .def_readonly("archer_enabled", &Config::archerEnabled) 44 | .def_readonly("pomdp", &Config::pompd) 45 | .def_readonly("start_gold", &Config::startGold) 46 | .def_readonly("start_stone", &Config::startStone) 47 | .def_readonly("start_lumber", &Config::startLumber) 48 | .def_readonly("start_food", &Config::startFood) 49 | .def_readonly("terminal_signal", &Config::terminalSignal) 50 | .def_readonly("console_caption_enabled", &Config::consoleCaptionEnabled) 51 | 52 | 53 | 54 | .def_static("defaults", &Config::defaults); 55 | } 56 | -------------------------------------------------------------------------------- /include/DeepRTS/ResourceLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per-arne on 02.04.17. 3 | // 4 | 5 | #ifndef DEEPRTS_RESOURCELOADER_H 6 | #define DEEPRTS_RESOURCELOADER_H 7 | 8 | #include 9 | namespace DeepRTS { 10 | 11 | /// The TilePropertyData class holds json data in memory. 12 | /// The data stems from the json maps. 13 | struct TilePropertyData { 14 | std::unordered_map tileID2Type; 15 | std::unordered_map tileData; 16 | 17 | nlohmann::json &getTileData(int tileID) { 18 | auto &tileType = tileID2Type[tileID]; 19 | auto &tData = tileData[tileType]; 20 | return tData; 21 | } 22 | }; 23 | 24 | /// The resourceLoader is primarily used to load maps. 25 | class ResourceLoader { 26 | public: 27 | /// json object of the map 28 | nlohmann::json mapJSON; 29 | 30 | /// json object of the tile metadata 31 | nlohmann::json tileJSON; 32 | 33 | 34 | private: 35 | /// Get the filepath of the filename 36 | /// \param fileName 37 | /// \return fullpath 38 | static std::string getFilePath(const std::string &fileName); 39 | 40 | /// Boolean if the map is loaded 41 | bool mapLoaded = false; 42 | 43 | /// Boolean if the tiles metadata is loaded 44 | bool tilesLoaded = true; 45 | 46 | /// Fucntion to load the tiles metadata json 47 | void loadTileJSON(); 48 | 49 | /// CONSTRUCTOR. Loads the TileJSON 50 | ResourceLoader() { 51 | loadTileJSON(); 52 | } 53 | 54 | public: 55 | /// The loadMapJSON function takes in a path to a file and loads the corresponding json 56 | /// \param map_file 57 | void loadMapJSON(const std::string &map_file); 58 | 59 | // C++ 11 60 | // ======= 61 | // We can use the better technique of deleting the methods 62 | // we don't want. 63 | public: 64 | ResourceLoader(ResourceLoader const &) = delete; 65 | 66 | void operator=(ResourceLoader const &) = delete; 67 | 68 | TilePropertyData tileData; 69 | 70 | // Note: Scott Meyers mentions in his Effective Modern 71 | // C++ book, that deleted functions should generally 72 | // be public as it results in better error messages 73 | // due to the compilers behavior to check accessibility 74 | // before deleted status 75 | static ResourceLoader &getInstance() { 76 | static ResourceLoader instance; // Guaranteed to be destroyed. 77 | // Instantiated on first use. 78 | return instance; 79 | } 80 | 81 | static TilePropertyData loadMAPJson(const nlohmann::json &tJSON); 82 | }; 83 | } 84 | 85 | #endif //DEEPRTS_RESOURCELOADER_H 86 | -------------------------------------------------------------------------------- /bindings/Game.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include "utilities/ndarray_converter.h" 6 | #include "./trampolines/PyGame.h" 7 | #include // Numpy bindings 8 | namespace py = pybind11; 9 | using DeepRTS::Game; 10 | using DeepRTS::Config; 11 | 12 | void init_Game(py::module &m) { 13 | py::class_(m, "Game") 14 | .def(py::init()) 15 | .def(py::init()) 16 | 17 | // Functions 18 | .def_readonly("config", &Game::config) 19 | .def("tick", &Game::tick) 20 | .def("update", &Game::update, py::return_value_policy::reference) 21 | .def("_update", &Game::update) 22 | .def("render", &Game::render) 23 | .def("_render", &Game::render) 24 | 25 | .def("caption", &Game::caption) 26 | .def("_caption", &Game::caption) 27 | .def("start", &Game::start) 28 | .def("stop", &Game::stop) 29 | .def("reset", &Game::reset) 30 | .def("is_terminal", &Game::isTerminal) 31 | .def("add_player", &Game::addPlayer, py::return_value_policy::reference) 32 | .def("insert_player", &Game::insertPlayer) 33 | // Callbacks 34 | .def("_on_unit_create", &Game::_onUnitCreate) 35 | .def("_on_unit_destroy", &Game::_onUnitDestroy) 36 | .def("_on_episode_start", &Game::_onEpisodeStart) 37 | .def("_on_episode_end", &Game::_onEpisodeEnd) 38 | .def("_on_tile_change", &Game::_onTileChange) 39 | .def("_on_resource_gather", &Game::_onResourceGather) 40 | .def("_on_resource_depleted", &Game::_onResourceDepleted) 41 | 42 | /// Getters 43 | .def("get_id", &Game::getId) 44 | .def("get_episode", &Game::getEpisode) 45 | .def("get_height", &Game::getHeight) 46 | .def("get_width", &Game::getWidth) 47 | .def("get_ticks", &Game::getTicks) 48 | .def("get_episode_duration", &Game::getGameDuration) 49 | .def("get_fps", &Game::getFPS) 50 | .def("get_max_fps", &Game::getMaxFPS) 51 | .def("get_ticks_modifier", &Game::getTicksModifier) 52 | 53 | .def("get_unit_by_name_id", &Game::getUnitByNameID, py::return_value_policy::reference) 54 | 55 | /// Setters 56 | .def("set_max_fps", &Game::setMaxFPS) 57 | .def("set_selected_player", &Game::setSelectedPlayer) 58 | 59 | 60 | .def_readonly("state", &Game::state) 61 | 62 | .def_readonly("units", &Game::units) 63 | .def_readonly("_players", &Game::players) 64 | .def_readonly("tilemap", &Game::tilemap) 65 | .def_readonly("map", &Game::map) 66 | .def_readonly("selected_player", &Game::selectedPlayer); 67 | 68 | 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/21x21-2p-ffa-Eflines.json: -------------------------------------------------------------------------------- 1 | { "height":21, 2 | "infinite":false, 3 | "layers":[ 4 | { 5 | "data":[52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 52, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 52, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 52, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 52, 334, 334, 334, 334, 334, 334, 270, 270, 270, 270, 270, 270, 270, 334, 334, 334, 334, 334, 334, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 334, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 334, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 17, 270, 270, 270, 270, 334, 270, 270, 270, 270, 17, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 334, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 334, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 334, 334, 334, 334, 334, 334, 270, 270, 270, 270, 270, 270, 270, 334, 334, 334, 334, 334, 334, 52, 52, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 52, 52, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 52, 52, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 52, 52, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52], 6 | "height":21, 7 | "name":"Rutelag 1", 8 | "offsetx":3, 9 | "offsety":-2, 10 | "opacity":1, 11 | "type":"tilelayer", 12 | "visible":true, 13 | "width":21, 14 | "x":0, 15 | "y":0 16 | }], 17 | "nextobjectid":1, 18 | "orientation":"orthogonal", 19 | "renderorder":"right-down", 20 | "tiledversion":"1.1.2", 21 | "tileheight":32, 22 | "tilesets":[ 23 | { 24 | "columns":19, 25 | "firstgid":1, 26 | "image":"..\/textures\/tiles.png", 27 | "imageheight":659, 28 | "imagewidth":626, 29 | "margin":0, 30 | "name":"tiles", 31 | "spacing":1, 32 | "tilecount":380, 33 | "tileheight":32, 34 | "tilewidth":32 35 | }], 36 | "tilewidth":32, 37 | "type":"map", 38 | "version":1, 39 | "width":21 40 | } -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/21x21-1p-scenario-Gondor.json: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "height":21, 3 | "infinite":false, 4 | "layers":[ 5 | { 6 | "data":[52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 52, 52, 373, 270, 373, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 373, 52, 52, 373, 270, 373, 270, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 270, 373, 52, 52, 373, 270, 373, 270, 270, 270, 270, 270, 270, 270, 373, 270, 270, 270, 270, 270, 270, 270, 373, 52, 52, 373, 270, 373, 270, 373, 373, 373, 373, 373, 270, 373, 373, 373, 373, 373, 270, 373, 270, 373, 52, 52, 373, 270, 373, 270, 373, 270, 270, 270, 270, 270, 270, 270, 270, 270, 373, 270, 373, 270, 373, 52, 52, 373, 270, 373, 270, 373, 270, 373, 373, 373, 373, 373, 373, 373, 270, 373, 270, 373, 270, 373, 52, 52, 373, 270, 270, 270, 373, 270, 373, 270, 270, 270, 270, 270, 373, 270, 373, 270, 373, 270, 373, 52, 52, 373, 373, 373, 373, 373, 270, 373, 270, 102, 102, 102, 270, 373, 270, 373, 270, 373, 270, 373, 52, 52, 270, 270, 270, 270, 373, 270, 373, 270, 102, 102, 102, 270, 373, 270, 373, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 373, 270, 373, 270, 102, 102, 102, 270, 373, 270, 373, 373, 373, 373, 270, 52, 52, 270, 270, 270, 270, 373, 270, 373, 270, 270, 270, 270, 270, 373, 270, 373, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 373, 270, 373, 373, 270, 270, 270, 373, 373, 270, 373, 270, 373, 373, 373, 52, 52, 270, 17, 270, 270, 373, 270, 270, 270, 270, 270, 270, 270, 270, 270, 373, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 270, 52, 52, 270, 270, 270, 270, 373, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 373, 270, 270, 270, 52, 52, 270, 270, 270, 270, 373, 270, 373, 373, 373, 373, 373, 373, 373, 373, 270, 373, 270, 373, 270, 52, 52, 270, 270, 270, 270, 270, 270, 373, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 373, 270, 52, 52, 270, 270, 270, 270, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52], 7 | "height":21, 8 | "id":1, 9 | "name":"Rutelag 1", 10 | "offsetx":3, 11 | "offsety":-2, 12 | "opacity":1, 13 | "type":"tilelayer", 14 | "visible":true, 15 | "width":21, 16 | "x":0, 17 | "y":0 18 | }], 19 | "nextlayerid":2, 20 | "nextobjectid":1, 21 | "orientation":"orthogonal", 22 | "renderorder":"right-down", 23 | "tiledversion":"1.7.2", 24 | "tileheight":32, 25 | "tilesets":[ 26 | { 27 | "columns":19, 28 | "firstgid":1, 29 | "image":"..\/textures\/tiles.png", 30 | "imageheight":659, 31 | "imagewidth":626, 32 | "margin":0, 33 | "name":"tiles", 34 | "spacing":1, 35 | "tilecount":380, 36 | "tileheight":32, 37 | "tilewidth":32 38 | }], 39 | "tilewidth":32, 40 | "type":"map", 41 | "version":"1.6", 42 | "width":21 43 | } -------------------------------------------------------------------------------- /DeepRTS/python/assets/maps/21x21-2p-ffa-FindGold-Vastrana.json: -------------------------------------------------------------------------------- 1 | { "compressionlevel":-1, 2 | "editorsettings": 3 | { 4 | "export": 5 | { 6 | "target":"." 7 | } 8 | }, 9 | "height":21, 10 | "infinite":false, 11 | "layers":[ 12 | { 13 | "data":[52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 270, 270, 270, 52, 270, 52, 270, 270, 270, 52, 270, 270, 270, 52, 270, 362, 52, 52, 270, 270, 24, 24, 24, 24, 270, 270, 52, 270, 270, 270, 52, 270, 52, 270, 270, 270, 52, 52, 52, 270, 24, 24, 24, 24, 24, 270, 270, 270, 52, 52, 270, 52, 270, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 17, 88, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 52, 52, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 52, 52, 270, 270, 52, 270, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 52, 52, 270, 270, 52, 270, 270, 270, 52, 270, 270, 270, 270, 17, 270, 270, 270, 52, 270, 270, 270, 52, 52, 270, 270, 52, 270, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 52, 270, 270, 270, 52, 52, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 52, 270, 270, 52, 52, 270, 270, 52, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 52, 270, 270, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52], 14 | "height":21, 15 | "id":1, 16 | "name":"Rutelag 1", 17 | "offsetx":3, 18 | "offsety":-2, 19 | "opacity":1, 20 | "type":"tilelayer", 21 | "visible":true, 22 | "width":21, 23 | "x":0, 24 | "y":0 25 | }], 26 | "nextlayerid":2, 27 | "nextobjectid":1, 28 | "orientation":"orthogonal", 29 | "renderorder":"right-down", 30 | "tiledversion":"1.4.3", 31 | "tileheight":32, 32 | "tilesets":[ 33 | { 34 | "columns":19, 35 | "firstgid":1, 36 | "image":"..\/textures\/tiles.png", 37 | "imageheight":659, 38 | "imagewidth":626, 39 | "margin":0, 40 | "name":"tiles", 41 | "spacing":1, 42 | "tilecount":380, 43 | "tileheight":32, 44 | "tilewidth":32 45 | }], 46 | "tilewidth":32, 47 | "type":"map", 48 | "version":1.4, 49 | "width":21 50 | } -------------------------------------------------------------------------------- /bindings/Unit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace py = pybind11; 4 | 5 | 6 | #include "unit/Unit.h" 7 | #include "../include/DeepRTS/Player.h" 8 | #include "../include/DeepRTS/Tile.h" 9 | using DeepRTS::Unit; 10 | using DeepRTS::Player; 11 | 12 | void init_Unit(py::module &m) { 13 | py::class_(m, "Unit") 14 | .def(py::init()) 15 | 16 | .def_readonly("id", &Unit::id) 17 | .def_readonly("name_id", &Unit::nameID) 18 | .def_readonly("type", &Unit::typeId) 19 | .def_readonly("health", &Unit::health) 20 | .def_readonly("health_max", &Unit::health_max) 21 | .def_readonly("name", &Unit::name) 22 | .def_readonly("width", &Unit::width) 23 | .def_readonly("height", &Unit::height) 24 | .def_readonly("lumber_cost", &Unit::lumberCost) 25 | .def_readonly("gold_cost", &Unit::goldCost) 26 | .def_readonly("stone_cost", &Unit::stoneCost) 27 | .def_readonly("lumber_carry", &Unit::lumberCarry) 28 | .def_readonly("gold_carry", &Unit::goldCarry) 29 | .def_readonly("stone_carry", &Unit::stoneCarry) 30 | 31 | .def_readonly("structure", &Unit::structure) 32 | .def_readonly("can_attack", &Unit::canAttack) 33 | .def_readonly("can_move", &Unit::canMove) 34 | .def_readonly("military", &Unit::military) 35 | .def_readonly("recallable", &Unit::recallable) 36 | 37 | 38 | .def_readonly("sight", &Unit::sight) 39 | .def_readonly("speed", &Unit::speed) 40 | .def_readonly("armor", &Unit::armor) 41 | .def_readonly("damage_min", &Unit::damageMin) 42 | .def_readonly("damage_max", &Unit::damageMax) 43 | .def_readonly("damage_range", &Unit::damageRange) 44 | .def_readonly("damage_piercing", &Unit::damagePiercing) 45 | .def_readonly("direction", &Unit::direction) 46 | 47 | .def_readonly("walking_timer", &Unit::walking_timer) 48 | .def_readonly("walking_interval", &Unit::walking_interval) 49 | .def_readwrite("walking_path", &Unit::walking_path) 50 | 51 | .def_readonly("harvest_timer", &Unit::harvestTimer) 52 | .def_readonly("harvest_interval", &Unit::harvestInterval) 53 | 54 | .def_readonly("combat_timer", &Unit::combatTimer) 55 | .def_readonly("combat_interval", &Unit::combatInterval) 56 | 57 | 58 | .def_readonly("spawn_duration", &Unit::spawnDuration) 59 | .def_readonly("spawn_timer", &Unit::spawnTimer) 60 | .def_readonly("build_timer", &Unit::buildTimer) 61 | .def_readonly("tile", &Unit::tile) 62 | .def_readonly("state", &Unit::state) 63 | .def("get_next_tile", &Unit::getNextTile) 64 | 65 | .def("get_player", &Unit::getPlayer, py::return_value_policy::reference) 66 | .def("right_click", &Unit::rightClick) 67 | .def("build", py::overload_cast(&Unit::build)) 68 | .def("build_no_cost", py::overload_cast(&Unit::build)) 69 | .def_readwrite("animation_counter", &Unit::animationCounter) 70 | 71 | .def("spawn", &Unit::spawn) 72 | ; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /examples/example_03/scenario182norewards.py: -------------------------------------------------------------------------------- 1 | from DeepRTS.python.scenario.engine import Scenario, ScenarioData 2 | from DeepRTS.python import util, Config, Game 3 | from DeepRTS import Engine 4 | import gym 5 | import numpy as np 6 | 7 | class Scenario182NoRewards(Scenario): 8 | 9 | def GAME_END(self, reward_success=1000000, reward_fail=-1000000, player=0): 10 | def wrap(self): 11 | p = self.game.selected_player 12 | if (p.is_defeated()): 13 | t = True 14 | r = reward_fail 15 | elif (self.game.is_terminal()): 16 | t = True 17 | r = reward_success 18 | else: 19 | t = False 20 | r = 0 21 | return t, r 22 | 23 | return wrap 24 | 25 | def __init__(self, config): 26 | 27 | engconf = config["engine"] if "engine" in config else {} 28 | gconf = config["gui"] if "gui" in config else {} 29 | rlconf = config["rl"] if "rl" in config else {} 30 | 31 | gui_config = Config( 32 | render=util.config(gconf, "render", True), 33 | view=util.config(gconf, "view", True), 34 | inputs=util.config(gconf, "inputs", False), 35 | caption=util.config(gconf, "caption", False), 36 | unit_health=util.config(gconf, "unit_health", False), 37 | unit_outline=util.config(gconf, "unit_outline", False), 38 | unit_animation=util.config(gconf, "unit_animation", False), 39 | audio=util.config(gconf, "audio", False), 40 | audio_volume=util.config(gconf, "audio_volume", 50) 41 | ) 42 | 43 | engine_config: Engine.Config = Engine.Config.defaults() 44 | engine_config.set_instant_building(True) 45 | engine_config.set_instant_town_hall(True) 46 | engine_config.set_barracks(True) 47 | engine_config.set_farm(True) 48 | engine_config.set_footman(True) 49 | engine_config.set_archer(True) 50 | engine_config.set_start_lumber(500) 51 | engine_config.set_start_gold(500) 52 | engine_config.set_start_stone(500) 53 | engine_config.set_tick_modifier(util.config(engconf, "tick_modifier", engine_config.tick_modifier)) 54 | engine_config.set_console_caption_enabled(False) 55 | 56 | game = Game( 57 | Config.Map.TWENTYONE, 58 | n_players=2, 59 | engine_config=engine_config, 60 | gui_config=gui_config, 61 | terminal_signal=True 62 | ) 63 | 64 | c_fps = engconf["fps"] if "fps" in engconf else -1 65 | c_ups = engconf["ups"] if "ups" in engconf else -1 66 | 67 | game.set_max_fps(c_fps) 68 | game.set_max_ups(c_ups) 69 | 70 | super().__init__( 71 | rlconf, 72 | game, 73 | 74 | # Scenarios 75 | self.GAME_END() 76 | # Scenario.DAMAGE_TAKEN(), 77 | # Scenario.NUM_FARM(), 78 | # Scenario.NUM_TOWN_HALL(), 79 | # Scenario.NUM_BARRACK(), 80 | # Scenario.GOLD_COLLECT_INCREMENT(100) 81 | # Scenario.LUMBER_COLLECT_INCREMENT(), 82 | # Scenario.OIL_COLLECT_INCREMENT(), 83 | # Scenario.UNITS_CREATED() 84 | ) 85 | 86 | self.DEFAULTS['flatten'] = False -------------------------------------------------------------------------------- /src/Map.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 04.02.18. 3 | // 4 | #include 5 | #include "Map.h" 6 | #include "ResourceLoader.h" 7 | 8 | 9 | using namespace DeepRTS; 10 | 11 | 12 | 13 | Map::Map(const std::string& map_file): mapFile(map_file) { 14 | ResourceLoader::getInstance().loadMapJSON(map_file); 15 | 16 | 17 | 18 | auto mapData = ResourceLoader::getInstance().mapJSON; 19 | auto _tileData = ResourceLoader::getInstance().tileData; 20 | 21 | auto tilesetData = mapData["tilesets"][0]; 22 | 23 | auto mapLayer = mapData["layers"][0]; 24 | 25 | auto _tileIDs = mapLayer["data"]; 26 | 27 | for(auto &id : _tileIDs) { 28 | int tileId = id.get(); 29 | tileIDs.emplace_back(tileId-1); 30 | } 31 | 32 | for(auto tileId : tileIDs) { 33 | auto tileData = _tileData.getTileData(tileId); 34 | if(tileData.is_null()){ 35 | std::runtime_error("Could not load tile"); 36 | } 37 | 38 | if(tileData["deplete_tile"].is_null()){std::cout << "Deplete Tile missing" << std::endl;} 39 | else if(tileData["name"].is_null()){std::cout << "Name missing" << std::endl;} 40 | else if(tileData["walkable"].is_null()){std::cout << "walkable missing" << std::endl;} 41 | else if(tileData["walk_modifier"].is_null()){std::cout << "walk_modifier missing" << std::endl;} 42 | else if(tileData["harvestable"].is_null()){std::cout << "harvestable missing" << std::endl;} 43 | else if(tileData["resources"].is_null()){std::cout << "resources" << std::endl;} 44 | else if(tileData["lumber_yield"].is_null()){std::cout << "lumber_yield" << std::endl;} 45 | else if(tileData["gold_yield"].is_null()){std::cout << "gold_yield" << std::endl;} 46 | else if(tileData["stone_yield"].is_null()){std::cout << "stone_yield" << std::endl;} 47 | 48 | auto deplete_tile = tileData["deplete_tile"].get(); 49 | auto name = tileData["name"].get(); 50 | auto walkable = tileData["walkable"].get(); 51 | auto walk_modifier = tileData["walk_modifier"].get(); 52 | auto harvestable = tileData["harvestable"].get(); 53 | auto resources = tileData["resources"].get(); 54 | auto lumber_yield = tileData["lumber_yield"].get(); 55 | auto gold_yield = tileData["gold_yield"].get(); 56 | auto stone_yield = tileData["stone_yield"].get(); 57 | auto damage_modifier = tileData["damage_modifier"].get(); 58 | 59 | tilesData.emplace(tileId,TileData( 60 | deplete_tile, 61 | name, 62 | walkable, 63 | walk_modifier, 64 | harvestable, 65 | resources, 66 | lumber_yield, 67 | gold_yield, 68 | stone_yield, 69 | damage_modifier 70 | )); 71 | 72 | } 73 | 74 | int mapWidth = mapData["width"].get(); 75 | int mapHeight = mapData["height"].get(); 76 | int tWidth = tilesetData["tilewidth"].get(); 77 | int tHeight = tilesetData["tileheight"].get(); 78 | //int tFirstGid = tilesetData["firstgid"].GetInt(); 79 | 80 | TILE_WIDTH = tWidth; 81 | TILE_HEIGHT = tHeight; 82 | MAP_WIDTH = mapWidth; 83 | MAP_HEIGHT = mapHeight; 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /DeepRTS/python/assets/tile_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "tile_types": { 3 | "Spawn": [16], 4 | "Wall": ["17-86", 87], 5 | "Gold": ["88-101"], 6 | "Lumber": ["102-141"], 7 | "Stone": ["142-179"], 8 | "Water": ["300-333"], 9 | "Desert": ["180-205", "334-355"], 10 | "Grass": ["238-269", "356-371"], 11 | "Lava": [372] 12 | }, 13 | "tile_metadata": { 14 | "Wall": { 15 | "name": "Wall", 16 | "harvestable": false, 17 | "walkable": false, 18 | "walk_modifier": 0, 19 | "stone_yield": 0, 20 | "lumber_yield": 0, 21 | "gold_yield": 0, 22 | "resources": 0, 23 | "deplete_tile": 51, 24 | "damage_modifier": 0 25 | }, 26 | "Lumber": { 27 | "name": "Lumber", 28 | "harvestable": true, 29 | "walkable": false, 30 | "walk_modifier": 0, 31 | "stone_yield": 0, 32 | "lumber_yield": 1, 33 | "gold_yield": 0, 34 | "resources": 1000, 35 | "deplete_tile": 269, 36 | "damage_modifier": 0 37 | }, 38 | "Water": { 39 | "name": "Water", 40 | "harvestable": false, 41 | "walkable": false, 42 | "walk_modifier": 0.0, 43 | "stone_yield": 0, 44 | "lumber_yield": 0, 45 | "gold_yield": 0, 46 | "resources": 0, 47 | "deplete_tile": 334, 48 | "damage_modifier": 0 49 | }, 50 | "Grass": { 51 | "name": "Grass", 52 | "harvestable": false, 53 | "walkable": true, 54 | "walk_modifier": 1.0, 55 | "stone_yield": 0, 56 | "lumber_yield": 0, 57 | "gold_yield": 0, 58 | "resources": 0, 59 | "deplete_tile": 269, 60 | "damage_modifier": 0 61 | }, 62 | "Desert": { 63 | "name": "Desert", 64 | "harvestable": false, 65 | "walkable": true, 66 | "walk_modifier": 0.5, 67 | "stone_yield": 0, 68 | "lumber_yield": 0, 69 | "gold_yield": 0, 70 | "resources": 0, 71 | "deplete_tile": 269, 72 | "damage_modifier": 0 73 | }, 74 | "Gold": { 75 | "name": "Gold", 76 | "harvestable": true, 77 | "walkable": false, 78 | "walk_modifier": 0, 79 | "stone_yield": 0, 80 | "lumber_yield": 0, 81 | "gold_yield": 1, 82 | "resources": 1000, 83 | "deplete_tile": 269, 84 | "damage_modifier": 0 85 | }, 86 | "Stone": { 87 | "name": "Stone", 88 | "harvestable": true, 89 | "walkable": false, 90 | "walk_modifier": 0, 91 | "stone_yield": 1, 92 | "lumber_yield": 0, 93 | "gold_yield": 0, 94 | "resources": 1000, 95 | "deplete_tile": 269, 96 | "damage_modifier": 0 97 | }, 98 | "Spawn": { 99 | "name": "Spawn", 100 | "harvestable": false, 101 | "walkable": false, 102 | "walk_modifier": 0, 103 | "stone_yield": 0, 104 | "lumber_yield": 0, 105 | "gold_yield": 0, 106 | "resources": 0, 107 | "deplete_tile": 269, 108 | "damage_modifier": 0 109 | }, 110 | "Lava": { 111 | "name": "Lava", 112 | "harvestable": false, 113 | "walkable": true, 114 | "walk_modifier": 0.5, 115 | "stone_yield": 0, 116 | "lumber_yield": 0, 117 | "gold_yield": 0, 118 | "resources": 0, 119 | "deplete_tile": 372, 120 | "damage_modifier": 1 121 | } 122 | } 123 | 124 | 125 | } -------------------------------------------------------------------------------- /examples/example_03/scenario182.py: -------------------------------------------------------------------------------- 1 | from DeepRTS.python.scenario.engine import Scenario, ScenarioData 2 | from DeepRTS.python import util, Config, Game 3 | from DeepRTS import Engine 4 | import gym 5 | import numpy as np 6 | 7 | 8 | 9 | class Scenario182Data(ScenarioData): 10 | 11 | def __init__(self): 12 | self.previous_statistic_damage_done = 0 13 | self.previous_statistic_resources = 0 14 | self.previous_statistic_buildings = 0 15 | self.previous_statistic_units = 0 16 | self.previous_statistic_food = 0 17 | super().__init__() 18 | 19 | def reset(self): 20 | self.__init__() 21 | 22 | class Scenario182(Scenario): 23 | 24 | 25 | def __init__(self, config): 26 | 27 | engconf = config["engine"] if "engine" in config else {} 28 | gconf = config["gui"] if "gui" in config else {} 29 | rlconf = config["rl"] if "rl" in config else {} 30 | 31 | gui_config = Config( 32 | render=util.config(gconf, "render", True), 33 | view=util.config(gconf, "view", True), 34 | inputs=util.config(gconf, "inputs", False), 35 | caption=util.config(gconf, "caption", False), 36 | unit_health=util.config(gconf, "unit_health", False), 37 | unit_outline=util.config(gconf, "unit_outline", False), 38 | unit_animation=util.config(gconf, "unit_animation", False), 39 | audio=util.config(gconf, "audio", False), 40 | audio_volume=util.config(gconf, "audio_volume", 50) 41 | ) 42 | 43 | engine_config: Engine.Config = Engine.Config.defaults() 44 | engine_config.set_instant_building(True) 45 | engine_config.set_instant_town_hall(True) 46 | engine_config.set_barracks(True) 47 | engine_config.set_farm(True) 48 | engine_config.set_footman(True) 49 | engine_config.set_archer(True) 50 | engine_config.set_start_lumber(500) 51 | engine_config.set_start_gold(500) 52 | engine_config.set_start_stone(500) 53 | engine_config.set_tick_modifier(util.config(engconf, "tick_modifier", engine_config.tick_modifier)) 54 | engine_config.set_console_caption_enabled(False) 55 | 56 | game = Game( 57 | Config.Map.TWENTYONE, 58 | n_players=2, 59 | engine_config=engine_config, 60 | gui_config=gui_config, 61 | terminal_signal=True 62 | ) 63 | 64 | c_fps = engconf["fps"] if "fps" in engconf else -1 65 | c_ups = engconf["ups"] if "ups" in engconf else -1 66 | 67 | game.set_max_fps(c_fps) 68 | game.set_max_ups(c_ups) 69 | 70 | super().__init__( 71 | rlconf, 72 | game, 73 | 74 | # Scenarios 75 | self.GAME_END(), 76 | self.FOOD(), 77 | self.RESOURCE_GATHERED(), 78 | self.BUILDINGS_BUILT(), 79 | self.UNITS_CREATED(), 80 | self.DAMAGE_DONE() 81 | # Scenario.DAMAGE_TAKEN(), 82 | # Scenario.NUM_FARM(), 83 | # Scenario.NUM_TOWN_HALL(), 84 | # Scenario.NUM_BARRACK(), 85 | # Scenario.GOLD_COLLECT_INCREMENT(100) 86 | # Scenario.LUMBER_COLLECT_INCREMENT(), 87 | # Scenario.OIL_COLLECT_INCREMENT(), 88 | # Scenario.UNITS_CREATED() 89 | ) 90 | 91 | self.data = Scenario182Data() 92 | self.DEFAULTS['flatten'] = False -------------------------------------------------------------------------------- /src/gui/Blend2DGUI.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/5/21. 3 | // 4 | #include "gui/Blend2DGUI.h" 5 | #include "Game.h" 6 | #include 7 | #include "Constants.h" 8 | using namespace DeepRTS; 9 | 10 | const cv::Mat& Blend2DGUI::render() const { 11 | return renderData; 12 | } 13 | 14 | void Blend2DGUI::onTileChange(const Tile &tile) { 15 | 16 | auto& tileTexture = tileset.at(tile.getTypeId()); 17 | int x_tile = (tile.x * tileSize); 18 | int y_tile = (tile.y * tileSize); 19 | 20 | if(tile.hasOccupant()){ 21 | auto& unit = game.units.at(tile.getOccupantID()); 22 | 23 | /// Draw unit 24 | if(unit.tile->id == tile.id){ 25 | /// We only want to draw on the first tile. For example, town halls 26 | 27 | /// Draw background 28 | Blend2DWrapper::blit(x_tile, y_tile, ctx, tileTexture); 29 | 30 | 31 | auto& unitTexture = units.at(unit.player_.getId()).at(unit.typeId).get( 32 | unit.animationCounter, 33 | static_cast(unit.direction), 34 | unit.state->id 35 | ); 36 | 37 | int x_unit = (tile.x * tileSize); 38 | int y_unit = (tile.y * tileSize); 39 | Blend2DWrapper::blit(x_unit, y_unit, ctx, unitTexture); 40 | 41 | } 42 | 43 | }else{ 44 | /// Redraw tile 45 | Blend2DWrapper::blit(x_tile, y_tile, ctx, tileTexture); 46 | } 47 | 48 | } 49 | 50 | void Blend2DGUI::renderMap(){ 51 | 52 | for(int i = 0; i < game.tilemap.tiles.size(); i++) { 53 | auto x = i % game.getWidth(); 54 | auto y = i / game.getWidth(); // where "/" is an integer division 55 | int x_start = (x * tileSize); 56 | int y_start = (y * tileSize); 57 | auto tileID = game.tilemap.tiles[i].getTypeId(); 58 | auto& tile = tileset.at(tileID); 59 | Blend2DWrapper::blit(x_start, y_start, ctx, tile); 60 | } 61 | } 62 | 63 | Blend2DGUI::Blend2DGUI(Game &game) : BaseGUI(game) 64 | 65 | , canvas( 66 | int(tileSize * game.getWidth()), 67 | int(tileSize * game.getHeight()), 68 | BL_FORMAT_PRGB32) 69 | , ctx(canvas) 70 | , tileset(tileSize, tileSize, "assets/textures/tiles.png") 71 | { 72 | blImageGetData(&canvas, &imageData); // get ptr to image data 73 | renderData = cv::Mat(canvas.height(), canvas.width(), CV_8UC4, imageData.pixelData); // create cv proxy 74 | 75 | 76 | std::vector> masks = { 77 | {0, 0, 255}, 78 | {255, 0, 0}, 79 | {0, 255, 0}, 80 | {255, 255, 0}, 81 | {0, 255, 255}, 82 | {255, 0, 255}, 83 | {255, 255, 255}, 84 | {128, 255, 128}, 85 | }; 86 | 87 | for(int i = 0; i < game.players.capacity(); i++){ 88 | 89 | auto& mask = masks.at(i); 90 | units.push_back({ 91 | {Constants::Unit::Peasant, Blend2DPeasant(mask, tileSize, 1, 1)}, 92 | // {Constants::Unit::Peon, Blend2DPeon()}, 93 | {Constants::Unit::TownHall, Blend2DTownHall(mask, tileSize, 3, 3)}, 94 | {Constants::Unit::Barracks, Blend2DBarracks(mask, tileSize, 3, 3)}, 95 | {Constants::Unit::Footman, Blend2DFootman(mask, tileSize, 1, 1)}, 96 | {Constants::Unit::Farm, Blend2DFarm(mask, tileSize, 1, 1)}, 97 | {Constants::Unit::Archer, Blend2DArcher(mask, tileSize, 1, 1)}, 98 | // add more here 99 | }); 100 | 101 | } 102 | 103 | 104 | 105 | renderMap(); 106 | } -------------------------------------------------------------------------------- /src/state/Walking.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 24.02.2017. 3 | // 4 | 5 | #include "state/Walking.h" 6 | #include "Player.h" 7 | #include "Game.h" 8 | #include "util/Pathfinder.h" 9 | #include "util/JPS.h" 10 | using namespace DeepRTS; 11 | 12 | Walking::Walking(Game &game) 13 | : BaseState(Constants::State::Walking) 14 | , search(game.tilemap){ 15 | name = "Walking"; 16 | } 17 | 18 | 19 | void Walking::update(Unit& unit){ 20 | Tile *walkingGoal = unit.getTile(unit.walkingGoalID); 21 | 22 | if(!walkingGoal){ 23 | assert(false); //No goal were set! 24 | } 25 | 26 | // No tiles in the walking path 27 | if (unit.walking_path.empty()) { 28 | unit.transitionState(); 29 | return; 30 | } 31 | 32 | 33 | if (unit.walking_timer < unit.walking_interval * unit.tile->getWalkModifier()) { 34 | unit.walking_timer += 1; 35 | return; 36 | } 37 | 38 | // Pop next 39 | Tile * nextTile = unit.walking_path.back(); 40 | unit.walking_path.pop_back(); 41 | 42 | // Check if someone is standing on goal 43 | if (!nextTile->isWalkable()) { 44 | unit.transitionState(); 45 | return; 46 | } 47 | 48 | 49 | unit.setPosition(*nextTile); 50 | unit.animationCounter++; 51 | unit.walking_timer = 0; 52 | 53 | if(unit.stepsLeft == 1) { 54 | unit.transitionState(); 55 | } 56 | if(unit.stepsLeft >= 1) { 57 | unit.stepsLeft --; 58 | } 59 | 60 | 61 | } 62 | 63 | void Walking::end(Unit & unit){ 64 | unit.walking_path.clear(); 65 | } 66 | 67 | void Walking::init(Unit & unit){ 68 | 69 | 70 | // Retrieve Tile* from walkingGoalID 71 | Tile *walkingGoal = unit.getTile(unit.walkingGoalID); 72 | 73 | // Predefine goal pointer 74 | Tile *goal; 75 | 76 | // Check if walking goal has a occupant 77 | if (!walkingGoal->isWalkable()) { 78 | goal = Pathfinder::find_first_walkable_tile(walkingGoal); 79 | 80 | } else { 81 | // Goal is walkable and there is no occupants there 82 | goal = walkingGoal; 83 | } 84 | 85 | // No goal has been set 86 | if (!goal) { 87 | return; 88 | } 89 | 90 | // Clear existing walking path 91 | unit.walking_path.clear(); 92 | 93 | // Set walkingGoalID to the set Goal 94 | unit.walkingGoalID = goal->id; 95 | 96 | // If the distance is only 1 n length, there is no need to calculate path 97 | if(unit.tile->distance(*goal) == 1) { 98 | unit.walking_path.push_back(goal); 99 | }else{ 100 | 101 | // The resulting path will go here. 102 | JPS::PathVector path; 103 | 104 | // Attempt to find a viable path 105 | /*search.findPath( 106 | path, 107 | JPS::Pos(unit.tile->x, unit.tile->y), 108 | JPS::Pos(goal->x, goal->y), 109 | 1);*/ 110 | 111 | JPS::findPath(path, unit.getPlayer().getGame().tilemap, unit.tile->x, unit.tile->y, goal->x, goal->y, 1, (JPS_Flag_NoStartCheck | JPS_Flag_NoEndCheck)); 112 | 113 | 114 | // Insert found path to the walking path vector 115 | std::reverse(path.begin(), path.end()); 116 | for(auto pathItem : path) { 117 | Tile& tile = unit.getPlayer().getGame().tilemap.getTile(pathItem.x, pathItem.y); 118 | unit.walking_path.push_back(&tile); 119 | } 120 | } 121 | 122 | // Set the initial direction of which the unit will move. 123 | if((int)unit.walking_path.size() > 0){ 124 | Tile * nextTile = unit.walking_path.back(); 125 | unit.setDirection(nextTile->x, nextTile->y); 126 | } 127 | 128 | } 129 | 130 | -------------------------------------------------------------------------------- /examples/old/test.py: -------------------------------------------------------------------------------- 1 | import Scenarios 2 | import Agents 3 | 4 | import torch 5 | import imageio 6 | 7 | import pygame 8 | 9 | import os 10 | from datetime import datetime 11 | 12 | import numpy 13 | 14 | action_names = { 15 | 16 | 1: "Previous Unit", 17 | 2: "Next Unit", 18 | 19 | 3: "Move Left", 20 | 4: "Move Right", 21 | 5: "Move Up", 22 | 6: "Move Down", 23 | 7: "Move Up Left", 24 | 8: "Move Up Right", 25 | 9: "Move Down Left", 26 | 10: "Move Down Right", 27 | 28 | 11: "Attack", 29 | 12: "Harvest", 30 | 31 | 13: "Build 0", 32 | 14: "Build 1", 33 | 15: "Build 2", 34 | 35 | 16: "No Action" 36 | } 37 | 38 | if __name__ == "__main__": 39 | 40 | now = datetime.now() 41 | now_string = now.strftime("%d-%m-%Y %H-%M-%S") 42 | directory = "Videos " + now_string 43 | 44 | test_directory = "Tests" 45 | test_path = os.path.join(os.getcwd(), test_directory) 46 | 47 | files = ["NN_700"] 48 | 49 | results_path = os.path.join(os.getcwd(), "Results") 50 | recording_path = os.path.join(results_path, directory) 51 | log_path = os.path.join(recording_path, "log.txt") 52 | 53 | os.mkdir(recording_path) 54 | log = open(log_path, "w+") 55 | 56 | # environment 57 | 58 | env = Scenarios.ImageToPyTorch(Scenarios.Scenario182({})) 59 | 60 | env.game.set_max_fps(99999999) 61 | env.game.set_max_ups(99999999) 62 | 63 | TRIALS = 100 64 | 65 | for file in files: 66 | 67 | file_path = os.path.join(test_path, file + ".pt") 68 | 69 | results_directory = file + "-Random" 70 | results_path = os.path.join(test_path, results_directory) 71 | os.mkdir(results_path) 72 | 73 | outcomes_path = os.path.join(results_path, "outcomes.txt") 74 | durations_path = os.path.join(results_path, "durations.txt") 75 | 76 | outcomes_file = open(outcomes_path, "w+") 77 | durations_file = open(durations_path, "w+") 78 | 79 | # agents 80 | 81 | state_size = env.observation_space.shape 82 | action_size = env.action_space.n 83 | 84 | agent_a = Agents.SmallAgent(4410, action_size) 85 | agent_a.load(file_path) 86 | 87 | agent_b = Agents.RandomAgent() 88 | 89 | for trial in range(TRIALS): 90 | 91 | state = env.reset() 92 | flat_state = state.flatten() 93 | 94 | # video stuff 95 | 96 | filenames = [] 97 | 98 | terminal = False 99 | changed = False 100 | count = 0 101 | 102 | # play game 103 | while not terminal: 104 | 105 | if trial == 0: 106 | if changed: 107 | # save the current window 108 | window = pygame.display.get_surface() 109 | 110 | image_name = "image_" + str(count) + ".jpeg" 111 | image_path = os.path.join(results_path, image_name) 112 | pygame.image.save(window, image_path) 113 | 114 | filenames.append(image_path) 115 | 116 | count += 1 117 | 118 | # AI for player 1 119 | env.game.set_player(env.game.players[0]) 120 | 121 | action = agent_a.get_action(flat_state, 0) 122 | next_state, _, terminal, _ = env.step(action) 123 | flat_next_state = next_state.flatten() 124 | 125 | # AI for player 1 126 | env.game.set_player(env.game.players[1]) 127 | 128 | action = agent_b.get_action(state, 0) 129 | next_state, _, terminal, _ = env.step(action) 130 | 131 | changed = not numpy.array_equal(state, next_state) 132 | 133 | state = next_state 134 | flat_state = flat_next_state 135 | 136 | if (env.game.players[0].is_defeated()): 137 | outcomes_file.write("0,") 138 | outcomes_file.flush() 139 | else: 140 | outcomes_file.write("1,") 141 | outcomes_file.flush() 142 | 143 | durations_file.write(str(env.game.get_episode_duration()) + ",") 144 | durations_file.flush() 145 | 146 | if trial == 0: 147 | images = [] 148 | for filename in filenames: 149 | images.append(imageio.imread(filename)) 150 | video_path = os.path.join(results_path, "video.gif") 151 | imageio.mimsave(video_path, images) -------------------------------------------------------------------------------- /src/scenario/Scenario.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per on 9/6/21. 3 | // 4 | 5 | #include "scenario/Scenario.h" 6 | 7 | #include 8 | #include "Player.h" 9 | #include "unit/Unit.h" 10 | #include "Game.h" 11 | 12 | DeepRTS::Scenarios::Scenario::Scenario( 13 | const std::string& map, 14 | Config config, 15 | Criteria::ScenarioCriteria::ScenarioContainer &&criteriaList) 16 | : Game(map, std::move(config)) 17 | , criteriaListTemplate(criteriaList) 18 | { 19 | createCriterionsForPlayers(); 20 | } 21 | 22 | void DeepRTS::Scenarios::Scenario::createCriterionsForPlayers(){ 23 | for(int i =0; i < 8; i++){ 24 | Criteria::ScenarioCriteria::ScenarioContainer copied; 25 | std::transform(criteriaListTemplate.begin(), criteriaListTemplate.end(), std::back_inserter(copied), []( 26 | std::shared_ptr& item){ 27 | return item->clone(); 28 | }); 29 | criteriaList[i] = copied; 30 | } 31 | } 32 | 33 | bool DeepRTS::Scenarios::Scenario::evaluate(const Player &player){ 34 | auto& criterias = criteriaList.at(player.getId()); 35 | 36 | return std::all_of(criterias.begin(), criterias.end(), [&player](auto& criteria){ 37 | return criteria->evaluate(player); 38 | }); 39 | } 40 | 41 | 42 | int DeepRTS::Scenarios::Scenario::reward(const Player &player) { 43 | auto& criterias = criteriaList.at(player.getId()); 44 | return std::all_of(criterias.begin(), criterias.end(), [](auto& criteria){ 45 | return criteria->reward(); 46 | }); 47 | } 48 | 49 | 50 | [[maybe_unused]] DeepRTS::Scenarios::Scenario::ActionSequenceContainer DeepRTS::Scenarios::Scenario::optimalStrategy() { 51 | return { 52 | }; 53 | } 54 | 55 | std::tuple DeepRTS::Scenarios::Scenario::computeOptimalStrategy(Player& player) { 56 | auto optimalActionSet = optimalStrategy(); 57 | 58 | // Set selected player 59 | setSelectedPlayer(player); 60 | 61 | int totalSteps = 0; 62 | int totalReward = 0; 63 | 64 | bool initialBuildHandled = false; 65 | for(auto& [action, unitName]: optimalActionSet){ 66 | auto* unit = getUnitByNameID(unitName); 67 | 68 | if(unit == nullptr){ 69 | throw std::runtime_error("Error in optimal_play_sequence. The unit with ID=" + unitName + "was not found."); 70 | } 71 | 72 | if(!initialBuildHandled){ 73 | while(unit->state->id == Constants::State::Building){ 74 | optimalPlayGameStep(player); 75 | } 76 | initialBuildHandled = true; 77 | } 78 | 79 | player.setTargetedUnitID(unit->id); 80 | 81 | while(unit->state->id != Constants::State::Idle){ 82 | auto [s, r, t] = optimalPlayGameStep(player); 83 | totalSteps += s; 84 | totalReward += r; 85 | terminal = t; 86 | } 87 | 88 | player.do_action(action); 89 | 90 | } 91 | 92 | terminal = false; 93 | while(!terminal){ 94 | auto [s, r, t] = optimalPlayGameStep(player); 95 | totalSteps += s; 96 | totalReward += r; 97 | terminal = t; 98 | } 99 | 100 | 101 | reset(); 102 | 103 | return {totalSteps, totalReward, terminal}; 104 | 105 | } 106 | 107 | std::tuple DeepRTS::Scenarios::Scenario::optimalPlayGameStep(Player &player) { 108 | update(); 109 | bool success = evaluate(player); 110 | int accumulatedReward = reward(player); 111 | int steps = 1; 112 | return {steps, accumulatedReward, success}; 113 | } 114 | 115 | void DeepRTS::Scenarios::Scenario::update() { 116 | Game::update(); 117 | for(auto& player: players){ 118 | auto terminal = evaluate(player) || player.evaluatePlayerState() == Constants::Defeat; 119 | 120 | if(terminal){ 121 | this->terminal = terminal; 122 | } 123 | 124 | } 125 | } 126 | 127 | void DeepRTS::Scenarios::Scenario::reset(){ 128 | Game::reset(); 129 | createCriterionsForPlayers(); // Create new criterions (dont care to reset em manually) 130 | } -------------------------------------------------------------------------------- /vcpkg_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | vcpkg_target_dir=$1 4 | 5 | # For Fedora 6 | FEDORA_PACKAGES="gcc gcc-c++ make curl tar unzip zip git ninja-build opencv opencv-devel perl dbus-devel libXi-devel libXtst-devel" 7 | 8 | # For Debian-based systems like Ubuntu 9 | DEBIAN_PACKAGES="build-essential tar curl zip unzip git ninja-build libopencv-dev perl libdbus-1-dev libxi-dev libxtst-dev" 10 | 11 | # For CentOS 12 | CENTOS_PACKAGES="gcc gcc-c++ make curl tar unzip zip git ninja-build opencv opencv-devel perl dbus-devel libXi-devel libXtst-devel" 13 | 14 | # For Arch Linux 15 | ARCH_PACKAGES="base-devel curl tar unzip zip git ninja opencv perl dbus libxi libxtst" 16 | 17 | # For MacOS (uses Homebrew) 18 | MACOS_PACKAGES="cmake curl unzip tar git ninja opencv perl dbus libxi libxtst" 19 | 20 | # For Alpine Linux (uses apk) 21 | APK_PACKAGES="gcc g++ make curl tar unzip zip git ninja perl dbus-dev libxi-dev libxtst-dev" 22 | 23 | 24 | # Function to install packages on Debian 25 | function install_packages_debian() { 26 | apt-get update 27 | apt-get install -y ${DEBIAN_PACKAGES} 28 | } 29 | 30 | # Function to install packages on Fedora 31 | function install_packages_fedora() { 32 | dnf install -y ${FEDORA_PACKAGES} 33 | } 34 | 35 | # Function to install packages on CentOS 36 | function install_packages_centos() { 37 | yum install -y ${CENTOS_PACKAGES} 38 | } 39 | 40 | # Function to install packages on Arch Linux 41 | function install_packages_arch() { 42 | pacman -Syu --needed ${ARCH_PACKAGES} 43 | } 44 | 45 | function install_packages_musl() { 46 | apk add --no-cache ${APK_PACKAGES} 47 | } 48 | 49 | # Function to install packages on MacOS 50 | function install_packages_macos() { 51 | # Verify if 'brew' is installed 52 | if ! command -v brew &> /dev/null 53 | then 54 | echo "Brew is not installed. Install it first and run the script again." 55 | exit 1 56 | fi 57 | 58 | # If 'brew' is installed, use it to install the packages 59 | for PACKAGE in ${MACOS_PACKAGES} 60 | do 61 | brew install ${PACKAGE} 62 | done 63 | } 64 | 65 | echo $OSTYPE 66 | 67 | # Identify the Linux distribution 68 | if [[ "$OSTYPE" == "linux-gnu"* ]] || [[ "$OSTYPE" == "linux-musl"* ]] || [[ "$OSTYPE" == "linux"* ]]; then 69 | 70 | 71 | if type apt-get > /dev/null 2>&1; then 72 | install_packages_debian 73 | elif type dnf > /dev/null 2>&1; then 74 | install_packages_fedora 75 | elif type yum > /dev/null 2>&1; then 76 | install_packages_centos 77 | elif type pacman > /dev/null 2>&1; then 78 | install_packages_arch 79 | elif type apk > /dev/null 2>&1; then 80 | install_packages_musl 81 | else 82 | echo "Unknown package manager. Please install the dependencies manually." 83 | fi 84 | 85 | elif [[ "$OSTYPE" == "darwin"* ]]; then 86 | install_packages_macos 87 | elif [[ "$OSTYPE" == "cygwin" ]]; then 88 | echo "Cygwin detected. Please install the required dependencies manually." 89 | elif [[ "$OSTYPE" == "msys" ]]; then 90 | echo "Git Bash detected. Please install the required dependencies manually." 91 | else 92 | echo "Unknown operating system. Please install the required dependencies manually." 93 | fi 94 | 95 | 96 | 97 | # Clone or update Vcpkg 98 | if [ ! -d "$vcpkg_target_dir/vcpkg" ]; then 99 | 100 | cd $vcpkg_target_dir && git clone https://github.com/Microsoft/vcpkg.git 101 | else 102 | cd $vcpkg_target_dir/vcpkg && git pull && cd .. 103 | fi 104 | 105 | 106 | # Build and install Vcpkg 107 | $vcpkg_target_dir/vcpkg/bootstrap-vcpkg.sh 108 | $vcpkg_target_dir/vcpkg/vcpkg integrate install 109 | 110 | 111 | 112 | # Get absolute path to current directory of this script realpath 113 | CURRENT_FILE=$(realpath "${BASH_SOURCE:-$0}") 114 | CURRENT_DIR=$(dirname "${CURRENT_FILE}") 115 | 116 | # Install libraries from txt file 117 | while read library; do 118 | $vcpkg_target_dir/vcpkg/vcpkg install $library 119 | done < $CURRENT_DIR/vcpkg_dependencies.txt 120 | 121 | cat /project/build/temp.linux-x86_64-cpython-38/vcpkg/buildtrees/gtk3/config-x64-linux-dbg-out.log 122 | -------------------------------------------------------------------------------- /bindings/Constants.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | namespace py = pybind11; 3 | 4 | #include "../include/DeepRTS/Constants.h" 5 | using namespace DeepRTS; 6 | 7 | void init_Constants(py::module &m) { 8 | 9 | auto constants = m.def_submodule("Constants"); 10 | 11 | constants.attr("MAX_PLAYERS") = py::int_(Constants::MAX_PLAYERS); 12 | constants.attr("MAX_UNITS") = py::int_(Constants::MAX_UNITS); 13 | constants.attr("ACTION_MIN") = py::int_(Constants::ACTION_MIN); 14 | constants.attr("ACTION_MAX") = py::int_(Constants::ACTION_MAX); 15 | 16 | 17 | py::enum_(constants, "Unit", py::arithmetic(), "Unit Constants") 18 | .value("Peasant", Constants::Unit::Peasant) 19 | .value("Peon", Constants::Unit::Peon) 20 | .value("TownHall", Constants::Unit::TownHall) 21 | .value("Barracks", Constants::Unit::Barracks) 22 | .value("Footman", Constants::Unit::Footman) 23 | .value("Farm", Constants::Unit::Farm) 24 | .value("Archer", Constants::Unit::Archer) 25 | .value("None", Constants::Unit::None); 26 | 27 | py::enum_(constants, "Race", py::arithmetic(), "Race Constants") 28 | .value("Human", Constants::Race::Human) 29 | .value("Orc", Constants::Race::Orc); 30 | 31 | py::enum_(constants, "PlayerState", py::arithmetic(), "Player State") 32 | .value("Victory", Constants::PlayerState::Victory) 33 | .value("Defeat", Constants::PlayerState::Defeat) 34 | .value("Playing", Constants::PlayerState::Playing); 35 | 36 | py::enum_(constants, "State", py::arithmetic(), "State Constants") 37 | .value("Idle", Constants::State::Idle) 38 | .value("Spawning", Constants::State::Spawning) 39 | .value("Walking", Constants::State::Walking) 40 | .value("Despawned", Constants::State::Despawned) 41 | .value("Harvesting", Constants::State::Harvesting) 42 | .value("Building", Constants::State::Building) 43 | .value("Combat", Constants::State::Combat) 44 | .value("Dead", Constants::State::Dead) 45 | .value("Base", Constants::State::Base); 46 | 47 | py::enum_(constants, "Pathfinding", py::arithmetic(), "Pathfinding Constants") 48 | .value("Walkable", Constants::Pathfinding::Walkable) 49 | .value("All", Constants::Pathfinding::All) 50 | .value("Attackable", Constants::Pathfinding::Attackable) 51 | .value("Harvestable", Constants::Pathfinding::Harvestable); 52 | 53 | py::enum_(constants, "Direction", py::arithmetic(), "Direction Constants") 54 | .value("Down", Constants::Direction::Down) 55 | .value("Up", Constants::Direction::Up) 56 | .value("Left", Constants::Direction::Left) 57 | .value("Right", Constants::Direction::Right) 58 | .value("DownLeft", Constants::Direction::DownLeft) 59 | .value("DownRight", Constants::Direction::DownRight) 60 | .value("UpLeft", Constants::Direction::UpLeft) 61 | .value("UpRight", Constants::Direction::UpRight); 62 | 63 | py::enum_(constants, "Action", py::arithmetic(), "Action Constants") 64 | .value("PreviousUnit", Constants::Action::PreviousUnit) 65 | .value("NextUnit", Constants::Action::NextUnit) 66 | .value("MoveLeft", Constants::Action::MoveLeft) 67 | .value("MoveRight", Constants::Action::MoveRight) 68 | .value("MoveUp", Constants::Action::MoveUp) 69 | .value("MoveDown", Constants::Action::MoveDown) 70 | .value("MoveUpLeft", Constants::Action::MoveUpLeft) 71 | .value("MoveUpRight", Constants::Action::MoveUpRight) 72 | .value("MoveDownLeft", Constants::Action::MoveDownLeft) 73 | .value("MoveDownRight", Constants::Action::MoveDownRight) 74 | .value("Attack", Constants::Action::Attack) 75 | .value("Harvest", Constants::Action::Harvest) 76 | .value("Build0", Constants::Action::Build0) 77 | .value("Build1", Constants::Action::Build1) 78 | .value("Build2", Constants::Action::Build2) 79 | .value("NoAction", Constants::Action::NoAction); 80 | } -------------------------------------------------------------------------------- /src/ResourceLoader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by per-arne on 02.04.17. 3 | // 4 | 5 | #include 6 | #include 7 | #include "util/String.h" 8 | #include "ResourceLoader.h" 9 | #include 10 | #include 11 | #ifdef _WIN32 12 | #include 13 | #define GetCurrentDir _getcwd 14 | #elif defined __linux__ || defined __APPLE__ 15 | #include 16 | #define GetCurrentDir getcwd 17 | #endif 18 | 19 | #include 20 | CMRC_DECLARE(DeepRTSAssets); 21 | using namespace DeepRTS; 22 | 23 | std::string GetCurrentWorkingDir() 24 | { 25 | char buff[FILENAME_MAX]; 26 | GetCurrentDir(buff, FILENAME_MAX); 27 | std::string current_working_dir(buff); 28 | return current_working_dir; 29 | } 30 | 31 | std::string ResourceLoader::getFilePath(const std::string& fileName) { 32 | std::string workingDir = GetCurrentWorkingDir(); 33 | std::string assetLocation = "python"; 34 | 35 | if (workingDir.find(assetLocation) != std::string::npos) { 36 | // asset location is included (happens in python runtime) 37 | return workingDir + "/assets/" + fileName; 38 | 39 | } else { 40 | // Did not find asset location in Working directory 41 | return workingDir + "/" + assetLocation + "/assets/" + fileName; 42 | } 43 | 44 | } 45 | 46 | 47 | void ResourceLoader::loadMapJSON(const std::string& mapFile) { 48 | // If map is already loaded 49 | if(mapLoaded) { 50 | return; 51 | } 52 | 53 | try{ 54 | auto fs = cmrc::DeepRTSAssets::get_filesystem(); 55 | std::string fileName = "assets/maps/" + mapFile; 56 | auto tilePropertiesFile = fs.open(fileName); 57 | std::string tilePropertiesData = std::string(tilePropertiesFile.begin(), tilePropertiesFile.size()); 58 | 59 | try{ 60 | mapJSON = nlohmann::json::parse(tilePropertiesData); 61 | }catch(const nlohmann::json::exception&){ 62 | throw std::runtime_error("Failed to parse: " + mapFile + " (" + fileName + ")."); 63 | } 64 | mapLoaded = true; 65 | 66 | }catch(const std::exception& err){ 67 | 68 | 69 | // Retrieve map file location 70 | auto mapFilePath = getFilePath("maps/" + mapFile); 71 | 72 | // Read Map data 73 | std::ifstream map(mapFilePath); 74 | 75 | if (map.is_open()) { 76 | try{ 77 | mapJSON = nlohmann::json::parse(map); 78 | }catch(const nlohmann::json::exception&){ 79 | throw std::runtime_error("Failed to parse: " + mapFile + " (" + mapFilePath + ")."); 80 | } 81 | mapLoaded = true; 82 | } 83 | else { 84 | throw std::runtime_error("File Error: Could not find: " + mapFile + " (" + mapFilePath + ").\nEnsure that the data directory exists!"); 85 | } 86 | 87 | } 88 | 89 | 90 | 91 | 92 | 93 | } 94 | 95 | TilePropertyData ResourceLoader::loadMAPJson(const nlohmann::json& tJSON){ 96 | TilePropertyData data; 97 | // Parse tile types 98 | for(auto &item : tJSON["tile_types"].items()){ 99 | 100 | for(auto &ele : item.value()){ 101 | 102 | if(ele.is_string()){ 103 | auto range = StringUtil::split(ele.get(), "-"); 104 | for(auto i = std::stoi(range[0]); i <= std::stoi(range[1]); i++){ 105 | 106 | data.tileID2Type.insert(std::make_pair(i, item.key())); 107 | } 108 | }else if(ele.is_number_integer()){ 109 | 110 | data.tileID2Type.insert(std::make_pair(ele.get(), item.key())); 111 | 112 | } 113 | 114 | } 115 | } 116 | 117 | // Parse tile data 118 | for(auto &item : tJSON["tile_metadata"].items()){ 119 | //std::cout << item.key() << std::endl; 120 | data.tileData.insert(std::make_pair(item.key(), item.value())); 121 | } 122 | return data; 123 | } 124 | 125 | void ResourceLoader::loadTileJSON() { 126 | auto fs = cmrc::DeepRTSAssets::get_filesystem(); 127 | std::string fileName = "assets/tile_properties.json"; 128 | auto tilePropertiesFile = fs.open(fileName); 129 | std::string tilePropertiesData = std::string(tilePropertiesFile.begin(), tilePropertiesFile.size()); 130 | 131 | try{ 132 | tileJSON = nlohmann::json::parse(tilePropertiesData); 133 | }catch(const nlohmann::json::exception&){ 134 | throw std::runtime_error("Failed to parse: " + fileName + "."); 135 | } 136 | tileData = ResourceLoader::loadMAPJson(tileJSON); 137 | tilesLoaded = true; 138 | 139 | 140 | } 141 | 142 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug/ 2 | .idea/ 3 | # Prerequisites 4 | *.d 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | *.smod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | 36 | 37 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 38 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 39 | 40 | # User-specific stuff: 41 | .idea/**/workspace.xml 42 | .idea/**/tasks.xml 43 | .idea/dictionaries 44 | 45 | # Sensitive or high-churn files: 46 | .idea/**/dataSources/ 47 | .idea/**/dataSources.ids 48 | .idea/**/dataSources.xml 49 | .idea/**/dataSources.local.xml 50 | .idea/**/sqlDataSources.xml 51 | .idea/**/dynamic.xml 52 | .idea/**/uiDesigner.xml 53 | 54 | # Gradle: 55 | .idea/**/gradle.xml 56 | .idea/**/libraries 57 | 58 | # Mongo Explorer plugin: 59 | .idea/**/mongoSettings.xml 60 | 61 | ## File-based project format: 62 | *.iws 63 | 64 | ## Plugin-specific files: 65 | 66 | # IntelliJ 67 | /out/ 68 | 69 | # mpeltonen/sbt-idea plugin 70 | .idea_modules/ 71 | 72 | # JIRA plugin 73 | atlassian-ide-plugin.xml 74 | 75 | # Crashlytics plugin (for Android Studio and IntelliJ) 76 | com_crashlytics_export_strings.xml 77 | crashlytics.properties 78 | crashlytics-build.properties 79 | fabric.properties 80 | 81 | CMakeCache.txt 82 | CMakeFiles 83 | CMakeScripts 84 | Testing 85 | Makefile 86 | cmake_install.cmake 87 | install_manifest.txt 88 | compile_commands.json 89 | CTestTestfile.cmake 90 | 91 | *.tlog 92 | *.iobj 93 | *.ipdb 94 | /x64 95 | 96 | # Byte-compiled / optimized / DLL files 97 | __pycache__/ 98 | *.py[cod] 99 | *$py.class 100 | 101 | # C extensions 102 | *.so 103 | 104 | # Distribution / packaging 105 | .Python 106 | env/ 107 | build/ 108 | develop-eggs/ 109 | dist/ 110 | downloads/ 111 | eggs/ 112 | .eggs/ 113 | lib/ 114 | lib64/ 115 | parts/ 116 | sdist/ 117 | var/ 118 | wheels/ 119 | *.egg-info/ 120 | .installed.cfg 121 | *.egg 122 | 123 | # PyInstaller 124 | # Usually these files are written by a python script from a template 125 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 126 | *.manifest 127 | *.spec 128 | 129 | # Installer logs 130 | pip-log.txt 131 | pip-delete-this-directory.txt 132 | 133 | # Unit test / coverage reports 134 | htmlcov/ 135 | .tox/ 136 | .coverage 137 | .coverage.* 138 | .cache 139 | nosetests.xml 140 | coverage.xml 141 | *,cover 142 | .hypothesis/ 143 | 144 | # Translations 145 | *.mo 146 | *.pot 147 | 148 | # Django stuff: 149 | *.log 150 | local_settings.py 151 | 152 | # Flask stuff: 153 | instance/ 154 | .webassets-cache 155 | 156 | # Scrapy stuff: 157 | .scrapy 158 | 159 | # Sphinx documentation 160 | docs/_build/ 161 | 162 | # PyBuilder 163 | target/ 164 | 165 | # Jupyter Notebook 166 | .ipynb_checkpoints 167 | 168 | # pyenv 169 | .python-version 170 | 171 | # celery beat schedule file 172 | celerybeat-schedule 173 | 174 | # SageMath parsed files 175 | *.sage.py 176 | 177 | # dotenv 178 | .env 179 | 180 | # virtualenv 181 | .venv 182 | venv/ 183 | ENV/ 184 | 185 | # Spyder project settings 186 | .spyderproject 187 | 188 | # Rope project settings 189 | .ropeproject 190 | project/msvc14/data/ 191 | project/msvc14/x64/ 192 | project/msvc15/x64/ 193 | project/msvc15/data/ 194 | project/msvc15/Y/ 195 | project/msvc15/.vs/ 196 | project/msvc15/State/ 197 | src/flatbuffers/State/ 198 | src/game/serialization/ 199 | src/game/python/State/ 200 | project/msvc15/RemoteAI.py 201 | project/msvc15/DQN.py 202 | project/msvc15/GameMessage_pb2.py 203 | project/msvc15/Main.py 204 | project/msvc15/PyAI.py 205 | project/msvc14/games/ 206 | project/msvc14/Algorithms/ 207 | project/msvc14/Main.py 208 | project/msvc14/Main_Standalone.py 209 | project/msvc14/PyAI.py 210 | project/msvc14/RemoteAI.py 211 | project/msvc14/State/ 212 | project/msvc14/DQN.py 213 | project/msvc14/GameMessage_pb2.py 214 | project/msvc14/WarC2Sim++.VC.VC.opendb 215 | project/msvc14/WarC2Sim++.VC.db 216 | project/msvc14/WarC2Sim++.vcxproj.user 217 | project/msvc15/Algorithms/DQN/ 218 | project/msvc14/__init__.py 219 | project/msvc14/deeprts.h5 220 | project/msvc15/Algorithms/__init__.py 221 | project/msvc15/Main_Standalone.py 222 | project/msvc15/__init__.py 223 | WarC2Sim.iml 224 | docs/docs.iml 225 | project/msvc14/.vs/WarC2Sim++/v14/.suo 226 | python/DeepRTS/assets 227 | *.iml 228 | /test/experiments/ 229 | test/assets 230 | code/assets 231 | coding/private 232 | samples/private/ 233 | 234 | .DS_Store 235 | 236 | DeepRTS/.directory 237 | 238 | 239 | cmake-build-release 240 | cmake-build-debug 241 | docs/api/latex/ 242 | 243 | -------------------------------------------------------------------------------- /src/state/Harvesting.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Per-Arne on 26.02.2017. 3 | // 4 | #include "state/Harvesting.h" 5 | #include "unit/Unit.h" 6 | #include "util/Pathfinder.h" 7 | #include "Player.h" 8 | #include "Game.h" 9 | using namespace DeepRTS; 10 | 11 | void Harvesting::update(Unit & unit){ 12 | 13 | if (unit.harvestIterator == 0) { 14 | // Go to harvestable_tile; 15 | 16 | Tile *harvestTarget = unit.getTile(unit.harvestTargetID); 17 | 18 | 19 | if(unit.distance(*harvestTarget) > 1) { 20 | // Must walk 21 | // Find closest walkable tile to the target 22 | Tile* closestWalkable = Pathfinder::find_first_walkable_tile(harvestTarget); 23 | 24 | // If distance is > 1, change harvest_target 25 | if(closestWalkable->distance(*harvestTarget) > 1) { 26 | Tile *closestHarvestable = Pathfinder::find_first_harvestable_tile(closestWalkable); 27 | if(!closestHarvestable){ 28 | unit.transitionState(unit.stateManager->idleState); 29 | return; 30 | } 31 | unit.harvestTargetID = closestHarvestable->id; 32 | 33 | 34 | } 35 | 36 | unit.walkingGoalID = closestWalkable->id; 37 | unit.transitionState(unit.stateManager->walkingState); 38 | unit.enqueueState(unit.stateManager->harvestingState); 39 | } 40 | 41 | unit.harvestIterator = 1; 42 | 43 | 44 | 45 | 46 | } else if (unit.harvestIterator == 1) { 47 | // Start harvesting 48 | Tile *harvestTarget = unit.getTile(unit.harvestTargetID); 49 | 50 | 51 | if(unit.harvestTimer < unit.harvestInterval) { 52 | unit.harvestTimer += 1; 53 | return; 54 | } 55 | 56 | if(unit.lumberCarry + unit.goldCarry + unit.stoneCarry >= unit.carryCapacity) { 57 | // Return to base 58 | unit.harvestIterator = 2; 59 | return; 60 | } 61 | 62 | unit.lumberCarry += harvestTarget->lumberYield * unit.config.yieldModifierLumber; 63 | unit.goldCarry += harvestTarget->goldYield * unit.config.yieldModifierGold; 64 | unit.stoneCarry += harvestTarget->stoneYield * unit.config.yieldModifierStone; 65 | unit.player_.sGatheredGold += harvestTarget->goldYield; 66 | unit.player_.sGatheredLumber += harvestTarget->lumberYield; 67 | unit.player_.sGatheredStone += harvestTarget->stoneYield; 68 | harvestTarget->takeResource(harvestTarget->lumberYield + harvestTarget->goldYield + harvestTarget->stoneYield); 69 | 70 | // Callback 71 | unit.game->_onResourceGather(*harvestTarget, unit); 72 | unit.animationCounter++; 73 | 74 | // No more resources // TODO constant parameter Config 75 | if(harvestTarget->getResources() <= 0) { 76 | 77 | harvestTarget->setDepleted(); 78 | // Callback 79 | unit.game->_onResourceDepleted(*harvestTarget, unit); 80 | 81 | // Find new harvestable 82 | Tile *closestHarvestable = Pathfinder::find_first_harvestable_tile(harvestTarget); 83 | if(!closestHarvestable){ 84 | unit.transitionState(unit.stateManager->idleState); 85 | return; 86 | } 87 | 88 | 89 | unit.harvestTargetID = closestHarvestable->id; 90 | } 91 | 92 | unit.harvestTimer = 0; 93 | 94 | } else if (unit.harvestIterator == 2) { 95 | // Recall (Walking) 96 | Unit* closestBase = unit.closestRecallBuilding(); 97 | 98 | // No base to recall to 99 | if (!closestBase) { 100 | unit.transitionState(); 101 | return; 102 | } 103 | 104 | 105 | if(unit.distance(*closestBase) > 1) { 106 | // Must walk 107 | unit.walkingGoalID = closestBase->tile->id; 108 | unit.transitionState(unit.stateManager->walkingState); 109 | unit.enqueueState(unit.stateManager->harvestingState); 110 | return; 111 | } else { 112 | // Can deliver 113 | unit.player_.addGold(unit.goldCarry); 114 | unit.player_.addLumber(unit.lumberCarry); 115 | unit.player_.addStone(unit.stoneCarry); 116 | 117 | unit.goldCarry = 0; 118 | unit.lumberCarry = 0; 119 | unit.stoneCarry = 0; 120 | 121 | if(unit.config.harvestForever) 122 | { 123 | unit.transitionState(unit.stateManager->harvestingState); 124 | }else{ 125 | unit.transitionState(); 126 | } 127 | } 128 | 129 | } 130 | } 131 | 132 | void Harvesting::end(Unit & unit){ 133 | (void)(unit); 134 | } 135 | 136 | void Harvesting::init(Unit & unit){ 137 | unit.harvestTimer = 0; 138 | unit.harvestIterator = 0; 139 | unit.tile->triggerOnTileChange(); 140 | 141 | } 142 | 143 | -------------------------------------------------------------------------------- /include/DeepRTS/Constants.h: -------------------------------------------------------------------------------- 1 | #pragma clang diagnostic push 2 | // 3 | // Created by Per-Arne on 24.02.2017. 4 | // 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEBUG(x) do { std::cerr << x; } while (0) 12 | namespace DeepRTS { 13 | 14 | namespace Constants { 15 | 16 | const int MAX_PLAYERS = 8; 17 | const int MAX_UNITS = 1000; 18 | const int ACTION_MIN = 1; 19 | const int ACTION_MAX = 16; // Set based on last action in enum 20 | 21 | 22 | enum Unit { 23 | Peasant = 1, 24 | Peon = 2, 25 | TownHall = 3, 26 | 27 | Barracks = 4, 28 | Footman = 5, 29 | Farm = 6, 30 | Archer = 7, 31 | 32 | None = -1 33 | }; 34 | 35 | 36 | enum Race { 37 | Human = 1, 38 | Orc = 2 39 | }; 40 | 41 | enum PlayerState { 42 | Victory = 1, 43 | Defeat = 2, 44 | Playing = 3 45 | }; 46 | 47 | enum Resource { 48 | Lumber = 1, 49 | Gold = 2, 50 | Stone = 3, 51 | Food = 4 52 | }; 53 | 54 | const std::unordered_map TypeToID = { 55 | {"Spawn", 1}, 56 | {"Grass", 2}, 57 | {"Wall", 3}, 58 | {"Desert", 4}, 59 | {"Water", 5}, 60 | {"Lumber", 6}, 61 | {"Gold", 7}, 62 | {"Stone", 8}, 63 | {"Lava", 9} 64 | }; 65 | 66 | 67 | enum State { 68 | Spawning = 1, 69 | Walking = 2, 70 | Despawned = 3, 71 | Harvesting = 4, 72 | Building = 5, 73 | Combat = 6, 74 | Dead = 7, 75 | Idle = 8, 76 | Base = -1, 77 | }; 78 | 79 | enum Pathfinding { 80 | Walkable = 1, 81 | All = 2, 82 | Attackable = 3, 83 | Harvestable = 4 84 | }; 85 | 86 | enum Direction { 87 | Down = 1, 88 | Up = 2, 89 | Left = 3, 90 | Right = 4, 91 | DownLeft = 5, 92 | DownRight = 6, 93 | UpLeft = 7, 94 | UpRight = 8 95 | }; 96 | 97 | enum Action { 98 | PreviousUnit = 1, 99 | NextUnit = 2, 100 | MoveLeft = 3, 101 | MoveRight = 4, 102 | MoveUp = 5, 103 | MoveDown = 6, 104 | MoveUpLeft = 7, 105 | MoveUpRight = 8, 106 | MoveDownLeft = 9, 107 | MoveDownRight = 10, 108 | 109 | Attack = 11, 110 | Harvest = 12, 111 | 112 | Build0 = 13, 113 | Build1 = 14, 114 | Build2 = 15, 115 | NoAction = 16, 116 | }; 117 | 118 | class Map { 119 | public: 120 | [[maybe_unused]] inline static const std::string EBLIL = "10x10-2p-ffa-Eblil.json"; 121 | [[maybe_unused]] inline static const std::string UTHA = "15x15-1p-ffa-Utha-Lava.json"; 122 | [[maybe_unused]] inline static const std::string CRESAL = "15x15-2p-ffa-Cresal.json"; 123 | [[maybe_unused]] inline static const std::string GONDOR = "21x21-1p-scenario-Gondor.json"; 124 | [[maybe_unused]] inline static const std::string EFLINES = "21x21-2p-ffa-Eflines.json"; 125 | [[maybe_unused]] inline static const std::string VASTRANA = "21x21-2p-ffa-FindGold-Vastrana.json"; 126 | [[maybe_unused]] inline static const std::string BLOILOR = "30x30-4p-ffa-Bloilor-Lava.json"; 127 | [[maybe_unused]] inline static const std::string THELOR_1 = "31x31-2p-ffa-Thelor.json"; 128 | [[maybe_unused]] inline static const std::string THELOR_2 = "31x31-4p-ffa-Thelor.json"; 129 | [[maybe_unused]] inline static const std::string THELOR_3 = "31x31-6p-ffa-Thelor.json"; 130 | 131 | }; 132 | 133 | const std::map ActionToName = { 134 | {PreviousUnit, "Prev Unit"}, 135 | {NextUnit, "Next Unit"}, 136 | {MoveLeft, "Move Left"}, 137 | {MoveRight, "Move Right"}, 138 | {MoveUp, "Move Up"}, 139 | {MoveDown, "Move Down"}, 140 | {MoveUpLeft, "Move Up Left"}, 141 | {MoveUpRight, "Move Up Right"}, 142 | {MoveDownLeft, "Move Down Left"}, 143 | {MoveDownRight, "Move Down Right"}, 144 | {Attack, "Attack"}, 145 | {Harvest, "Harvest"}, 146 | {Build0, "Build 0"}, 147 | {Build1, "Build 1"}, 148 | {Build2, "Build 2"}, 149 | {NoAction, "No Action"} 150 | }; 151 | 152 | 153 | } 154 | } 155 | #pragma clang diagnostic pop -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import re 3 | 4 | import sys 5 | import platform 6 | import subprocess 7 | import os 8 | 9 | from setuptools import setup, Extension, find_packages 10 | from setuptools.command.build_ext import build_ext 11 | from distutils.version import LooseVersion 12 | 13 | 14 | class CMakeExtension(Extension): 15 | def __init__(self, name, sourcedir=''): 16 | super().__init__(name, sources=[]) 17 | self.sourcedir = os.path.abspath(sourcedir) 18 | 19 | 20 | class CMakeBuild(build_ext): 21 | def run(self): 22 | if not self._check_cmake(): 23 | raise RuntimeError("CMake must be installed to build the following extensions: " + 24 | ", ".join(e.name for e in self.extensions)) 25 | 26 | for ext in self.extensions: 27 | self.build_extension(ext) 28 | 29 | @staticmethod 30 | def _check_cmake(): 31 | try: 32 | out = subprocess.check_output(['cmake', '--version']) 33 | if platform.system() == "Windows": 34 | cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) 35 | if cmake_version < '3.1.0': 36 | raise RuntimeError("CMake >= 3.1.0 is required on Windows") 37 | return True 38 | except OSError: 39 | return False 40 | 41 | def build_dependencies(self, current_dir: pathlib.Path, build_dir: pathlib.Path): 42 | # Get the absolute path of the current directory 43 | 44 | # VC pkg dir = Current directory + /vcpkg 45 | vcpkg_config_dir = current_dir.resolve() 46 | 47 | vcpkg_build_dir = (build_dir / "vcpkg").resolve() 48 | toolchain_file = vcpkg_build_dir / "scripts" / "buildsystems" / "vcpkg.cmake" 49 | 50 | # Get macOS version and set MACOSX_DEPLOYMENT_TARGET environment variable 51 | # macos_version = subprocess.check_output(["sw_vers", "-productVersion"]).decode().strip().rsplit('.', 1)[0] 52 | # os.environ["MACOSX_DEPLOYMENT_TARGET"] = macos_version 53 | 54 | # Install dependencies 55 | subprocess.run([ 56 | str(vcpkg_config_dir / "vcpkg_install.sh"), 57 | str(build_dir.absolute()) 58 | ], check=True) 59 | 60 | return toolchain_file 61 | 62 | def build_extension(self, ext): 63 | extdir = os.path.abspath(os.path.join(os.path.dirname(self.get_ext_fullpath(ext.name)), "DeepRTS")) 64 | cfg = 'Debug' if self.debug else 'Release' 65 | 66 | cmake_args = [ 67 | '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, 68 | '-DPython_EXECUTABLE=' + sys.executable, 69 | '-DPYTHON_BUILD=true' 70 | ] 71 | 72 | build_args = ['--config', cfg] 73 | 74 | if platform.system() == "Windows": 75 | cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] 76 | if sys.maxsize > 2 ** 32: 77 | cmake_args += ['-A', 'x64'] 78 | build_args += ['--', '/m'] 79 | else: 80 | cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] 81 | build_args += ['--', '-j'] 82 | 83 | env = os.environ.copy() 84 | env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), 85 | self.distribution.get_version()) 86 | 87 | if not os.path.exists(self.build_temp): 88 | os.makedirs(self.build_temp) 89 | 90 | # Current dir 91 | current_dir = pathlib.Path.cwd() 92 | 93 | # Build dependencies 94 | toolchain_file = self.build_dependencies(current_dir, pathlib.Path(self.build_temp)) 95 | 96 | # CMake 97 | subprocess.run([ 98 | "cmake", 99 | # "-GNinja", 100 | f"-B{self.build_temp}", 101 | "-S.", 102 | f"-DCMAKE_TOOLCHAIN_FILE={toolchain_file}", 103 | "-DCMAKE_BUILD_TYPE=Release" 104 | ] + cmake_args, 105 | check=True, 106 | cwd=current_dir, 107 | env=env 108 | ) 109 | 110 | # CMake build 111 | subprocess.run([ 112 | "cmake", 113 | "--build", 114 | self.build_temp 115 | ] + build_args, 116 | check=True, 117 | cwd=current_dir 118 | ) 119 | 120 | 121 | setup( 122 | name='DeepRTS', 123 | author='Per-Arne Andersen', 124 | author_email='per@sysx.no', 125 | url='https://github.com/cair/deep-rts', 126 | description='A Real-Time-Strategy game for Deep Learning research ', 127 | long_description='', 128 | include_package_data=True, 129 | packages=find_packages( 130 | exclude=["coding"], 131 | include=["DeepRTS*"] 132 | 133 | ), 134 | ext_modules=[ 135 | CMakeExtension('libdeeprts') 136 | ], 137 | cmdclass=dict( 138 | build_ext=CMakeBuild, 139 | ), 140 | install_requires=['numpy'], 141 | zip_safe=False, 142 | ) 143 | -------------------------------------------------------------------------------- /DeepRTS/python/game.py: -------------------------------------------------------------------------------- 1 | from DeepRTS import Engine, Constants 2 | from DeepRTS.python import GUI 3 | from DeepRTS.python import Config 4 | from DeepRTS.python import DeepRTSPlayer 5 | 6 | import numpy as np 7 | import random 8 | import os 9 | import argparse 10 | import gym 11 | 12 | 13 | 14 | dir_path = os.path.dirname(os.path.realpath(__file__)) 15 | 16 | 17 | class Game(Engine.Game): 18 | 19 | def __init__(self, 20 | map_name, 21 | n_players=2, 22 | engine_config=Engine.Config.defaults(), 23 | gui_config=None, 24 | tile_size=32, 25 | terminal_signal=False 26 | ): 27 | # This sets working directory, so that the C++ can load files correctly (dir_path not directly accessible in 28 | # c++) 29 | os.chdir(dir_path) 30 | 31 | # Override map 32 | try: 33 | # This sometimmes fails under ray 34 | parser = argparse.ArgumentParser(description='Process some integers.') 35 | parser.add_argument('--map', action="store", dest="map", type=str) 36 | args = parser.parse_args() 37 | 38 | if args.map is not None: 39 | map_name = args.map 40 | except: 41 | pass 42 | 43 | # TODO 44 | if engine_config: 45 | engine_config.set_terminal_signal(terminal_signal) 46 | # Disable terminal signal 47 | engine_config.set_terminal_signal(terminal_signal) 48 | 49 | # Call C++ constructor 50 | super(Game, self).__init__(map_name, engine_config) 51 | 52 | # Event listeners 53 | self._listeners = { 54 | "on_tile_change": [] 55 | } 56 | 57 | self._render_every = 1 58 | self._view_every = 1 59 | self._capture_every = 1 60 | 61 | self.gui = GUI(self, tile_size=tile_size, config=gui_config if isinstance(gui_config, Config) else Config()) 62 | self._py_players = [] # Keep reference of the py object 63 | for i in range(n_players): 64 | player = DeepRTSPlayer(self) 65 | self.insert_player(player) 66 | self._py_players.append(player) 67 | 68 | # Select first player as default 69 | self.set_player(self.players[0]) 70 | 71 | # Define the action space 72 | self.action_space = LimitedDiscrete(Constants.action_min, Constants.action_max) 73 | 74 | # Define the observation space, here we assume that max is 255 (image) # TODO 75 | self.observation_space = gym.spaces.Box( 76 | 0, 77 | 255, 78 | shape=self.get_state().shape, dtype=np.float32) 79 | 80 | self.start() 81 | 82 | @property 83 | def players(self): 84 | return self._py_players 85 | 86 | @staticmethod 87 | def sample_action(self): 88 | return int(Engine.Constants.action_max * random.random()) + Engine.Constants.action_min 89 | 90 | def update(self): 91 | self.tick() 92 | 93 | if self.gui.config.input: 94 | self.event() 95 | 96 | super().update() 97 | 98 | self.caption() 99 | 100 | if self.gui.config.render: 101 | self.render() 102 | 103 | if self.gui.config.view: 104 | self.view() 105 | 106 | def _render(self): 107 | if self.get_ticks() % self._render_every == 0: 108 | self.gui.render() 109 | 110 | def view(self): 111 | if self.get_ticks() % self._view_every == 0: 112 | self.gui.view() 113 | 114 | def event(self): 115 | self.gui.event() 116 | 117 | def capture(self): 118 | if self.get_ticks() % self._capture_every == 0: 119 | return self.gui.capture() 120 | return None 121 | 122 | def get_state(self, image=False, copy=True): 123 | if image: 124 | return self.gui.capture(copy=copy) 125 | else: 126 | return np.array(self.state, copy=copy) 127 | 128 | def _caption(self): 129 | pass 130 | 131 | def _on_unit_create(self, unit): 132 | pass 133 | 134 | def _on_unit_destroy(self, unit): 135 | pass 136 | 137 | def _on_episode_start(self): 138 | pass 139 | # for tile in self.tilemap.tiles: 140 | # self.gui.gui_tiles.set_tile(tile.x, tile.y, tile.get_type_id()) 141 | 142 | def _on_episode_end(self): 143 | pass 144 | 145 | def _on_tile_deplete(self, tile): 146 | # TODO 147 | pass 148 | # self.gui.gui_tiles.set_tile(tile.x, tile.y, tile.get_type_id()) 149 | 150 | def _on_tile_change(self, tile): 151 | self.gui.on_tile_change(tile) 152 | 153 | def set_render_frequency(self, interval): 154 | self._render_every = interval 155 | 156 | def set_player(self, player: DeepRTSPlayer): 157 | self.set_selected_player(player) 158 | 159 | def set_view_every(self, n): 160 | self._view_every = n 161 | 162 | def set_capture_every(self, n): 163 | self._capture_every = n -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description [![Build Status](https://travis-ci.org/cair/deep-rts.svg?branch=master)](https://travis-ci.org/cair/deep-rts) [![Documentation](https://img.shields.io/badge/docs-readme-blue.svg)](https://cair.github.io/deep-rts) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/cair/DeepRTS/c%2B%2B/LICENCE.MIT) 4 | DeepRTS is a high-performance Real-TIme strategy game for Reinforcement Learning research. 5 | It is written in C++ for performance, 6 | but provides an python interface to better interface with machine-learning toolkits. 7 | Deep RTS can process the game with over **6 000 000** steps per second and **2 000 000** steps when rendering graphics. 8 | In comparison to other solutions, such as StarCraft, this is over **15 000% faster simulation** time running on Intel i7-8700k with Nvidia RTX 2080 TI. 9 | 10 | The aim of Deep RTS is to bring a more affordable and sustainable solution to RTS AI research by reducing computation time. 11 | 12 | It is recommended to use the master-branch for the newest (and usually best) version of the environment. I am greatful for any input in regards to improving the environment. 13 | 14 | 15 | Please use the following citation when using this in your work! 16 | ``` 17 | @INPROCEEDINGS{8490409, 18 | author={P. {Andersen} and M. {Goodwin} and O. {Granmo}}, 19 | booktitle={2018 IEEE Conference on Computational Intelligence and Games (CIG)}, 20 | title={Deep RTS: A Game Environment for Deep Reinforcement Learning in Real-Time Strategy Games}, 21 | year={2018}, 22 | volume={}, 23 | number={}, 24 | pages={1-8}, 25 | keywords={computer games;convolution;feedforward neural nets;learning (artificial intelligence);multi-agent systems;high-performance RTS game;artificial intelligence research;deep reinforcement learning;real-time strategy games;computer games;RTS AIs;Deep RTS game environment;StarCraft II;Deep Q-Network agent;cutting-edge artificial intelligence algorithms;Games;Learning (artificial intelligence);Machine learning;Planning;Ground penetrating radar;Geophysical measurement techniques;real-time strategy game;deep reinforcement learning;deep q-learning}, 26 | doi={10.1109/CIG.2018.8490409}, 27 | ISSN={2325-4270}, 28 | month={Aug},} 29 | ``` 30 | 31 | 32 | 33 | 34 | 35 | ## Dependencies 36 | 37 | * Python >= 3.9.1 38 | 39 | # Installation 40 | 41 | ### Method 1 (From Git Repo) 42 | ``` 43 | sudo pip3 install git+https://github.com/cair/DeepRTS.git 44 | ``` 45 | 46 | ### Method 2 (Clone & Build) 47 | ``` 48 | git clone https://github.com/cair/deep-rts.git 49 | cd deep-rts 50 | git submodule sync 51 | git submodule update --init 52 | sudo pip3 install . 53 | ``` 54 | 55 | # Available maps 56 | ``` 57 | 10x10-2-FFA 58 | 15x15-2-FFA 59 | 21x21-2-FFA 60 | 31x31-2-FFA 61 | 31x31-4-FFA 62 | 31x31-6-FFA 63 | ``` 64 | 65 | # Scenarios 66 | Deep RTS features scenarios which is pre-built mini-games. 67 | These mini-games is well suited to train agents on specific tasks, 68 | or to test algorithms in different problem setups. 69 | The benefits of using scenarios is that you can trivially design reward functions using criterias that each outputs a reward/punishment signal depending on completion of the task. 70 | Examples of tasks are to: 71 | * collect 1000 gold 72 | * do 100 damage 73 | * take 1000 damage 74 | * defeat 5 enemies 75 | 76 | Deep RTS currently implements the following scenarios 77 | ``` 78 | GoldCollectFifteen 79 | GeneralAIOneVersusOne 80 | ``` 81 | 82 | # Minimal Example 83 | ```python 84 | import random 85 | from DeepRTS.python import Config 86 | from DeepRTS.python import scenario 87 | 88 | if __name__ == "__main__": 89 | random_play = True 90 | episodes = 100 91 | 92 | for i in range(episodes): 93 | env = scenario.GeneralAI_1v1(Config.Map.THIRTYONE) 94 | state = env.reset() 95 | done = False 96 | 97 | while not done: 98 | env.game.set_player(env.game.players[0]) 99 | action = random.randrange(15) 100 | next_state, reward, done, _ = env.step(action) 101 | state = next_state 102 | 103 | if (done): 104 | break 105 | 106 | env.game.set_player(env.game.players[1]) 107 | action = random.randrange(15) 108 | next_state, reward, done, _ = env.step(action) 109 | state = next_state 110 | 111 | ``` 112 | # In-Game Footage 113 | 114 | ### 10x10 - 2 Player - free-for-all 115 | 116 | 117 | ### 15x15 - 2 Player - free-for-all 118 | 119 | 120 | ### 21x21 - 2 Player - free-for-all 121 | 122 | 123 | ### 31x31 - 2 Player - free-for-all 124 | 125 | 126 | ### 31x31 - 4 Player - free-for-all 127 | 128 | 129 | ### 31x3 - 6 Player - free-for-all 130 | 131 | --------------------------------------------------------------------------------