// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2023 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include "geneprops.h" #include GeneProps GeneProps::standard_values; GeneProps::GeneProps() { Part_MinMaxDef default_part = Model::getDefPart(); Joint default_joint = Model::getDefJoint(); length = 1.0; weight = 1.0; friction = default_part.friction; curvedness = 0.0; twist = 0.0; energy = 1.0; // before 2023-05, the four fields below were aggregated and normalized using normalizeBiol4(), but this normalization only worked for f1 and f4 - other genetic encodings do not perform such normalization. If at all, this should be handled by the expdef depending on the goal of the experiment (e.g., to encourage specialization). muscle_power = 0.25; // "biological" property, same as findNeuroClass("BendMuscle or RotMuscle")->paraminterface->getDoubleById("power") assimilation = default_part.assim; // "biological" property stamina = default_joint.stamina; // "biological" property ingestion = default_part.ingest; // "biological" property muscle_bend_range = 1.0; // same as findNeuroClass("BendMuscle")->paraminterface->getDoubleById("range") muscle_reset_range = true; cred = default_part.vcolor.x; cgreen = default_part.vcolor.y; cblue = default_part.vcolor.z; } void GeneProps::normalizeBiol4() { // make them sum to 1 double sum = muscle_power + assimilation + stamina + ingestion; if (sum == 0) { muscle_power = assimilation = stamina = ingestion = 0.25; } else { muscle_power /= sum; assimilation /= sum; stamina /= sum; ingestion /= sum; } } int GeneProps::executeModifier_Legacy(char modif) { switch (modif) { #ifdef v1f1COMPATIBLE case 'L': length += (3.0 - length) * 0.3; length = std::min(length, Model::getMaxJoint().d.x); break; #else case 'L': length += (2.0 - length) * 0.3; //2.0 is currently Model::getMaxJoint().d.x so min() does not limit the range length = std::min(length, Model::getMaxJoint().d.x); break; #endif case 'l': length += (0.33 - length) * 0.3; length = std::max(length, Model::getMinJoint().d.x); break; case 'W': weight += (2.0 - weight) * 0.3; break; case 'w': weight += (0.5 - weight) * 0.3; break; case 'F': friction += (4 - friction) * 0.2; break; case 'f': friction -= friction * 0.2; break; case 'C': curvedness += (2.0 - curvedness) * 0.25; break; case 'c': curvedness += (-2.0 - curvedness) * 0.25; break; case 'Q': twist += (M_PI_2 - twist) * 0.3; break; case 'q': twist += (-M_PI_2 - twist) * 0.3; break; case 'E': energy += (10.0 - energy) * 0.1; break; case 'e': energy -= energy * 0.1; break; case 'A': assimilation += (1 - assimilation) * 0.8; normalizeBiol4(); break; case 'a': assimilation -= assimilation * 0.4; normalizeBiol4(); break; case 'I': ingestion += (1 - ingestion) * 0.8; normalizeBiol4(); break; case 'i': ingestion -= ingestion * 0.4; normalizeBiol4(); break; case 'S': stamina += (1 - stamina) * 0.8; normalizeBiol4(); break; case 's': stamina -= stamina * 0.4; normalizeBiol4(); break; case 'M': muscle_power += (1 - muscle_power) * 0.8; normalizeBiol4(); break; case 'm': muscle_power -= muscle_power * 0.4; normalizeBiol4(); break; case 'D': cred += (1.0 - cred) * 0.25; break; case 'd': cred += (0.0 - cred) * 0.25; break; case 'G': cgreen += (1.0 - cgreen) * 0.25; break; case 'g': cgreen += (0.0 - cgreen) * 0.25; break; case 'B': cblue += (1.0 - cblue) * 0.25; break; case 'b': cblue += (0.0 - cblue) * 0.25; break; default: return -1; } return 0; } int GeneProps::executeModifier(char modif, GenePropsOps* ops) { if (ops == NULL) ops = getStandardOps(); #define APPLY(name) ops->name->apply(name, modif) #define APPLY_AND_MAYBE_NORMALIZEBIOL4(name) {APPLY(name); if (ops->use_normalizebiol4) normalizeBiol4();} switch (toupper(modif)) { case 'L': APPLY(length); length = std::min(length, Model::getMaxJoint().d.x); break; break; case 'l': APPLY(length); length = std::max(length, Model::getMinJoint().d.x); break; break; case 'W': APPLY(weight); break; case 'F': APPLY(friction); break; case 'C': APPLY(curvedness); break; case 'Q': APPLY(twist); break; case 'E': APPLY(energy); break; case 'A': APPLY_AND_MAYBE_NORMALIZEBIOL4(assimilation); break; case 'I': APPLY_AND_MAYBE_NORMALIZEBIOL4(ingestion); break; case 'S': APPLY_AND_MAYBE_NORMALIZEBIOL4(stamina); break; case 'M': APPLY_AND_MAYBE_NORMALIZEBIOL4(muscle_power); break; case 'D': APPLY(cred); break; case 'G': APPLY(cgreen); break; case 'B': APPLY(cblue); break; default: return -1; } return 0; #undef APPLY #undef APPLY_AND_MAYBE_NORMALIZEBIOL4 } void GeneProps::propagateAlong(bool use_f1_muscle_reset_range, GenePropsOps* ops) { length = 0.5 * length + 0.5 * standard_values.length; weight += (standard_values.weight - weight) * 0.5; friction = 0.8 * friction + 0.2 * standard_values.friction; curvedness = 0.66 * curvedness; twist = 0.66 * twist; assimilation = 0.8 * assimilation + 0.2 * standard_values.assimilation; ingestion = 0.8 * ingestion + 0.2 * standard_values.ingestion; stamina = 0.8 * stamina + 0.2 * standard_values.stamina; muscle_power = 0.8 * muscle_power + 0.2 * standard_values.muscle_power; if (ops == NULL) ops = getStandardOps(); if (ops->use_normalizebiol4) normalizeBiol4(); if (use_f1_muscle_reset_range) { if (muscle_reset_range) muscle_bend_range = 1.0; else muscle_reset_range = true; } } //////////////////////////////////////////////////// void GenePropsOp::apply(double &value, char modif) const { if (isupper(modif)) value = increase(value); else value = decrease(value); } double GenePropsOp_Old::increase(double value) const { return value + (maxvalue - value) * change; } double GenePropsOp_Old::decrease(double value) const { return value + (minvalue - value) * revchange; } GenePropsOp_Old::GenePropsOp_Old(double minvalue, double maxvalue, double defvalue, double change, double revchange) { this->minvalue = minvalue; this->maxvalue = maxvalue; this->defvalue = defvalue; this->change = change; this->revchange = (revchange < 0) ? change : revchange; } GenePropsOp_Exponential::GenePropsOp_Exponential(double minvalue, double maxvalue, double defvalue, double change) :GenePropsOp_NormalizedAndScaled(change) { double mid = (maxvalue + minvalue) / 2; if (fabs(mid - defvalue) < 0.01) { linear = true; a = (maxvalue - minvalue) / 2; b = defvalue; } else { linear = false; a = -(maxvalue - defvalue) / (minvalue - defvalue); b = (minvalue * minvalue - 2 * defvalue * minvalue + defvalue * defvalue) / (minvalue + maxvalue - 2 * defvalue); c = (maxvalue * minvalue - defvalue * defvalue) / (minvalue + maxvalue - 2 * defvalue); log_a = log(a); } } double GenePropsOp_Exponential::scale(double value) const { if (linear) return a * value + b; else return pow(a, (value + 1)) * b + c; } double GenePropsOp_Exponential::scaleInv(double value) const { if (linear) return (value - b) / a; else return -(log_a - log(value / b - c / b)) / log_a; } //////////////////////////////////////////////////////////////////// GenePropsOps::~GenePropsOps() { delete length; delete curvedness; delete weight; delete friction; delete muscle_power; delete assimilation; delete stamina; delete ingestion; delete twist; delete energy; delete cred; delete cgreen; delete cblue; } GenePropsOps_Old::GenePropsOps_Old() { use_normalizebiol4 = true; length = new GenePropsOp_Old(0.33, 2.0, GeneProps::standard_values.length, 0.3); weight = new GenePropsOp_Old(0.5, 2.0, GeneProps::standard_values.weight, 0.3); friction = new GenePropsOp_Old(0, 4.0, GeneProps::standard_values.friction, 0.2); curvedness = new GenePropsOp_Old(-2, 2, GeneProps::standard_values.curvedness, 0.25); twist = new GenePropsOp_Old(-M_PI_2, M_PI_2, GeneProps::standard_values.twist, 0.3); energy = new GenePropsOp_Old(0, 10, GeneProps::standard_values.energy, 0.1); assimilation = new GenePropsOp_Old(0, 1, GeneProps::standard_values.assimilation, 0.8, 0.4); ingestion = new GenePropsOp_Old(0, 1, GeneProps::standard_values.ingestion, 0.8, 0.4); stamina = new GenePropsOp_Old(0, 1, GeneProps::standard_values.stamina, 0.8, 0.4); muscle_power = new GenePropsOp_Old(0, 1, GeneProps::standard_values.muscle_power, 0.8, 0.4); cred = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cred, 0.25); cgreen = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cgreen, 0.25); cblue = new GenePropsOp_Old(0, 1, GeneProps::standard_values.cblue, 0.25); } GenePropsOps_New05::GenePropsOps_New05() { use_normalizebiol4 = false; auto fields = { length,curvedness,weight,friction,muscle_power,assimilation,stamina,ingestion,twist,energy,cred,cgreen,cblue }; for (auto f : fields) { auto f_gpo = dynamic_cast(f); if (f_gpo) f_gpo->change = f_gpo->revchange = 0.5; } } GenePropsOps_Exponential::GenePropsOps_Exponential() { length = new GenePropsOp_Exponential(0.33, 2.0, GeneProps::standard_values.length); weight = new GenePropsOp_Exponential(0.5, 2.0, GeneProps::standard_values.weight); friction = new GenePropsOp_Exponential(0, 4.0, GeneProps::standard_values.friction); curvedness = new GenePropsOp_Exponential(-2, 2, GeneProps::standard_values.curvedness); twist = new GenePropsOp_Exponential(-M_PI_2, M_PI_2, GeneProps::standard_values.twist); energy = new GenePropsOp_Exponential(0, 10, GeneProps::standard_values.energy); assimilation = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.assimilation); ingestion = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.ingestion); stamina = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.stamina); muscle_power = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.muscle_power); cred = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cred); cgreen = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cgreen); cblue = new GenePropsOp_Exponential(0, 1, GeneProps::standard_values.cblue); } GenePropsOps* GeneProps::standard_ops = NULL; GenePropsOps* GeneProps::getStandardOps() { if (!standard_ops) standard_ops = new GenePropsOps_New05(); return standard_ops; }