1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-10-31 00:07:39 +02:00

Merge pull request #211 from Chocimier/iss2321

Tested. Everthing looks fine so merging.
This commit is contained in:
ArseniyShestakov
2016-09-14 00:37:17 +03:00
committed by GitHub
4 changed files with 175 additions and 5 deletions

View File

@@ -520,6 +520,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
if(vstd::contains(t->forbiddenBuildings, ID))
return EBuildingState::FORBIDDEN; //forbidden
auto possiblyNotBuiltTest = [&](BuildingID id) -> bool
{
return ((id == BuildingID::CAPITOL) ? true : !t->hasBuilt(id));
};
std::function<bool(BuildingID id)> allowedTest = [&](BuildingID id) -> bool
{
if (vstd::contains(t->forbiddenBuildings, id))
{
return false;
}
return t->genBuildingRequirements(id, true).satisfiable(allowedTest, possiblyNotBuiltTest);
};
if (!t->genBuildingRequirements(ID, true).satisfiable(allowedTest, possiblyNotBuiltTest))
return EBuildingState::FORBIDDEN;
if(ID == BuildingID::CAPITOL)
{
const PlayerState *ps = getPlayer(t->tempOwner, false);

View File

@@ -99,6 +99,129 @@ namespace LogicalExpressionDetail
}
};
template <typename ContainedClass>
class SatisfiabilityVisitor;
template <typename ContainedClass>
class FalsifiabilityVisitor;
template <typename ContainedClass>
class PossibilityVisitor : public boost::static_visitor<bool>
{
typedef ExpressionBase<ContainedClass> Base;
protected:
std::function<bool(const typename Base::Value &)> satisfiabilityTest;
std::function<bool(const typename Base::Value &)> falsifiabilityTest;
SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor;
FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor;
size_t countSatisfiable(const std::vector<typename Base::Variant> & element) const
{
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
{
return boost::apply_visitor(*satisfiabilityVisitor, expr);
});
}
size_t countFalsifiable(const std::vector<typename Base::Variant> & element) const
{
return boost::range::count_if(element, [&](const typename Base::Variant & expr)
{
return boost::apply_visitor(*falsifiabilityVisitor, expr);
});
}
public:
PossibilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
satisfiabilityTest(satisfiabilityTest),
falsifiabilityTest(falsifiabilityTest),
satisfiabilityVisitor(nullptr),
falsifiabilityVisitor(nullptr)
{}
void setSatisfiabilityVisitor(SatisfiabilityVisitor<ContainedClass> *satisfiabilityVisitor)
{
this->satisfiabilityVisitor = satisfiabilityVisitor;
}
void setFalsifiabilityVisitor(FalsifiabilityVisitor<ContainedClass> *falsifiabilityVisitor)
{
this->falsifiabilityVisitor = falsifiabilityVisitor;
}
};
/// Visitor to test whether expression's value can be true
template <typename ContainedClass>
class SatisfiabilityVisitor : public PossibilityVisitor<ContainedClass>
{
typedef ExpressionBase<ContainedClass> Base;
public:
SatisfiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest)
{
this->setSatisfiabilityVisitor(this);
}
bool operator()(const typename Base::OperatorAny & element) const
{
return this->countSatisfiable(element.expressions) != 0;
}
bool operator()(const typename Base::OperatorAll & element) const
{
return this->countSatisfiable(element.expressions) == element.expressions.size();
}
bool operator()(const typename Base::OperatorNone & element) const
{
return this->countFalsifiable(element.expressions) == element.expressions.size();
}
bool operator()(const typename Base::Value & element) const
{
return this->satisfiabilityTest(element);
}
};
/// Visitor to test whether expression's value can be false
template <typename ContainedClass>
class FalsifiabilityVisitor : public PossibilityVisitor<ContainedClass>
{
typedef ExpressionBase<ContainedClass> Base;
public:
FalsifiabilityVisitor(std::function<bool (const typename Base::Value &)> satisfiabilityTest,
std::function<bool (const typename Base::Value &)> falsifiabilityTest):
PossibilityVisitor<ContainedClass>(satisfiabilityTest, falsifiabilityTest)
{
this->setFalsifiabilityVisitor(this);
}
bool operator()(const typename Base::OperatorAny & element) const
{
return this->countFalsifiable(element.expressions) == element.expressions.size();
}
bool operator()(const typename Base::OperatorAll & element) const
{
return this->countFalsifiable(element.expressions) != 0;
}
bool operator()(const typename Base::OperatorNone & element) const
{
return this->countSatisfiable(element.expressions) != 0;
}
bool operator()(const typename Base::Value & element) const
{
return this->falsifiabilityTest(element);
}
};
/// visitor that is trying to generates candidates that must be fulfilled
/// to complete this expression
template <typename ContainedClass>
@@ -436,6 +559,30 @@ public:
return boost::apply_visitor(testVisitor, data);
}
/// calculates if expression can evaluate to "true".
bool satisfiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
{
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest, falsifiabilityTest);
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(satisfiabilityTest, falsifiabilityTest);
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
falsifiabilityVisitor.setSatisfiabilityVisitor(&satisfiabilityVisitor);
return boost::apply_visitor(satisfiabilityVisitor, data);
}
/// calculates if expression can evaluate to "false".
bool falsifiable(std::function<bool(const Value &)> satisfiabilityTest, std::function<bool(const Value &)> falsifiabilityTest) const
{
LogicalExpressionDetail::SatisfiabilityVisitor<Value> satisfiabilityVisitor(satisfiabilityTest);
LogicalExpressionDetail::FalsifiabilityVisitor<Value> falsifiabilityVisitor(falsifiabilityTest);
satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
return boost::apply_visitor(falsifiabilityVisitor, data);
}
/// generates list of candidates that can be fulfilled by caller (like AI)
std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
{

View File

@@ -1124,7 +1124,7 @@ bool CGTownInstance::hasBuilt(BuildingID buildingID) const
return vstd::contains(builtBuildings, buildingID);
}
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID) const
CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID, bool deep) const
{
const CBuilding * building = town->buildings.at(buildID);
@@ -1132,17 +1132,22 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(BuildingID buildID)
[&](const BuildingID & id) -> CBuilding::TRequired::Variant
{
const CBuilding * build = town->buildings.at(id);
CBuilding::TRequired::OperatorAll requirements;
if (!hasBuilt(id))
return id;
{
requirements.expressions.push_back(id);
CBuilding::TRequired::OperatorAll requirements;
if (!deep)
{
return requirements;
}
}
if (build->upgrade != BuildingID::NONE)
requirements.expressions.push_back(dependTest(build->upgrade));
requirements.expressions.push_back(build->requirements.morph(dependTest));
return requirements;
};

View File

@@ -238,7 +238,7 @@ public:
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
int getTownLevel() const;
CBuilding::TRequired genBuildingRequirements(BuildingID build) const;
CBuilding::TRequired genBuildingRequirements(BuildingID build, bool deep = false) const;
void mergeGarrisonOnSiege() const; // merge garrison into army of visiting hero
void removeCapitols (PlayerColor owner) const;