From 42410e25f5c1dab5148085dc777fa2a635ee6ae9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Bergstr=C3=B6m?= <davbe125@student.liu.se>
Date: Wed, 1 Aug 2018 08:43:02 +0200
Subject: [PATCH] Rework TechTree and TechTreeImproved

Integrate all information from TechTreeImproved into the existing class
TechTree. Thus TechTreeImproved is deprecated and removed from the
Python-API.
---
 python-api-src/library.cpp |  3 ++-
 src/TechTree.cpp           | 44 +++++++++++++++++++++-----------------
 src/TechTreeImproved.cpp   | 43 ++++++++++++++++++++++++++++++++++---
 src/TechTreeImproved.h     |  9 ++++++--
 4 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/python-api-src/library.cpp b/python-api-src/library.cpp
index 165d95ca9..73222c244 100644
--- a/python-api-src/library.cpp
+++ b/python-api-src/library.cpp
@@ -112,12 +112,12 @@ PYBIND11_MODULE(library, m)
     m.def("create_participants", &sc2::CreateParticipant, "Create participant from bot", "race"_a, "bot"_a);
     m.def("create_computer", &sc2::CreateComputer, "Create participant from built-in Starcraft computer", "race"_a, "difficulty"_a);
 
+    /*
     py::class_<BuildDescription>(m, "BuildDescription")
         .def(py::init())
         .def_readwrite("producer_type", &BuildDescription::producer_type)
         .def_readwrite("result_type", &BuildDescription::result_type)
         .def_readwrite("ability_used", &BuildDescription::ability_used)
-        .def_readwrite("time", &BuildDescription::time)
         .def_readwrite("buildings_needed", &BuildDescription::buildings_needed)
         .def_readwrite("addons_needed", &BuildDescription::addons_needed);
 
@@ -125,4 +125,5 @@ PYBIND11_MODULE(library, m)
         .def(py::init())
         .def("load_data", &TechTreeImproved::LoadData)
         .def("how_to_build", &TechTreeImproved::HowToBuild);
+    */
 }
diff --git a/src/TechTree.cpp b/src/TechTree.cpp
index 576ec8804..a358e4d4e 100644
--- a/src/TechTree.cpp
+++ b/src/TechTree.cpp
@@ -27,35 +27,39 @@ void TechTree::onStart()
         return;
     }
 
-    for (std::pair<const UnitType, TypeData> & pair : m_unitTypeData)
+    std::set<sc2::UNIT_TYPEID> updated;
+
+    for (const BuildDescription & description : tree.BuildDescriptions())
     {
-        TypeData & data = pair.second;
+        if (m_unitTypeData.count(UnitType(description.result_type, m_bot)) == 0)
+        {
+            std::cout << "Inserting new information about UNIT_TYPEID: " 
+                << sc2::UnitTypeToName(description.result_type) << " (" 
+                << static_cast<unsigned int>(description.result_type) << ")" 
+                << std::endl;
+        }
 
-        const std::vector<BuildDescription> & howToBuild = tree.HowToBuild(pair.first.getAPIUnitType());
+        TypeData & data = m_unitTypeData[UnitType(description.result_type, m_bot)];
 
-        if (howToBuild.empty())
+        // If this is the first time we a way to build this type, remove previous data
+        if (updated.count(description.result_type) == 0)
         {
-            continue;
+            data.whatBuilds.clear();
+            data.requiredUnits.clear();
+            data.requiredUpgrades.clear();
+            updated.insert(description.result_type);
         }
 
-        data.whatBuilds.clear();
-        data.requiredUnits.clear();
-        // TODO: Support for upgrades, is it possible via JSON? Is the hard coded information correct?
-        data.requiredUpgrades.clear();
+        data.whatBuilds.push_back(UnitType(description.producer_type, m_bot));
 
-        for (const BuildDescription & description : howToBuild)
+        for (sc2::UNIT_TYPEID unit_typeid : description.buildings_needed)
         {
-            data.whatBuilds.push_back(UnitType(description.producer_type, m_bot));
-
-            for (sc2::UNIT_TYPEID unit_typeid : description.buildings_needed)
-            {
-                data.requiredUnits.push_back(UnitType(unit_typeid, m_bot));
-            }
+            data.requiredUnits.push_back(UnitType(unit_typeid, m_bot));
+        }
 
-            for (sc2::UNIT_TYPEID unit_typeid : description.addons_needed)
-            {
-                data.requiredAddons.push_back(UnitType(unit_typeid, m_bot));
-            }
+        for (sc2::UNIT_TYPEID unit_typeid : description.addons_needed)
+        {
+            data.requiredAddons.push_back(UnitType(unit_typeid, m_bot));
         }
     }
 
diff --git a/src/TechTreeImproved.cpp b/src/TechTreeImproved.cpp
index ab0a36b96..9a20e5535 100644
--- a/src/TechTreeImproved.cpp
+++ b/src/TechTreeImproved.cpp
@@ -27,7 +27,7 @@ void add_requirement(ResearchDescription & description, json & requirement)
     }
     else if (type == "not")
     {
-        // Ignore this. This is mostly used for: "We cannot do upgrade X if upgrade X is already running somewhere."
+        // Ignore this. This is used for: "We cannot do upgrade X if upgrade X is already running somewhere."
     }
     else if (type == "unitCount")
     {
@@ -114,7 +114,8 @@ void add_requirement(BuildDescription & description, json & requirement)
 
 void parse_build_description(BuildDescription & description, json & build_item)
 {
-    description.result_type = build_item["unit"];
+    description.result_type = static_cast<sc2::UNIT_TYPEID>(build_item["unit"]);
+    description.ability_used = static_cast<sc2::ABILITY_ID>(build_item["ability"]);
 
     if (build_item.find("requires") != build_item.end())
     {
@@ -142,7 +143,6 @@ void TechTreeImproved::parse_unit(json::iterator it)
 {
     sc2::UNIT_TYPEID producer_id = string_to_id(it.key());
     //std::string name = sc2::UnitTypeToName(producer_id);
-    std::vector<BuildDescription> build_descriptions;
 
     if (it.value().find("builds") != it.value().end())
     {
@@ -163,6 +163,7 @@ void TechTreeImproved::parse_unit(json::iterator it)
             {
                 result_to_data[description.result_type] = { description };
             }
+            build_descriptions.push_back(description);
         }
     }
 
@@ -186,6 +187,42 @@ void TechTreeImproved::parse_unit(json::iterator it)
             {
                 upgrade_to_data[description.result_type] = { description };
             }
+            research_descriptions.push_back(description);
+        }
+    }
+
+    if (it.value().find("morphs") != it.value().end())
+    {
+        for (auto & morph_item : it.value()["morphs"])
+        {
+            BuildDescription description;
+            description.producer_type = producer_id;
+            description.ability_used = static_cast<sc2::ABILITY_ID>(morph_item["ability"]);
+            description.result_type = static_cast<sc2::UNIT_TYPEID>(morph_item["unit"]);
+
+            if (morph_item.find("requires") != morph_item.end())
+            {
+                for (auto & requirement : morph_item["requires"])
+                {
+                    std::string type = requirement["type"];
+                    if (type == "unitCount")
+                    {
+                        for (auto & unit : requirement["unit"])
+                        {
+                            sc2::UNIT_TYPEID unit_typeid = static_cast<sc2::UNIT_TYPEID>(unit);
+                            description.buildings_needed.push_back(unit_typeid);
+                        }
+                    }
+                    else if (type == "upgradeCount")
+                    {
+                        sc2::UPGRADE_ID upgrade_id = static_cast<sc2::UPGRADE_ID>(requirement["upgrade"]);
+                        description.upgrades_needed.push_back(upgrade_id);
+                    }
+                }
+
+            }
+
+            build_descriptions.push_back(description);
         }
     }
 }
diff --git a/src/TechTreeImproved.h b/src/TechTreeImproved.h
index 5e9710a86..55b022701 100644
--- a/src/TechTreeImproved.h
+++ b/src/TechTreeImproved.h
@@ -12,12 +12,11 @@ struct BuildDescription
 {
     sc2::UNIT_TYPEID producer_type;
     sc2::UNIT_TYPEID result_type;
-    // TODO: Are these 2 used?
     sc2::AbilityID ability_used;
-    float time;
 
     std::vector<sc2::UNIT_TYPEID> buildings_needed;
     std::vector<sc2::UNIT_TYPEID> addons_needed;
+    std::vector<sc2::UPGRADE_ID> upgrades_needed;
 };
 
 struct ResearchDescription
@@ -35,6 +34,9 @@ class TechTreeImproved
     std::map<sc2::UNIT_TYPEID, std::vector<BuildDescription>> result_to_data;
     std::map<sc2::UPGRADE_ID, std::vector<ResearchDescription>> upgrade_to_data;
 
+    std::vector<BuildDescription> build_descriptions;
+    std::vector<ResearchDescription> research_descriptions;
+
     // If there is no BuildDescription for a given type, a reference to tihs list is returned.
     const std::vector<BuildDescription> empty_build {};
     const std::vector<ResearchDescription> empty_research {};
@@ -46,4 +48,7 @@ public:
     // Given a unit, how can we build it?
     const std::vector<BuildDescription> & HowToBuild(sc2::UnitTypeID unit) const;
     const std::vector<ResearchDescription> & HowToResearch(sc2::UpgradeID upgrade) const;
+
+    const std::vector<BuildDescription> & BuildDescriptions() const { return build_descriptions; }
+    const std::vector<ResearchDescription> & ResearchDescriptions() const { return research_descriptions; }
 };
\ No newline at end of file
-- 
GitLab