Program Listing for File Host.h¶
↰ Return to documentation for file (source/default_mode/Host.h
)
#ifndef HOST_H
#define HOST_H
#include "../../Empirical/include/emp/math/Random.hpp"
#include "../../Empirical/include/emp/tools/string_utils.hpp"
#include <iomanip> // setprecision
#include <sstream> // stringstream
#include <string>
#include "../Organism.h"
#include "SymWorld.h"
class Host: public Organism {
protected:
double interaction_val = 0;
int age = 0;
emp::vector<emp::Ptr<Organism>> syms = {};
emp::vector<emp::Ptr<Organism>> repro_syms = {};
double points = 0;
double res_in_process = 0;
emp::Ptr<emp::Random> random = NULL;
emp::Ptr<SymWorld> my_world = NULL;
emp::Ptr<SymConfigBase> my_config = NULL;
bool dead = false;
public:
Host(emp::Ptr<emp::Random> _random, emp::Ptr<SymWorld> _world, emp::Ptr<SymConfigBase> _config,
double _intval =0.0, emp::vector<emp::Ptr<Organism>> _syms = {},
emp::vector<emp::Ptr<Organism>> _repro_syms = {},
double _points = 0.0) : interaction_val(_intval), syms(_syms), repro_syms(_repro_syms), points(_points), random(_random), my_world(_world), my_config(_config) {
if (_intval == -2) {
interaction_val = random->GetDouble(-1, 1);
}
if (interaction_val > 1 || interaction_val < -1) {
throw "Invalid interaction value. Must be between -1 and 1"; // Exception for invalid interaction value
};
}
~Host(){
for(size_t i=0; i<syms.size(); i++){
syms[i].Delete();
}
for(size_t j=0; j<repro_syms.size(); j++){
repro_syms[j].Delete();
}
}
Host(const Host &) = default;
Host(Host &&) = default;
Host() = default;
Host & operator=(const Host &) = default;
Host & operator=(Host &&) = default;
bool operator==(const Host &other) const { return (this == &other);}
bool operator!=(const Host &other) const {return !(*this == other);}
std::string const GetName() {
return "Host";
}
double GetIntVal() const { return interaction_val;}
emp::vector<emp::Ptr<Organism>>& GetSymbionts() {return syms;}
emp::vector<emp::Ptr<Organism>>& GetReproSymbionts() {return repro_syms;}
double GetPoints() { return points;}
double GetResInProcess() { return res_in_process;}
bool IsHost() { return true; }
void SetIntVal(double _in) {
if ( _in > 1 || _in < -1) {
throw "Invalid interaction value. Must be between -1 and 1"; // Exception for invalid interaction value
}
else {
interaction_val = _in;
}
}
void SetSymbionts(emp::vector<emp::Ptr<Organism>> _in) {
ClearSyms();
for(size_t i = 0; i < _in.size(); i++){
AddSymbiont(_in[i]);
}
}
void SetPoints(double _in) {points = _in;}
void ClearSyms() {syms.resize(0);}
void ClearReproSyms() {repro_syms.resize(0);}
void SetDead() { dead = true;}
void SetResInProcess(double _in) { res_in_process = _in;}
bool GetDead() {return dead;}
int GetAge() {return age;}
void SetAge(int _in) {age = _in;}
void GrowOlder(){
age = age + 1;
if(age > my_config->HOST_AGE_MAX() && my_config->HOST_AGE_MAX() > 0){
SetDead();
}
}
double StealResources(double _intval){
double hostIntVal = GetIntVal();
double res_in_process = GetResInProcess();
//calculate how many resources another organism can steal from this host
if (hostIntVal>0){ //cooperative hosts shouldn't be over punished by StealResources
hostIntVal = 0;
}
if (_intval < hostIntVal){
//organism trying to steal can overcome host's defense
double stolen = (hostIntVal - _intval) * res_in_process;
double remainingResources = res_in_process - stolen;
SetResInProcess(remainingResources);
return stolen;
} else {
//defense cannot be overcome, no resources are stolen
return 0;
}
}
void AddPoints(double _in) {points += _in;}
int AddSymbiont(emp::Ptr<Organism> _in) {
if((int)syms.size() < my_config->SYM_LIMIT() && SymAllowedIn()){
syms.push_back(_in);
_in->SetHost(this);
_in->UponInjection();
return syms.size();
} else {
_in.Delete();
return 0;
}
}
bool SymAllowedIn(){
bool do_phage_exclusion = my_config->PHAGE_EXCLUDE();
if(!do_phage_exclusion){
return true;
}
else{
int num_syms = syms.size();
//essentially imitaties a 1/ 2^n chance, with n = number of symbionts
int enter_chance = random->GetUInt((int) pow(2.0, num_syms));
if(enter_chance == 0) { return true; }
return false;
}
}
void AddReproSym(emp::Ptr<Organism> _in) {repro_syms.push_back(_in);}
bool HasSym() {
return syms.size() != 0;
}
emp::Ptr<Organism> MakeNew(){
emp::Ptr<Host> new_host = emp::NewPtr<Host>(random, my_world, my_config, GetIntVal());
return new_host;
}
emp::Ptr<Organism> Reproduce(){
emp::Ptr<Organism> host_baby = MakeNew();
host_baby->Mutate();
SetPoints(0);
return host_baby;
}
void Mutate(){
double mutation_size = my_config->HOST_MUTATION_SIZE();
if (mutation_size == -1) mutation_size = my_config->MUTATION_SIZE();
double mutation_rate = my_config->HOST_MUTATION_RATE();
if (mutation_rate == -1) mutation_rate = my_config->MUTATION_RATE();
if(random->GetDouble(0.0, 1.0) <= mutation_rate){
interaction_val += random->GetRandNormal(0.0, mutation_size);
if(interaction_val < -1) interaction_val = -1;
else if (interaction_val > 1) interaction_val = 1;
}
}
void DistribResources(double resources) {
double hostIntVal = interaction_val; //using private variable because we can
//do ectosymbiosis if the config setting is on, there is a parallel sym
//In the event that the host has no symbionts, the host gets all resources not allocated to defense or
// given to absent partner.
if(syms.empty()) {
if(hostIntVal >= 0){
double spent = resources * hostIntVal;
this->AddPoints(resources - spent);
}
else {
double hostDefense = -1.0 * hostIntVal * resources;
this->AddPoints(resources - hostDefense);
}
return; //This concludes resource distribution for a host without symbionts
}
size_t num_sym = syms.size();
double sym_piece = (double) resources / num_sym;
for(size_t i=0; i < syms.size(); i++){
DistribResToSym(syms[i], sym_piece);
}
} //end DistribResources
double HandleEctosymbiosis(double resources, size_t location){
double leftover_resources = resources;
if(GetDoEctosymbiosis(location)){
double sym_piece = leftover_resources / (syms.size() + 1); //if there are no endo syms, the ecto sym will handle all the resources
DistribResToSym(my_world->GetSymAt(location), sym_piece);
leftover_resources = leftover_resources - sym_piece; //leave the leftover resources to be split by other syms
}
return leftover_resources;
}
bool GetDoEctosymbiosis(size_t location){
//a host is immune to ectosymbiosis if immunity is on and it has a sym.
if (!my_config->ECTOSYMBIOSIS()) return false; //if the config setting is off, we immediately know that ectosymbiosis won't happen
else{
bool is_immune = my_config->ECTOSYMBIOTIC_IMMUNITY() && HasSym();
bool valid_sym = my_world->GetSymAt(location) != nullptr && !my_world->GetSymAt(location)->GetDead();
return (valid_sym == true) && (is_immune == false);
}
}
void DistribResToSym(emp::Ptr<Organism> sym, double sym_piece){
double hostIntVal = interaction_val;
double hostDonation = 0;
if(hostIntVal < 0){
double hostDefense = hostIntVal * sym_piece * -1.0;
hostDonation = 0;
SetResInProcess(sym_piece - hostDefense);
}
else if(hostIntVal >= 0){
hostDonation = hostIntVal * sym_piece;
SetResInProcess(sym_piece - hostDonation);
}
double sym_return = sym->ProcessResources(hostDonation, this);
this->AddPoints(sym_return + GetResInProcess());
SetResInProcess(0);
}
void Process(emp::WorldPosition pos) {
size_t location = pos.GetIndex();
//Currently just wrapping to use the existing function
double desired_resources = my_config->RES_DISTRIBUTE();
double world_resources = my_world->PullResources(desired_resources); //recieve resources from the world
double resources = HandleEctosymbiosis(world_resources, location);
if(resources > 0) DistribResources(resources); //if there are enough resources left, distribute them.
// Check reproduction
if (GetPoints() >= my_config->HOST_REPRO_RES() && repro_syms.size() == 0) { // if host has more points than required for repro
// will replicate & mutate a random offset from parent values
// while resetting resource points for host and symbiont to zero
emp::Ptr<Organism> host_baby = Reproduce();
//Now check if symbionts get to vertically transmit
for(size_t j = 0; j< (GetSymbionts()).size(); j++){
emp::Ptr<Organism> parent = GetSymbionts()[j];
parent->VerticalTransmission(host_baby);
}
my_world->DoBirth(host_baby, location); //Automatically deals with grid
}
if (GetDead()){
return; //If host is dead, return
}
if (HasSym()) { //let each sym do whatever they need to do
emp::vector<emp::Ptr<Organism>>& syms = GetSymbionts();
for(size_t j = 0; j < syms.size(); j++){
emp::Ptr<Organism> curSym = syms[j];
if (GetDead()){
return; //If previous symbiont killed host, we're done
}
//sym position should have host index as id and
//position in syms list + 1 as index (0 as fls index)
emp::WorldPosition sym_pos = emp::WorldPosition(j+1, location);
if(!curSym->GetDead()){
curSym->Process(sym_pos);
}
if(curSym->GetDead()){
syms.erase(syms.begin() + j); //if the symbiont dies during their process, remove from syms list
curSym.Delete();
}
} //for each sym in syms
} //if org has syms
GrowOlder();
}
};//Host
#endif