Ignore:
Timestamp:
07/11/24 17:15:51 (4 months ago)
Author:
Maciej Komosinski
Message:

Color mutations in f1 and f4, and a new syntax for "allowed modifiers" (opposite to previous "excluded modifiers") with optional probabilities for each modifier

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/genetics/genooperators.cpp

    r1287 r1313  
    11// This file is a part of Framsticks SDK.  http://www.framsticks.com/
    2 // Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
     2// Copyright (C) 1999-2024  Maciej Komosinski and Szymon Ulatowski.
    33// See LICENSE.txt for details.
    44
     
    5656        for (sum = 0, i = 0; i < count; i++) { sum += probtab[i]; if (sel < sum) return i; }
    5757        return -1;
     58}
     59
     60int GenoOperators::roulette(const vector<double> &probtab)
     61{
     62        return roulette(probtab.data(), (int)probtab.size());
    5863}
    5964
     
    461466}
    462467
    463 char *GenoOperators::strchrn0(const char *str, char ch)
     468char *GenoOperators::strchr_no0(const char *str, char ch)
    464469{
    465470        return ch == 0 ? NULL : strchr((char *)str, ch);
    466471}
    467472
    468 int GenoOperators::getRandomChar(const char *choices, const char *excluded)
    469 {
    470         int allowed_count = 0;
    471         for (size_t i = 0; i < strlen(choices); i++) if (!strchrn0(excluded, choices[i])) allowed_count++;
    472         if (allowed_count == 0) return -1; //no char is allowed
    473         int rnd_index = rndUint(allowed_count) + 1;
    474         allowed_count = 0;
    475         for (size_t i = 0; i < strlen(choices); i++)
    476         {
    477                 if (!strchrn0(excluded, choices[i])) allowed_count++;
    478                 if (allowed_count == rnd_index) return int(i);
    479         }
    480         return -1; //never happens
     473double GenoOperators::probOfModifier(const char* mod_def)
     474{
     475        if (*(mod_def + 1) == '(') //the special syntax with the appended probability value in (...)
     476                return std::atof(mod_def + 2); //0.0 when no valid number
     477        return 1.0;
     478}
     479
     480char GenoOperators::getRandomModifier(const char *choices)
     481{
     482        static const char* EXTRA_CHARS = "().0123456789";
     483        // this function assumes that EXTRA_CHARS are only used for the special probabilities syntax in "choices", not as valid choice characters.
     484        vector<char> allowed; //this could be determined only once for a given "choices", as long as the effect of "choices" is deterministic (i.e., "choices" does not include probabilities)
     485        size_t choices_len = strlen(choices);
     486        allowed.reserve(choices_len); //max size, avoid reallocations later
     487        for (size_t i = 0; i < choices_len; i++)
     488        {
     489                if (strchr(EXTRA_CHARS, choices[i])) continue; //skip parentheses and numbers
     490                double prob = probOfModifier(&choices[i]);
     491                if (prob == 1.0 || rndDouble(1) < prob)
     492                        allowed.push_back(choices[i]);
     493        }
     494        if (allowed.size() == 0) return 0; //no char is allowed
     495        return allowed[rndUint(allowed.size())];
     496}
     497
     498char GenoOperators::getRandomColorModifier(const char *choices, const char *color_modifiers)
     499{
     500        vector<char> allowed_colors;
     501        vector<double> allowed_probs;
     502        size_t colors_len = strlen(color_modifiers);
     503        allowed_colors.reserve(colors_len); //max size, avoid reallocations later
     504        allowed_probs.reserve(colors_len); //max size, avoid reallocations later
     505        for (size_t i = 0; i < colors_len; i++) //for all known color modifiers...
     506        {
     507                const char *pos = strchr(choices, color_modifiers[i]); //...search in "choices" - i.e., in currently set active modifiers. Note that "choices" may use an extended syntax with numbers and parentheses, such as qM(0.1)Dm(0.1)dG(0.2)C
     508                if (pos) //found the color modifier in choices
     509                {
     510                        allowed_colors.push_back(*pos);
     511                        allowed_probs.push_back(probOfModifier(pos));
     512                }
     513        }
     514        // the above "parsing" part could be done only once "choices" changes, not every time we want to get a random color modifier...
     515        int idx = roulette(allowed_probs);
     516        return idx < 0 ? 0 : allowed_colors[idx];
    481517}
    482518
     
    544580}
    545581
    546 string GenoOperators::simplifiedModifiers(const string & original)
     582string GenoOperators::simplifiedModifiers(const string & original, const char* colorgenes)
    547583{
    548584        const int MAX_NUMBER_SAME_TYPE = 5; // max. number of modifiers of each type (case-insensitive). The more characters, the closer we can get to min and max values of a given property at the expense of the length of evolved genotypes. 5 is "close enough", but how close we get to the extreme also depends on the initial value of a given property, which is not always exactly in the middle of min and max. rR is treated separately in simplification because their influence follows different (i.e., simple additive) logic - so the simplifiedModifiersFixedOrder() logic with cancelling out antagonistic modifiers would be appropriate for rR.
     585        const int MAX_NUMBER_SAME_TYPE_COLOR = 1; //color does not affect fitness and is used purely for aesthetics, so allow at most 1 char for each r,g,b channel - we get very low resolution of colors (only 3*3*3 combinations), but we spare the genotype length and limit bloat
    549586        int counter[256] = {}; //initialize with zeros; 256 is unnecessarily too big and redundant, but enables very fast access (indexed directly by the ascii code)
    550587        string simplified = "";
     
    556593                unsigned char lower = std::tolower(c);
    557594                counter[lower]++;
    558                 if (counter[lower] <= MAX_NUMBER_SAME_TYPE) //get rid of modifiers that are too numerous, but get rid of the first ones in the string (="oldest", the last ones looking from the end), because their influence on the parameter value is the smallest
     595                int MAX_NUMBER = strchr(colorgenes, c) != NULL ? MAX_NUMBER_SAME_TYPE_COLOR : MAX_NUMBER_SAME_TYPE;
     596                if (counter[lower] <= MAX_NUMBER) //get rid of modifiers that are too numerous - get rid of the first ones in the string (="oldest", the last ones looking from the end), because their influence on the parameter value is the smallest
    559597                        simplified += c;
    560598        }
Note: See TracChangeset for help on using the changeset viewer.