Skip to content

Commit

Permalink
refactor(internal): Turn variant into its own class (#6592)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amazinite authored May 13, 2022
1 parent 8bd80d3 commit 4dc603e
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 101 deletions.
6 changes: 6 additions & 0 deletions EndlessSky.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
87D6407E8B579EB502BFBCE5 /* GameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9F0F4096A9008E2D8F3304BB /* GameAction.cpp */; };
88A64339B56EBA1F7923E1C7 /* GameLoadingPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E640C7A366679B27CCADAC /* GameLoadingPanel.cpp */; };
90CF46CE84794C6186FC6CE2 /* EsUuid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 950742538F8CECF5D4168FBC /* EsUuid.cpp */; };
920F40E0ADECA8926F423FDA /* Variant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 61FA4C2BB89E08C5E2B8B4B9 /* Variant.cpp */; };
94DF4B5B8619F6A3715D6168 /* Weather.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E8A4C648B242742B22A34FA /* Weather.cpp */; };
9E1F4BF78F9E1FC4C96F76B5 /* Test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2E8047A8987DD8EC99FF8E2E /* Test.cpp */; };
A90633FF1EE602FD000DA6C0 /* LogbookPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A90633FD1EE602FD000DA6C0 /* LogbookPanel.cpp */; };
Expand Down Expand Up @@ -227,6 +228,8 @@
5155CD721DBB9FF900EF090B /* Depreciation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Depreciation.h; path = source/Depreciation.h; sourceTree = "<group>"; };
5CE3475B85CE8C48D98664B7 /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Test.h; path = source/Test.h; sourceTree = "<group>"; };
5CF247B48EEC7A3C366C1DFA /* DamageDealt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DamageDealt.h; path = source/DamageDealt.h; sourceTree = "<group>"; };
5EBC44769E84CF0C953D08B3 /* Variant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Variant.h; path = source/Variant.h; sourceTree = "<group>"; };
61FA4C2BB89E08C5E2B8B4B9 /* Variant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Variant.cpp; path = source/Variant.cpp; sourceTree = "<group>"; };
6245F8231D301C7400A7A094 /* Body.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Body.cpp; path = source/Body.cpp; sourceTree = "<group>"; };
6245F8241D301C7400A7A094 /* Body.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Body.h; path = source/Body.h; sourceTree = "<group>"; };
6245F8261D301C9000A7A094 /* Hardpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Hardpoint.cpp; path = source/Hardpoint.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -858,6 +861,8 @@
5CF247B48EEC7A3C366C1DFA /* DamageDealt.h */,
D0FA4800BE72C1B5A7D567B9 /* MenuAnimationPanel.cpp */,
8CB543A1AA20F764DD7FC15A /* MenuAnimationPanel.h */,
61FA4C2BB89E08C5E2B8B4B9 /* Variant.cpp */,
5EBC44769E84CF0C953D08B3 /* Variant.h */,
);
name = source;
sourceTree = "<group>";
Expand Down Expand Up @@ -1215,6 +1220,7 @@
027A4E858B292CE9F0A06F89 /* FireCommand.cpp in Sources */,
E3D54794A1EEF51CD4859170 /* DamageProfile.cpp in Sources */,
F35E4D6EA465D71CDA282EBA /* MenuAnimationPanel.cpp in Sources */,
920F40E0ADECA8926F423FDA /* Variant.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 2 additions & 0 deletions EndlessSkyLib.cbp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@
<Unit filename="source/UI.h" />
<Unit filename="source/UniverseObjects.cpp" />
<Unit filename="source/UniverseObjects.h" />
<Unit filename="source/Variant.cpp" />
<Unit filename="source/Variant.h" />
<Unit filename="source/Visual.cpp" />
<Unit filename="source/Visual.h" />
<Unit filename="source/Weapon.cpp" />
Expand Down
113 changes: 27 additions & 86 deletions source/Fleet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.

#include <algorithm>
#include <cmath>
#include <functional>
#include <iterator>

using namespace std;
Expand Down Expand Up @@ -204,27 +205,17 @@ void Fleet::Load(const DataNode &node)
{
resetVariants = false;
variants.clear();
total = 0;
}
variants.emplace_back(child);
total += variants.back().weight;
}
else if(key == "variant")
{
// If given a full ship definition of one of this fleet's variant members, remove the variant.
bool didRemove = false;
// If given a full definition of one of this fleet's variant members, remove the variant.
Variant toRemove(child);
for(auto it = variants.begin(); it != variants.end(); ++it)
if(toRemove.ships.size() == it->ships.size() &&
is_permutation(it->ships.begin(), it->ships.end(), toRemove.ships.begin()))
{
total -= it->weight;
variants.erase(it);
didRemove = true;
break;
}

if(!didRemove)
auto removeIt = std::remove(variants.begin(), variants.end(), toRemove);
if(removeIt != variants.end())
variants.erase(removeIt, variants.end());
else
child.PrintTrace("Warning: Did not find matching variant for specified operation:");
}
else
Expand All @@ -249,11 +240,10 @@ bool Fleet::IsValid(bool requireGovernment) const
if(fighterNames && fighterNames->IsEmpty())
return false;

// A fleet's variants should reference at least one valid ship.
for(auto &&v : variants)
if(none_of(v.ships.begin(), v.ships.end(),
[](const Ship *const s) noexcept -> bool { return s->IsValid(); }))
return false;
// Any variant a fleet could choose should be valid.
if(any_of(variants.begin(), variants.end(),
[](const Variant &v) noexcept -> bool { return !v.IsValid(); }))
return false;

return true;
}
Expand All @@ -264,28 +254,21 @@ void Fleet::RemoveInvalidVariants()
{
auto IsInvalidVariant = [](const Variant &v) noexcept -> bool
{
return v.ships.empty() || none_of(v.ships.begin(), v.ships.end(),
[](const Ship *const s) noexcept -> bool { return s->IsValid(); });
return !v.IsValid();
};
auto firstInvalid = find_if(variants.begin(), variants.end(), IsInvalidVariant);
if(firstInvalid == variants.end())
return;

// Ensure the class invariant can be maintained.
// (This must be done first as we cannot do anything but `erase` elements filtered by `remove_if`.)
int removedWeight = 0;
for(auto it = firstInvalid; it != variants.end(); ++it)
if(IsInvalidVariant(*it))
removedWeight += it->weight;

int total = variants.TotalWeight();
auto removeIt = remove_if(firstInvalid, variants.end(), IsInvalidVariant);
int count = distance(removeIt, variants.end());
variants.erase(removeIt, variants.end());

Files::LogError("Warning: " + (fleetName.empty() ? "unnamed fleet" : "fleet \"" + fleetName + "\"")
+ ": Removing " + to_string(count) + " invalid " + (count > 1 ? "variants" : "variant")
+ " (" + to_string(removedWeight) + " of " + to_string(total) + " weight)");

total -= removedWeight;
variants.erase(removeIt, variants.end());
+ " (" + to_string(total - variants.TotalWeight()) + " of " + to_string(total) + " weight)");
}


Expand All @@ -300,12 +283,12 @@ const Government *Fleet::GetGovernment() const
// Choose a fleet to be created during flight, and have it enter the system via jump or planetary departure.
void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Planet *planet) const
{
if(!total || variants.empty() || personality.IsDerelict())
if(variants.empty() || personality.IsDerelict())
return;

// Pick a fleet variant to instantiate.
const Variant &variant = ChooseVariant();
if(variant.ships.empty())
const vector<const Ship *> &variantShips = variants.Get().Ships();
if(variantShips.empty())
return;

// Figure out what system the fleet is starting in, where it is going, and
Expand All @@ -328,7 +311,7 @@ void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Pla
bool hasJump = false;
bool hasHyper = false;
double jumpDistance = System::DEFAULT_NEIGHBOR_DISTANCE;
for(const Ship *ship : variant.ships)
for(const Ship *ship : variantShips)
{
if(ship->Attributes().Get("jump drive"))
{
Expand Down Expand Up @@ -393,7 +376,7 @@ void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Pla
source = linkVector[choice];
}

auto placed = Instantiate(variant);
auto placed = Instantiate(variantShips);
// Carry all ships that can be carried, as they don't need to be positioned
// or checked to see if they can access a particular planet.
for(auto &ship : placed)
Expand Down Expand Up @@ -469,20 +452,20 @@ void Fleet::Enter(const System &system, list<shared_ptr<Ship>> &ships, const Pla
// only uncarried ships will be added to the list (as any carriables will be stored in bays).
void Fleet::Place(const System &system, list<shared_ptr<Ship>> &ships, bool carried) const
{
if(!total || variants.empty())
if(variants.empty())
return;

// Pick a fleet variant to instantiate.
const Variant &variant = ChooseVariant();
if(variant.ships.empty())
const vector<const Ship *> &variantShips = variants.Get().Ships();
if(variantShips.empty())
return;

// Determine where the fleet is going to or coming from.
auto center = ChooseCenter(system);

// Place all the ships in the chosen fleet variant.
shared_ptr<Ship> flagship;
vector<shared_ptr<Ship>> placed = Instantiate(variant);
vector<shared_ptr<Ship>> placed = Instantiate(variantShips);
for(shared_ptr<Ship> &ship : placed)
{
// If this is a fighter and someone can carry it, no need to position it.
Expand Down Expand Up @@ -558,49 +541,7 @@ void Fleet::Place(const System &system, Ship &ship)

int64_t Fleet::Strength() const
{
if(!total || variants.empty())
return 0;

int64_t sum = 0;
for(const Variant &variant : variants)
{
int64_t thisSum = 0;
for(const Ship *ship : variant.ships)
thisSum += ship->Cost();
sum += thisSum * variant.weight;
}
return sum / total;
}



Fleet::Variant::Variant(const DataNode &node)
{
weight = 1;
if(node.Token(0) == "variant" && node.Size() >= 2)
weight = node.Value(1);
else if(node.Token(0) == "add" && node.Size() >= 3)
weight = node.Value(2);

for(const DataNode &child : node)
{
int n = 1;
if(child.Size() >= 2 && child.Value(1) >= 1.)
n = child.Value(1);
ships.insert(ships.end(), n, GameData::Ships().Get(child.Token(0)));
}
}



const Fleet::Variant &Fleet::ChooseVariant() const
{
// Pick a random variant based on the weights.
unsigned index = 0;
for(int choice = Random::Int(total); choice >= variants[index].weight; ++index)
choice -= variants[index].weight;

return variants[index];
return variants.Average(std::mem_fn(&Variant::Strength));
}


Expand All @@ -621,10 +562,10 @@ pair<Point, double> Fleet::ChooseCenter(const System &system)



vector<shared_ptr<Ship>> Fleet::Instantiate(const Variant &variant) const
vector<shared_ptr<Ship>> Fleet::Instantiate(const vector<const Ship *> &ships) const
{
vector<shared_ptr<Ship>> placed;
for(const Ship *model : variant.ships)
for(const Ship *model : ships)
{
// At least one of this variant's ships is valid, but we should avoid spawning any that are not defined.
if(!model->IsValid())
Expand Down
19 changes: 4 additions & 15 deletions source/Fleet.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.

#include "Personality.h"
#include "Sale.h"
#include "Variant.h"
#include "WeightedList.h"

#include <list>
#include <memory>
Expand Down Expand Up @@ -70,19 +72,8 @@ class Fleet {


private:
class Variant {
public:
explicit Variant(const DataNode &node);

int weight;
std::vector<const Ship *> ships;
};


private:
const Variant &ChooseVariant() const;
static std::pair<Point, double> ChooseCenter(const System &system);
std::vector<std::shared_ptr<Ship>> Instantiate(const Variant &variant) const;
std::vector<std::shared_ptr<Ship>> Instantiate(const std::vector<const Ship *> &ships) const;
bool PlaceFighter(std::shared_ptr<Ship> fighter, std::vector<std::shared_ptr<Ship>> &placed) const;
void SetCargo(Ship *ship) const;

Expand All @@ -92,9 +83,7 @@ class Fleet {
const Government *government = nullptr;
const Phrase *names = nullptr;
const Phrase *fighterNames = nullptr;
std::vector<Variant> variants;
// The sum of all available variant weights.
int total = 0;
WeightedList<Variant> variants;
// The number of different items the ships in this fleet will carry in cargo.
int cargo = 3;
std::vector<std::string> commodities;
Expand Down
Loading

0 comments on commit 4dc603e

Please sign in to comment.