Index: cpp/frams/genetics/fB/fB_oper.cpp
===================================================================
--- cpp/frams/genetics/fB/fB_oper.cpp	(revision 1130)
+++ cpp/frams/genetics/fB/fB_oper.cpp	(revision 1273)
@@ -1,5 +1,10 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
+
+//TODO parsing quotes/neurons seems too relaxed, for example the genotype aag"S""acalaaaafbc is considered valid
+//TODO Same with numbers: "----1.23" is valid
+//TODO reconsider: Horizontal gene transfer - copying a single random gene from each parent to the beginning of the other parent: should the gene be copied (seems to cause bloat!) or rather moved?
+//Neurons ("N") can grow even without using quotes and providing neuron classname in the genotype, for example aaaaabbccvaaapdgfddaalaandwddbaajt (this works likely as designed, but investigate and reconsider); also valid neuron definitions inside the genotype are sometimes not expressed
 
 #include <frams/util/sstring.h>
@@ -19,12 +24,12 @@
 	{ "Genetics: fB: Mutation", },
 	{ "Genetics: fB: Crossover", },
-	{ "fB_mut_substitution", 1, 0, "Substitution", "f 0 1 0.6", FIELD(mutationprobs[FB_SUBSTITUTION]), "Probability of mutation by changing single random letter in genotype", },
-	{ "fB_mut_insertion", 1, 0, "Insertion", "f 0 1 0.095", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", },
-	{ "fB_mut_nclassins", 1, 0, "Insertion of neuron class definition", "f 0 1 0.005", FIELD(mutationprobs[FB_NCLASSINS]), "Probability of mutation by inserting neuron class definition in random place of genotype", },
-	{ "fB_mut_deletion", 1, 0, "Deletion", "f 0 1 0.1", FIELD(mutationprobs[FB_DELETION]), "Probability of mutation by deleting random characters in genotype", },
-	{ "fB_mut_duplication", 1, 0, "Duplication", "f 0 1 0.0", FIELD(mutationprobs[FB_DUPLICATION]), "Probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype", },
-	{ "fB_mut_translocation", 1, 0, "Translocation", "f 0 1 0.15", FIELD(mutationprobs[FB_TRANSLOCATION]), "Probability of mutation by replacing two substrings in genotype", },
-	{ "fB_cross_gene_transfer", 2, 0, "Horizontal gene transfer", "f 0 1 0.0", FIELD(crossoverprobs[FB_GENE_TRANSFER]), "Probability of crossing over by transferring single genes from both parents to beginning of each other", },
-	{ "fB_cross_crossover", 2, 0, "Crossing over", "f 0 1 1.0", FIELD(crossoverprobs[FB_CROSSING_OVER]), "Probability of crossing over by random distribution of genes from both parents to both children", },
+	{ "fB_mut_substitute", 1, 0, "Substitution", "f 0 100 1", FIELD(mutationprobs[FB_SUBSTITUTION]), "Relative probability of changing a single random character (or a neuron) in the genotype", },
+	{ "fB_mut_insert", 1, 0, "Insertion", "f 0 100 3", FIELD(mutationprobs[FB_INSERTION]), "Relative probability of inserting a random character in a random place of the genotype", },
+	{ "fB_mut_insert_neuron", 1, 0, "Insertion of a neuron", "f 0 100 3", FIELD(mutationprobs[FB_INSERTION_NEURON]), "Relative probability of inserting a neuron in a random place of genotype", },
+	{ "fB_mut_delete", 1, 0, "Deletion", "f 0 100 4", FIELD(mutationprobs[FB_DELETION]), "Relative probability of deleting a random character (or a neuron) in the genotype", },
+	{ "fB_mut_duplicate", 1, 0, "Duplication", "f 0 100 0", FIELD(mutationprobs[FB_DUPLICATION]), "Relative probability of copying a single *gene* of the genotype and appending it to the beginning of this genotype", },
+	{ "fB_mut_translocate", 1, 0, "Translocation", "f 0 100 4", FIELD(mutationprobs[FB_TRANSLOCATION]), "Relative probability of swapping two substrings in the genotype", },
+	{ "fB_cross_gene_transfer", 2, 0, "Horizontal gene transfer", "f 0 100 0", FIELD(crossoverprobs[FB_GENE_TRANSFER]), "Relative probability of crossing over by copying a single random gene from each parent to the beginning of the other parent", },
+	{ "fB_cross_crossover", 2, 0, "Crossing over", "f 0 100 100", FIELD(crossoverprobs[FB_CROSSING_OVER]), "Relative probability of crossing over by a random distribution of genes from both parents to both children", },
 	{ 0, },
 };
@@ -128,5 +133,5 @@
 	if (!genotype.getNextToken(pos, strdims, '\n'))
 	{
-		return GENOPER_OPFAIL;
+		return GENOPER_OK;
 	}
 	// parse dimension
@@ -134,5 +139,5 @@
 	if (!ExtValue::parseInt(strdims.c_str(), dims, true, false))
 	{
-		return GENOPER_OPFAIL;
+		return GENOPER_OK;
 	}
 	SString line;
@@ -171,5 +176,5 @@
 			else
 			{
-				return GENOPER_OPFAIL;
+				return GENOPER_OK;
 			}
 		}
@@ -247,5 +252,5 @@
 	{
 		std::list<SString> tokenized = tokenizeSequence(line);
-		int rndid = rndUint(tokenized.size()); // select random letter from genotype
+		int rndid = rndUint((int)tokenized.size()); // select random letter from genotype
 		// increment/decrement character - when overflow happens, this method
 		// uses the "reflect" approach
@@ -282,9 +287,9 @@
 		break;
 	}
-	case FB_NCLASSINS:
+	case FB_INSERTION_NEURON:
 	{
 		std::list<SString> tokenized = tokenizeSequence(line);
 		std::list<SString>::iterator it = tokenized.begin();
-		int rndid = rndUint(tokenized.size()); // select random insertion point
+		int rndid = rndUint((int)tokenized.size()); // select random insertion point
 		std::advance(it, rndid);
 		NeuroClass *cls = getRandomNeuroClass(Model::SHAPETYPE_BALL_AND_STICK);
@@ -307,5 +312,5 @@
 		chg = 1.0 / line.length();
 		std::list<SString> tokenized = tokenizeSequence(line);
-		int rndid = rndUint(tokenized.size()); // select random insertion point
+		int rndid = rndUint((int)tokenized.size()); // select random insertion point
 		std::list<SString>::iterator it = tokenized.begin();
 		std::advance(it, rndid);
@@ -321,5 +326,5 @@
 		std::list<SString> tokenized = tokenizeSequence(line);
 		std::list<SString>::iterator it = tokenized.begin();
-		int rndid = rndUint(tokenized.size()); // select random deletion point
+		int rndid = rndUint((int)tokenized.size()); // select random deletion point
 		std::advance(it, rndid);
 		tokenized.erase(it);
@@ -343,5 +348,5 @@
 		for (int i = 0; i < 4; i++)
 		{
-			cuts[i] = rndUint(tokenized.size());
+			cuts[i] = rndUint((int)tokenized.size());
 		}
 		std::sort(cuts.begin(), cuts.end());
@@ -407,5 +412,5 @@
 	case FB_GENE_TRANSFER:
 	{
-		// get random gene from first parent
+		// get a random gene from the first parent
 		int choice = rndUint(fB_GenoHelpers::geneCount(parent1));
 		int start, end;
@@ -414,5 +419,5 @@
 		child2 = gene + parent2;
 		chg2 = (float)parent2.length() / (float)child2.length();
-		// do the same for second parent
+		// do the same for the second parent
 		choice = rndUint(fB_GenoHelpers::geneCount(parent2));
 		gene = fB_GenoHelpers::getGene(choice, parent2, start, end);
@@ -554,21 +559,41 @@
 		{
 			pos--;
-			if (isdigit(geno[pos]) == 0)
-			{
-				return GENSTYLE_CS(0, GENSTYLE_INVALID);
-			}
-		}
-		return GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
-	}
-	if (islower(ch) == 0)
-	{
-		return GENSTYLE_CS(0, GENSTYLE_INVALID);
-	}
-	uint32_t style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
-	if (ch == 'a' && pos > 0 && (geno[pos - 1] == 'a' || geno[pos - 1] == '\n'))
+			if (isdigit(geno[pos]) == 0) //going left we encountered some non-digit character
+			{
+				return GENSTYLE_CS(GENCOLOR_NUMBER, GENSTYLE_NONE); //so 'ch' is any digit in the genotype (neural property value etc.); for simplicity, digits as parts of neuroclass name or property name also get included here
+			}
+		}
+		return GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD); //only digits up to the beginning, so this is the dimensionality value
+	}
+	if (ch == '-' || ch == '.')
+		return GENSTYLE_CS(GENCOLOR_NUMBER, GENSTYLE_NONE);
+	if (ch == '"')
+		return GENSTYLE_RGBS(150, 0, 150, GENSTYLE_BOLD); //quotes encompass neuron definitions. To further distinguish the text inside quotes from the text outside quotes, we would need to determine the number of '"' from the beginning, i.e. linear search through the entire genotype. We don't want to do it - it would mean the complexity of len(geno)^2 if performed for each symbol in the genotype independently, like this function does. Below we perform an approximate partial scan.
+	if (isupper(ch) || strchr("@|*", ch))
+		return GENSTYLE_RGBS(150, 0, 150, GENSTYLE_BOLD); //neuroclass
+	if (strchr(":,=", ch))
+		return GENSTYLE_RGBS(150, 0, 150, GENSTYLE_NONE); //these symbols occur exclusively inside "...neuron...", so let's make the entire neuron section "...neuron..." more visually uniform by using the same violet color as the neuroclass name and quotes have
+	if (islower(ch)) //how to color the current lower-case letter?
+	{
+		static const int SCAN_RANGE = 8; //how many characters before the current one to scan to discover some context and find out if we are likely in the neuroclass name or the property name. Reduces computational complexity. Example genotype fragments: abcabc"T:r=0.9, ry=4.088, rz=1.213"abcabc or abc"N:in=0.0, fo=0.17, si=999.0"abc
+		int i = pos;
+		while (i > 0 && pos - i < SCAN_RANGE)
+		{
+			i--; //go back one char
+			if (isupper(geno[i]))
+				return GENSTYLE_RGBS(150, 0, 150, GENSTYLE_BOLD); //neuroclass
+			if (geno[i] == ',' || geno[i] == ':') //this is what must occur before property name starts
+				return GENSTYLE_RGBS(255, 140, 0, GENSTYLE_BOLD); //property
+			if (!(isalpha(geno[i]) || isspace(geno[i]))) //going left we encountered any char that is not a letter or space
+				break;
+		}
+	}
+
+	uint32_t style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE); //if the current character did not fall into any of the above cases, assume default black style
+	if (ch == 'a' && (geno[pos + 1] == 'a' || (pos > 0 && geno[pos - 1] == 'a'))) //start codon, "aa"
 	{
 		style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
 	}
-	else if (ch == 'z' && pos > 0 && geno[pos - 1] == 'z')
+	else if (ch == 'z' && (geno[pos + 1] == 'z' || (pos > 0 && geno[pos - 1] == 'z'))) //stop codon, "zz"
 	{
 		style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
Index: cpp/frams/genetics/fB/fB_oper.h
===================================================================
--- cpp/frams/genetics/fB/fB_oper.h	(revision 1130)
+++ cpp/frams/genetics/fB/fB_oper.h	(revision 1273)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -11,17 +11,17 @@
 /** @name Codes for general fB mutation types */
 //@{
-#define FB_SUBSTITUTION  0 ///<Relative probability of mutation by changing single random letter in genotype (substitution)
-#define FB_INSERTION     1 ///<Relative probability of mutation by inserting characters in random place of genotype
-#define FB_NCLASSINS     2 ///<Relative probability of mutation by inserting neuron class definition in random place of genotype
-#define FB_DELETION      3 ///<Relative probability of mutation by deleting random characters in genotype
-#define FB_DUPLICATION   4 ///<Relative probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype
-#define FB_TRANSLOCATION 5 ///<Relative probability of mutation by replacing two substrings in genotype
-#define FB_MUT_COUNT     6 ///<Count of mutation types
+#define FB_SUBSTITUTION     0 ///<Relative probability of changing a single random character (or a neuron) in the genotype
+#define FB_INSERTION        1 ///<Relative probability of inserting a random character in a random place of the genotype
+#define FB_INSERTION_NEURON 2 ///<Relative probability of inserting a neuron in a random place of genotype
+#define FB_DELETION         3 ///<Relative probability of deleting a random character (or a neuron) in the genotype
+#define FB_DUPLICATION      4 ///<Relative probability of copying a single *gene* of the genotype and appending it to the beginning of this genotype
+#define FB_TRANSLOCATION    5 ///<Relative probability of swapping two substrings in the genotype
+#define FB_MUT_COUNT        6 ///<Count of mutation types
 //@}
 
 /** @name Codes for fB cross over types */
 //@{
-#define FB_GENE_TRANSFER 0 ///<Relative probability of crossing over by transferring single genes from both parents to beginning of each other
-#define FB_CROSSING_OVER 1 ///<Relative probability of crossing over by random distribution of genes from both parents to both children
+#define FB_GENE_TRANSFER 0 ///<Relative probability of crossing over by copying a single random gene from each parent to the beginning of the other parent
+#define FB_CROSSING_OVER 1 ///<Relative probability of crossing over by a random distribution of genes from both parents to both children
 #define FB_XOVER_COUNT   2 ///<Count of crossing over types
 //@}
@@ -48,5 +48,5 @@
 	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
 
-	virtual const char* getSimplest() { return "5\naaazz"; }
+	virtual const char* getSimplest() { return "3\naaazz"; }
 
 	uint32_t style(const char *geno, int pos);
