Another rework for scripthooks, for better performance.
continuous-integration/drone/push Build is passing Details

This new version caches pointers to the pointers to scripts, so that we can build the data once and then simply iterate over it whenever we want to run a hook.
This commit is contained in:
Deukhoofd 2019-11-10 17:08:42 +01:00
parent e1a8d80863
commit d8332f9e40
19 changed files with 118 additions and 72 deletions

View File

@ -7,12 +7,12 @@
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class ChoiceQueue { class ChoiceQueue {
std::vector<const BaseTurnChoice*> _queue; std::vector<BaseTurnChoice*> _queue;
size_t _current = 0; size_t _current = 0;
public: public:
bool HasCompletedQueue = false; bool HasCompletedQueue = false;
explicit ChoiceQueue(std::vector<const BaseTurnChoice*> queue) explicit ChoiceQueue(std::vector<BaseTurnChoice*> queue)
:_queue(std::move(queue)){} :_queue(std::move(queue)){}
const BaseTurnChoice* Dequeue(){ const BaseTurnChoice* Dequeue(){
@ -25,7 +25,7 @@ namespace CreatureLib::Battling{
return _current < _queue.size(); return _current < _queue.size();
} }
std::vector<const BaseTurnChoice*>& GetInnerQueue(){ std::vector<BaseTurnChoice*>& GetInnerQueue(){
return _queue; return _queue;
} }
}; };

View File

@ -1,8 +1,6 @@
#include "TurnOrdering.hpp" #include "TurnOrdering.hpp"
#include "../TurnChoices/AttackTurnChoice.hpp" #include "../TurnChoices/AttackTurnChoice.hpp"
#include "../Models/Creature.hpp"
#include "../Models/Battle.hpp" #include "../Models/Battle.hpp"
#include "../../Core/Exceptions/NotImplementedException.hpp"
#include <algorithm> #include <algorithm>
@ -15,8 +13,8 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core::
if (aKind != bKind) if (aKind != bKind)
return aKind > bKind; return aKind > bKind;
if (aKind == TurnChoiceKind::Attack){ if (aKind == TurnChoiceKind::Attack){
auto aPriority = static_cast<const AttackTurnChoice*>(a)->GetPriority(); auto aPriority = dynamic_cast<const AttackTurnChoice*>(a)->GetPriority();
auto bPriority = static_cast<const AttackTurnChoice*>(b)->GetPriority(); auto bPriority = dynamic_cast<const AttackTurnChoice*>(b)->GetPriority();
if (aPriority != bPriority) if (aPriority != bPriority)
return aPriority > bPriority; return aPriority > bPriority;
} }
@ -29,7 +27,7 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core::
return randomValue == 0; return randomValue == 0;
} }
void TurnOrdering::OrderChoices(std::vector<const BaseTurnChoice *> &vec, Core::Random& rand) { void TurnOrdering::OrderChoices(std::vector<BaseTurnChoice *> &vec, Core::Random& rand) {
auto comp = [&](const BaseTurnChoice * a,const BaseTurnChoice * b)-> bool { auto comp = [&](const BaseTurnChoice * a,const BaseTurnChoice * b)-> bool {
return ___ChoiceOrderFunc(a,b,rand); return ___ChoiceOrderFunc(a,b,rand);
}; };

View File

@ -8,7 +8,7 @@
namespace CreatureLib::Battling { namespace CreatureLib::Battling {
class TurnOrdering { class TurnOrdering {
public: public:
static void OrderChoices(std::vector<const BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand); static void OrderChoices(std::vector<BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand);
}; };
} }

View File

@ -33,10 +33,10 @@ void Battle::CheckChoicesSetAndRun() {
return; return;
} }
} }
auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide); auto choices = std::vector<BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
auto i = 0; auto i = 0;
for (auto side: _sides){ for (auto side: _sides){
for (const BaseTurnChoice* choice: side->GetChoices()){ for (BaseTurnChoice* choice: side->GetChoices()){
if (choice->GetKind() == TurnChoiceKind::Attack){ if (choice->GetKind() == TurnChoiceKind::Attack){
auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack(); auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack();
uint8_t uses = 1; uint8_t uses = 1;
@ -93,6 +93,6 @@ void Battle::FillRecall(uint8_t side, uint8_t, Creature *c) {
} }
} }
void Battle::GetActiveScripts(ScriptAggregator &aggr) const { void Battle::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
aggr.Add(&_volatile); scripts.emplace_back(&_volatile);
} }

View File

@ -42,7 +42,7 @@ namespace CreatureLib::Battling {
void FillRecall(uint8_t side, uint8_t, Creature* c); void FillRecall(uint8_t side, uint8_t, Creature* c);
void GetActiveScripts(ScriptAggregator &aggr) const override; void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
}; };
} }

View File

@ -16,11 +16,11 @@ void BattleSide::ResetChoices() {
} }
} }
const std::vector<const BaseTurnChoice *>& BattleSide::GetChoices() const{ const std::vector<BaseTurnChoice *>& BattleSide::GetChoices() const{
return _choices; return _choices;
} }
void BattleSide::SetChoice(const BaseTurnChoice *choice) { void BattleSide::SetChoice(BaseTurnChoice *choice) {
auto find = std::find(_creatures.begin(), _creatures.end(), choice->GetUser()); auto find = std::find(_creatures.begin(), _creatures.end(), choice->GetUser());
if (find ==_creatures.end()) if (find ==_creatures.end())
throw CreatureException("User not found"); throw CreatureException("User not found");
@ -41,7 +41,7 @@ Creature *BattleSide::GetCreature(uint8_t index) const {
return _creatures[index]; return _creatures[index];
} }
void BattleSide::GetActiveScripts(ScriptAggregator &aggr) const { void BattleSide::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
aggr.Add(&_volatile); scripts.emplace_back(&_volatile);
_battle->GetActiveScripts(aggr); _battle->GetActiveScripts(scripts);
} }

View File

@ -9,7 +9,7 @@ namespace CreatureLib::Battling{
class BattleSide : public ScriptSource{ class BattleSide : public ScriptSource{
uint8_t _creaturesPerSide; uint8_t _creaturesPerSide;
std::vector<Creature*> _creatures; std::vector<Creature*> _creatures;
std::vector<const BaseTurnChoice*> _choices; std::vector<BaseTurnChoice*> _choices;
uint8_t _choicesSet = 0; uint8_t _choicesSet = 0;
ScriptSet _volatile; ScriptSet _volatile;
Battle* _battle; Battle* _battle;
@ -21,9 +21,9 @@ namespace CreatureLib::Battling{
} }
[[nodiscard]] bool AllChoicesSet() const; [[nodiscard]] bool AllChoicesSet() const;
[[nodiscard]] const std::vector<const BaseTurnChoice*>& GetChoices() const; [[nodiscard]] const std::vector<BaseTurnChoice*>& GetChoices() const;
void SetChoice(const BaseTurnChoice* choice); void SetChoice(BaseTurnChoice* choice);
void ResetChoices(); void ResetChoices();
void SetCreature(Creature* creature, uint8_t index); void SetCreature(Creature* creature, uint8_t index);
@ -31,7 +31,7 @@ namespace CreatureLib::Battling{
Creature* GetCreature(uint8_t index) const; Creature* GetCreature(uint8_t index) const;
bool CreatureOnSide(const Creature* creature) const; bool CreatureOnSide(const Creature* creature) const;
void GetActiveScripts(ScriptAggregator &aggr) const override; void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <algorithm> #include <algorithm>
#include <utility>
#include "Creature.hpp" #include "Creature.hpp"
#include "../Models/Battle.hpp" #include "../Models/Battle.hpp"
@ -20,9 +21,9 @@ Battling::Creature::Creature(const Library::CreatureSpecies* species, const Libr
__Gender(gender), __Gender(gender),
__Coloring(coloring), __Coloring(coloring),
__HeldItem(heldItem), __HeldItem(heldItem),
_nickname(nickname), _nickname(std::move(nickname)),
_talentIndex(talent), _talentIndex(talent),
_attacks(attacks) _attacks(std::move(attacks))
{} {}
@ -140,8 +141,8 @@ bool Battling::Creature::HasType(uint8_t type) const {
return std::find(t.begin(), t.end(), type) != t.end(); return std::find(t.begin(), t.end(), type) != t.end();
} }
void Battling::Creature::GetActiveScripts(Battling::ScriptAggregator &aggr) const { void Battling::Creature::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
aggr.Add(_status); scripts.emplace_back(&_status);
aggr.Add(&_volatile); scripts.emplace_back(&_volatile);
_side->GetActiveScripts(aggr); _side->GetActiveScripts(scripts);
} }

View File

@ -18,7 +18,8 @@ namespace CreatureLib::Battling{
class Creature : public ScriptSource{ class Creature : public ScriptSource{
GetProperty(const Library::CreatureSpecies*, Species); GetProperty(const Library::CreatureSpecies*, Species);
GetProperty(const Library::SpeciesVariant*, Variant); GetProperty(const Library::SpeciesVariant*, Variant)
GetProperty(uint8_t, Level); GetProperty(uint8_t, Level);
GetProperty(uint32_t, Experience); GetProperty(uint32_t, Experience);
GetProperty(Core::StatisticSet<uint8_t >, StatExperience); GetProperty(Core::StatisticSet<uint8_t >, StatExperience);
@ -67,7 +68,7 @@ namespace CreatureLib::Battling{
[[nodiscard]] const std::vector<uint8_t>& GetTypes() const; [[nodiscard]] const std::vector<uint8_t>& GetTypes() const;
[[nodiscard]] bool HasType(uint8_t type) const; [[nodiscard]] bool HasType(uint8_t type) const;
void GetActiveScripts(ScriptAggregator& aggr) const override; void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
//region Stat APIs //region Stat APIs
@ -85,6 +86,7 @@ namespace CreatureLib::Battling{
void RecalculateBoostedStats(); void RecalculateBoostedStats();
void RecalculateFlatStat(Core::Statistic); void RecalculateFlatStat(Core::Statistic);
void RecalculateBoostedStat(Core::Statistic); void RecalculateBoostedStat(Core::Statistic);
//endregion //endregion

View File

@ -89,8 +89,10 @@ namespace CreatureLib::Battling {
return _attack; return _attack;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override { protected:
aggr.Add(_script); void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
scripts.emplace_back(&_script);
GetUser()->GetActiveScripts(scripts);
} }
}; };
} }

View File

@ -6,26 +6,23 @@
#include "Script.hpp" #include "Script.hpp"
#include "ScriptSet.hpp" #include "ScriptSet.hpp"
#include "../../Core/Exceptions/NotReachableException.hpp" #include "../../Core/Exceptions/NotReachableException.hpp"
#include "ScriptWrapper.hpp"
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class ScriptAggregator{ class ScriptAggregator{
std::queue<std::any> _queue; __gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfIterator;
__gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfEnd;
bool _isSetSet = false; bool _isSetSet = false;
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setIterator; std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setIterator;
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setEnd; std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setEnd;
public: public:
ScriptAggregator() = default; ScriptAggregator(std::vector<ScriptWrapper> scripts){
_selfIterator = scripts.begin();
void Add(Script* script){ _selfEnd = scripts.end();
_queue.push(script); };
}
void Add(const ScriptSet* scriptSet){
_queue.push(scriptSet);
}
bool HasNext(){ bool HasNext(){
return !_queue.empty() || _isSetSet; return _selfIterator != _selfEnd || _isSetSet;
} }
Script* GetNext(){ Script* GetNext(){
@ -42,15 +39,17 @@ namespace CreatureLib::Battling{
} }
return s; return s;
} }
if (_queue.empty()) if (_selfIterator == _selfEnd)
return nullptr; return nullptr;
auto next = _queue.front(); auto next = *_selfIterator;
_queue.pop(); if (!next.IsSet()){
if (next.type() == typeid(Script*)){ auto scriptPtr = next.GetScript();
return std::any_cast<Script*>(next); if (scriptPtr == nullptr)
return GetNext();
return *scriptPtr;
} }
else{ else{
auto set = std::any_cast<const ScriptSet*>(next); auto set = next.GetScriptSet();
if (set->Count() == 0) if (set->Count() == 0)
return GetNext(); return GetNext();
auto it = set->GetIterator(); auto it = set->GetIterator();

View File

@ -1,7 +1,6 @@
#define HOOK(hookName, source, ... ) \ #define HOOK(hookName, source, ... ) \
{ \ { \
auto aggregator = CreatureLib::Battling::ScriptAggregator(); \ auto aggregator = source -> GetScriptIterator(); \
source -> GetActiveScripts(aggregator); \
while (aggregator.HasNext()){ \ while (aggregator.HasNext()){ \
auto next = aggregator.GetNext(); \ auto next = aggregator.GetNext(); \
if (next == nullptr) continue; \ if (next == nullptr) continue; \

View File

@ -7,8 +7,18 @@
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class ScriptSource { class ScriptSource {
bool _areScriptsInitialized = false;
std::vector<ScriptWrapper> _scripts;
protected:
virtual void GetActiveScripts(std::vector<ScriptWrapper>& scripts) = 0;
public: public:
virtual void GetActiveScripts(ScriptAggregator& aggr) const = 0; ScriptAggregator GetScriptIterator(){
if (!_areScriptsInitialized){
GetActiveScripts(_scripts);
_areScriptsInitialized = true;
}
return ScriptAggregator(_scripts);
}
}; };
} }

View File

@ -0,0 +1,3 @@
#include "ScriptWrapper.hpp"

View File

@ -0,0 +1,33 @@
#ifndef CREATURELIB_SCRIPTWRAPPER_HPP
#define CREATURELIB_SCRIPTWRAPPER_HPP
#include <variant>
#include "Script.hpp"
#include "ScriptSet.hpp"
namespace CreatureLib::Battling{
class ScriptWrapper {
std::variant<Script**, ScriptSet*> _value;
bool _isSet;
public:
ScriptWrapper(Script** s) : _value(s), _isSet(false){}
ScriptWrapper(ScriptSet* s) : _value(s), _isSet(true){}
bool IsSet() const{
return _isSet;
}
Script** GetScript() const{
return std::get<Script**>(_value);
}
ScriptSet* GetScriptSet() const{
return std::get<ScriptSet*>(_value);
}
};
}
#endif //CREATURELIB_SCRIPTWRAPPER_HPP

View File

@ -31,10 +31,12 @@ namespace CreatureLib::Battling{
return _target; return _target;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override { protected:
aggr.Add(_attackScript); void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
GetUser()->GetActiveScripts(aggr); scripts.emplace_back(&_attackScript);
GetUser()->GetActiveScripts(scripts);
} }
}; };
} }

View File

@ -17,10 +17,6 @@ namespace CreatureLib::Battling{
[[nodiscard]] inline Creature* GetUser() const{ [[nodiscard]] inline Creature* GetUser() const{
return _user; return _user;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override {
}
}; };
} }

View File

@ -12,8 +12,9 @@ namespace CreatureLib::Battling {
return TurnChoiceKind ::Pass; return TurnChoiceKind ::Pass;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override { protected:
GetUser()->GetActiveScripts(aggr); void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
GetUser()->GetActiveScripts(scripts);
} }
}; };
} }

View File

@ -11,12 +11,12 @@ using namespace CreatureLib::Battling;
TEST_CASE( "Turn ordering: Attack before pass", "[Battling]" ) { TEST_CASE( "Turn ordering: Attack before pass", "[Battling]" ) {
auto choice1 = new PassTurnChoice(nullptr); auto choice1 = new PassTurnChoice(nullptr);
auto choice2 = new AttackTurnChoice(nullptr, nullptr, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, nullptr, Target(0,0));
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
auto rand = Core::Random(); auto rand = Core::Random();
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
vec = std::vector<const BaseTurnChoice*>{choice2, choice1}; vec = std::vector<BaseTurnChoice*>{choice2, choice1};
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
@ -31,12 +31,12 @@ TEST_CASE( "Turn ordering: High priority goes before no priority", "[Battling]"
auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
auto rand = Core::Random(); auto rand = Core::Random();
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
vec = std::vector<const BaseTurnChoice*>{choice2, choice1}; vec = std::vector<BaseTurnChoice*>{choice2, choice1};
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
@ -53,12 +53,12 @@ TEST_CASE( "Turn ordering: Higher priority goes before high priority", "[Battlin
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
auto rand = Core::Random(); auto rand = Core::Random();
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
vec = std::vector<const BaseTurnChoice*>{choice2, choice1}; vec = std::vector<BaseTurnChoice*>{choice2, choice1};
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
@ -75,12 +75,12 @@ TEST_CASE( "Turn ordering: High priority goes before low priority", "[Battling]"
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
auto rand = Core::Random(); auto rand = Core::Random();
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
vec = std::vector<const BaseTurnChoice*>{choice2, choice1}; vec = std::vector<BaseTurnChoice*>{choice2, choice1};
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
@ -97,12 +97,12 @@ TEST_CASE( "Turn ordering: No priority goes before low priority", "[Battling]" )
auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
auto rand = Core::Random(); auto rand = Core::Random();
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);
vec = std::vector<const BaseTurnChoice*>{choice2, choice1}; vec = std::vector<BaseTurnChoice*>{choice2, choice1};
TurnOrdering::OrderChoices(vec,rand); TurnOrdering::OrderChoices(vec,rand);
CHECK(vec[0] == choice2); CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1); CHECK(vec[1] == choice1);