52 lines
2.8 KiB
Python
52 lines
2.8 KiB
Python
"""Execute role resolution: reserve explicit choices, then sample without replacement."""
|
|
import re
|
|
from policy_harness import ROOT, body, run
|
|
path = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_FactionSelection.c'
|
|
code = '\n'.join(body(path, signature) for signature in ['static bool Resolve(', 'static bool Distinct('])
|
|
code = code.replace('array<string> available', 'Array<string> available').replace('array<string> fixed', 'Array<string> fixed')
|
|
code = code.replace('map<string, string>', 'Map&').replace('foreach (', 'for (').replace('Math.RandomInt', 'RandomInt')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <algorithm>
|
|
using string=std::string;
|
|
template<class T> struct Array:std::vector<T> {
|
|
using std::vector<T>::vector;
|
|
int Count()const{return this->size();} bool IsEmpty(){return this->empty();}
|
|
bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}
|
|
void Insert(T v){this->push_back(v);} void Remove(int i){this->erase(this->begin()+i);}
|
|
void RemoveItem(T v){auto i=std::find(this->begin(),this->end(),v);if(i!=this->end())this->erase(i);}
|
|
};
|
|
struct Map:std::map<string,string>{bool Contains(string k){return count(k);}string Get(string k){return at(k);}void Set(string k,string v){(*this)[k]=v;}void Clear(){clear();}};
|
|
struct Rules {
|
|
static Array<string> Roles(){return {"escapists","enemy","independent"};}
|
|
static bool Find(string id){return id=="us"||id=="ussr"||id=="fia"||id=="rhs";}
|
|
static int RandomInt(int,int end){static unsigned x=17;x=x*1664525u+1013904223u;return x%end;}
|
|
''' + code + r'''
|
|
};
|
|
int main(){
|
|
Map saved,resolved;
|
|
for(auto role:Rules::Roles())saved.Set(role,"random");
|
|
for(int n=0;n<1000;n++){
|
|
assert(Rules::Resolve({"us","ussr","fia","rhs"},saved,resolved));
|
|
assert(Rules::Distinct(resolved)&&resolved.size()==3);
|
|
for(auto role:Rules::Roles())assert(saved.Get(role)=="random");
|
|
}
|
|
saved.Set("enemy","us");saved.Set("independent","fia");
|
|
for(int n=0;n<100;n++){
|
|
assert(Rules::Resolve({"us","ussr","fia"},saved,resolved));
|
|
assert(resolved.Get("escapists")=="ussr"&&resolved.Get("enemy")=="us"&&resolved.Get("independent")=="fia");
|
|
}
|
|
saved.Set("enemy","rhs");
|
|
assert(Rules::Resolve({"us","ussr","fia"},saved,resolved));
|
|
assert(resolved.Get("enemy")!="rhs"&&resolved.Get("independent")=="fia");
|
|
saved.Set("enemy","fia");assert(!Rules::Resolve({"us","ussr","fia"},saved,resolved));assert(resolved.empty());
|
|
saved.Set("enemy","unknown");assert(!Rules::Resolve({"us","ussr","fia"},saved,resolved));
|
|
saved.Set("enemy","us");assert(!Rules::Resolve({"us","fia"},saved,resolved));
|
|
saved.erase("escapists");assert(!Rules::Resolve({"us","ussr","fia"},saved,resolved));
|
|
}
|
|
''')
|
|
print('PASS: actual faction resolution reserves explicit roles, samples without replacement, substitutes disabled selections, and rejects duplicate/unknown/missing choices and insufficient pools')
|