Index: cpp/frams/genetics/fF/fF_genotype.cpp
===================================================================
--- cpp/frams/genetics/fF/fF_genotype.cpp	(revision 145)
+++ cpp/frams/genetics/fF/fF_genotype.cpp	(revision 145)
@@ -0,0 +1,20 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "fF_genotype.h"
+
+#define FIELDSTRUCT fF_growth_params
+ParamEntry fF_growth_params::paramtab[] =
+{
+	{ "fF", 1, 7, "fF" },
+	{ "n", 0, PARAM_CANOMITNAME, "number of chambers", "d 1 15 1", FIELD(number_of_chambers), },
+	{ "sx", 0, PARAM_CANOMITNAME, "scale x", "f 0.5 1.0 0.9", FIELD(scalex), },
+	{ "sy", 0, PARAM_CANOMITNAME, "scale y", "f 0.5 1.0 0.9", FIELD(scaley), },
+	{ "sz", 0, PARAM_CANOMITNAME, "scale z", "f 0.5 1.0 0.9", FIELD(scalez), },
+	{ "tr", 0, PARAM_CANOMITNAME, "translation factor", "f 0 1 0.5", FIELD(translation), }, //formally -1..1, but let's avoid redundancy and elliminate symmetrical constructs
+	{ "a1", 0, PARAM_CANOMITNAME, "angle 1", "f -3.1415926 3.1415926 0", FIELD(angle1), },
+	{ "a2", 0, PARAM_CANOMITNAME, "angle 2", "f -3.1415926 3.1415926 0", FIELD(angle2), },
+	{ 0, 0, 0, },
+};
+#undef FIELDSTRUCT
Index: cpp/frams/genetics/fF/fF_genotype.h
===================================================================
--- cpp/frams/genetics/fF/fF_genotype.h	(revision 140)
+++ cpp/frams/genetics/fF/fF_genotype.h	(revision 145)
@@ -8,14 +8,18 @@
 #include <stdio.h>
 #include "common/stl-util.h"
-
+#include <frams/param/param.h>
 
 struct fF_growth_params
 {
 	int number_of_chambers;
-	double scalex, scaley, scalez; //scaling factors
-	double translation; //translation factor, TF range [−1; 1]
+	double scalex, scaley, scalez;
+	double translation;
 	double angle1, angle2;
 
+	static ParamEntry paramtab[];
+	Param param;
+
 	fF_growth_params()
+		:param(paramtab, this)
 	{
 		reset();
@@ -24,18 +28,19 @@
 	void reset()
 	{
-		number_of_chambers = 1;
-		scalex = scaley = scalez = 1;
-		translation = 1;
-		angle1 = angle2 = 0;
+		param.setDefault();
 	}
 
 	bool load(const char* serialized)
 	{
-		return sscanf(serialized, "%d %lf %lf %lf %lf %lf %lf", &number_of_chambers, &scalex, &scaley, &scalez, &translation, &angle1, &angle2) == 7;
+		SString s = serialized;
+		int p = 0; //position in string
+		return ((param.load2(s, p)==7) && (p==s.len()));
 	}
 
 	string save()
 	{
-		return ssprintf("%d %f %f %f %f %f %f", number_of_chambers, scalex, scaley, scalez, translation, angle1, angle2);
+		SString tmp;
+		param.save2(tmp, NULL/*object containing default values for comparison*/, false/*add CR*/, false/*force field names*/);
+		return string((const char*)tmp);
 	}
 };
Index: cpp/frams/genetics/fF/oper_fF.cpp
===================================================================
--- cpp/frams/genetics/fF/oper_fF.cpp	(revision 140)
+++ cpp/frams/genetics/fF/oper_fF.cpp	(revision 145)
@@ -4,16 +4,14 @@
 
 #include "oper_fF.h"
-#include <frams/genetics/f9/conv_f9.h>
+#include "fF_genotype.h"
 #include <common/nonstd.h> //randomN, rnd01
 
 
-//THIS FILE NEEDS UPDATE. OLD, UNRELATED SOURCES BELOW (COPIED FROM f9).
-
 #define FIELDSTRUCT GenoOper_fF
-static ParamEntry GENOf9param_tab[]=
+static ParamEntry GENOfFparam_tab[] =
 {
-	{"Genetics: fF",1,1,},
-	{"fF_mut",0,0,"Mutation probability","f 0 1 0.1",FIELD(mut_prob),"How many genes should be mutated during single mutation (1=all genes, 0.1=ten percent)",},
-	{0,},
+	{ "Genetics: fF", 1, 1, },
+	{ "fF_xover", 0, 0, "Averaging crossover proportion", "f 0 0.5 0.5", FIELD(xover_proportion), "0.5 => children are averaged parents.\n0.2 => children are only 20% different from parents.\n0 => each child is identical to one parent (no crossover).", },
+	{ 0, },
 };
 #undef FIELDSTRUCT
@@ -22,89 +20,69 @@
 GenoOper_fF::GenoOper_fF()
 {
-	par.setParamTab(GENOf9param_tab);
+	par.setParamTab(GENOfFparam_tab);
 	par.select(this);
 	par.setDefault();
-	supported_format='F';
+	supported_format = 'F';
 }
 
 int GenoOper_fF::checkValidity(const char* gene)
 {
-	return GENOPER_OK;
-	if (!gene[0]) return 1; //empty is not valid
-	bool ok=true;
-	int i;
-	for(i=0;i<strlen(gene);i++) if (!strchr(turtle_commands_f9,gene[i])) {ok=false; break;}
-	return ok ? GENOPER_OK : i+1;
+	fF_growth_params par;
+	return par.load(gene) ? GENOPER_OK : 1;
 }
 
-///Remove all invalid letters from the genotype
 int GenoOper_fF::validate(char *&gene)
 {
-	SString validated; //new genotype (everything except turtle_commands_f9 is skipped)
-	for(int i=0;i<strlen(gene);i++)
-		if (strchr(turtle_commands_f9,gene[i])) validated+=gene[i];  //validated contains only turtle_commands_f9
+	fF_growth_params par; //is initialized with default values
+	par.load(gene); //loads as much as possible, other fields remain with default values
+	string validated = par.save();
 	free(gene);
-	gene=strdup(validated); //reallocate
+	gene = strdup(validated.c_str()); //reallocate
 	return GENOPER_OK;
 }
 
-///Very simple mutation
-int GenoOper_fF::mutate(char *&gene,float &chg,int &method)
+//Creep-mutate one property
+int GenoOper_fF::mutate(char *&gene, float &chg, int &method)
 {
-	method=0;
-	int changes=0,len=strlen(gene);
-	int symbols=strlen(turtle_commands_f9);
-
-	for(int i=0;i<len;i++)
+	method = 0;
+	fF_growth_params par;
+	par.load(gene);
+	int which = randomN(par.param.getPropCount());
+	bool mutated_ok = GenoOperators::mutatePropertyNaive(par.param, which);
+	if (mutated_ok)
 	{
-		if (rnd01<mut_prob) //normalize prob with the length of the genotype
-		{
-			char oldgene=gene[i];
-			gene[i]=turtle_commands_f9[randomN(symbols)];
-			if (gene[i]!=oldgene) changes++;
-		}
+		string saved = par.save();
+		free(gene);
+		gene = strdup(saved.c_str()); //reallocate
+		chg = 1.0f / par.param.getPropCount();
+		return GENOPER_OK;
 	}
-
-	if (rnd01<mut_prob) //add or delete a random char
+	else
 	{
-		SString newgeno(gene);
-		if (randomN(2)==0) //add
-		{
-			int symbols=strlen(turtle_commands_f9);
-			int p=randomN(len+1);  //random location
-			//printf("before add: %s\n",(const char*)newgeno);
-			newgeno=newgeno.substr(0,p)+SString(turtle_commands_f9+randomN(symbols),1)+newgeno.substr(p);
-			//printf("after add: %s\n",(const char*)newgeno);
-			changes++;
-		} else if (len>1) //delete
-		{
-			int p=randomN(len);  //random location
-			//printf("before delete: %s\n",(const char*)newgeno);
-			newgeno=newgeno.substr(0,p)+newgeno.substr(p+1);
-			//printf("after delete: %s\n",(const char*)newgeno);
-			changes++;
-		}
-		free(gene);
-		gene=strdup(newgeno); //reallocate
+		chg = 0;
+		return GENOPER_OPFAIL;
 	}
-
-	chg=(float)changes/len;
-	return changes>0?GENOPER_OK:GENOPER_OPFAIL; //no changes => OPFAIL so that genman will call mutate again
 }
 
-///A simple one-point crossover
-int GenoOper_fF::crossOver(char *&g1,char *&g2,float& chg1,float& chg2)
+///Averaging crossover
+int GenoOper_fF::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
 {
-	int len1=strlen(g1),len2=strlen(g2);
-	int p1=randomN(len1);  //random cut point for first genotype
-	int p2=randomN(len2);  //random cut point for second genotype
-	char *child1=(char*)malloc(p1+len2-p2+1);
-	char *child2=(char*)malloc(p2+len1-p1+1);
-	strncpy(child1,g1,p1);   strcpy(child1+p1,g2+p2);
-	strncpy(child2,g2,p2);   strcpy(child2+p2,g1+p1);
-	free(g1); g1=child1;
-	free(g2); g2=child2;
-	chg1=(float)p1/strlen(child1);
-	chg2=(float)p2/strlen(child2);
+	//g1 = strdup("1,0.5,0.5,0.5,0.5,1,1"); //testing...
+	//g2 = strdup("4,1,  1,  1,  1,  2,2"); //testing...
+	//xover_proportion = 0.1; //testing...
+	fF_growth_params par1;
+	par1.load(g1);
+	fF_growth_params par2;
+	par2.load(g2);
+	chg1 = xover_proportion;
+	chg2 = 1 - xover_proportion;
+	for (int i = 0; i < par1.param.getPropCount(); i++)
+		GenoOperators::linearMix(par1.param, i, par2.param, i, xover_proportion);
+	string saved = par1.save();
+	free(g1);
+	g1 = strdup(saved.c_str()); //reallocate
+	saved = par2.save();
+	free(g2);
+	g2 = strdup(saved.c_str()); //reallocate
 	return GENOPER_OK;
 }
@@ -113,13 +91,10 @@
 unsigned long GenoOper_fF::style(const char *g, int pos)
 {
-	char ch=g[pos];
-	unsigned long style=GENSTYLE_CS(0,GENSTYLE_INVALID); //default, should be changed below
-	char *ptr=strchr((char*)turtle_commands_f9,ch);
-	if (ptr)
-	{
-		int pos=ptr-turtle_commands_f9;
-		int axis=pos/2;
-		style=GENSTYLE_RGBS(axis==0?200:0,axis==1?200:0,axis==2?200:0,GENSTYLE_NONE);
-	}
+	char ch = g[pos];
+	unsigned long style = GENSTYLE_CS(0, GENSTYLE_INVALID); //default, should be changed below
+	if (strchr("-.e 0123456789", ch) != NULL)
+		style = GENSTYLE_CS(GENCOLOR_NUMBER, GENSTYLE_NONE);
+	else if (ch == ',')
+		style = GENSTYLE_RGBS(0, 0, 0, GENSTYLE_BOLD);
 	return style;
 }
Index: cpp/frams/genetics/fF/oper_fF.h
===================================================================
--- cpp/frams/genetics/fF/oper_fF.h	(revision 140)
+++ cpp/frams/genetics/fF/oper_fF.h	(revision 145)
@@ -18,7 +18,7 @@
 	int crossOver(char *&g1, char *&g2, float& chg1, float& chg2);
 	unsigned long style(const char *g, int pos);
-	const char* getSimplest() { return "5 0.9 0.8 0.7 0.7 0.3 0.7"; }
+	const char* getSimplest() { return "6,0.8,0.85,0.9,0.6,0.3,0.7"; }
 
-	double mut_prob; //mutation probability
+	double xover_proportion;
 };
 
