Files
EscapistsReintroduced/tests/test_faction_selection.py
T
jakub 1b1a8b5173 Add mission customization, HQ support and aggression-driven AI
Integrate faction and random settings menus, generated objectives, scouts, convoys, air support, mortar stations and body-intel recovery. Add identified-body aggression, finite hunter UAZ deployment, dedicated objective defence and maximum AI skill with separate reduced aim accuracy. Include policy tests, native probes, evidence and documentation.
2026-09-23 15:07:14 +02:00

51 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);
}
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')