Index: cpp/frams/genetics/f4/oper_f4.cpp
===================================================================
--- cpp/frams/genetics/f4/oper_f4.cpp	(revision 676)
+++ cpp/frams/genetics/f4/oper_f4.cpp	(revision 760)
@@ -5,4 +5,5 @@
 // Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
 // Copyright (C) since 2001 Maciej Komosinski
+// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
 
 #include "oper_f4.h"
@@ -138,10 +139,10 @@
 #define REP_MAXCOUNT 19
 
-	f4_node * n1, *n2, *n3, *n4, *n5;
-
 	// do the mutation
 	// pick a random node
-	n1 = g->child->randomNode();
+	f4_node *n1 = g->child->randomNode();
+	vector<NeuroClass*> neulist;
 	//DB( printf("%c\n", n1->name); )
+	int neuronid = -1;
 
 	switch (roulette(prob, F4_COUNT))
@@ -155,29 +156,55 @@
 		{
 			// add division ('<')
-			n3 = n1->parent;
+			f4_node *n3 = n1->parent;
 			n3->removeChild(n1);
-			n2 = new f4_node('<', n3, n3->pos);
+			f4_node *n2 = new f4_node('<', n3, n3->pos);
 			n2->addChild(n1);
 			// new cell is stick or neuron
 			// "X>" or "N>"
+			f4_node *n5 = NULL;
 			double pr = rnd01;
 			pr -= 0.5;
-			if (pr < 0) n3 = new f4_node('X', n2, n2->pos);
+			if (pr < 0) n5 = new f4_node('X', n2, n2->pos);
 			else
 			{
-				pr -= 0.5;
-				if (pr < 0)
-				{
-					// if neuron, make muscle and add a link
-					n3 = new f4_node('N', n2, n2->pos);
-					if (randomN(2) == 0)
-						n4 = new f4_node('|', n3, n2->pos);
-					else
-						n4 = new f4_node('@', n3, n2->pos);
-					n5 = new f4_node('[', n4, n2->pos);
-					linkNodeMakeRandom(n5);
-				}
-			}
-			new f4_node('>', n3, n3->pos);
+				// make neuron
+				NeuroClass * rndclass = GenoOperators::getRandomNeuroClass();
+				if (rndclass == NULL)
+				{
+					n5 = new f4_node('X', n2, n2->pos);
+				}
+				else
+				{
+					f4_node *n4 = new f4_node(rndclass->getName().c_str(), n2, n2->pos); //TODO move this above
+					if (rndclass->getPreferredInputs() != 0)
+					{
+						neuronid = -1;
+						for (int i = 0; i < g->count(); i++)
+						{
+							f4_node * gcur = g->ordNode(i);
+							char * temp = (char*)gcur->name.c_str();
+							NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
+							if (neuclass != NULL)
+							{
+								neulist.push_back(neuclass);
+							}
+							if (g->ordNode(i) == n3)
+							{
+								neuronid = neulist.size()-1;
+							}
+						}
+						if (neuronid == -1)
+						{
+							return GENOPER_OPFAIL;
+						}
+						n5 = new f4_node('[', n4, n2->pos);
+						linkNodeMakeRandom(n5, neuronid, neulist);
+					}
+					else {
+						n5 = n4;
+					}
+				}
+			}
+			new f4_node('>', n5, n5->pos);
 			n1->parent = n2;
 			// now with 50% chance swap children
@@ -193,9 +220,34 @@
 		{
 			// add link
-			n1->parent->removeChild(n1);
-			n2 = new f4_node('[', n1->parent, n1->parent->pos);
-			linkNodeMakeRandom(n2);
-			n2->addChild(n1);
-			n1->parent = n2;
+			f4_node * par = n1->parent;
+			char * temp = (char*)par->name.c_str();
+			NeuroClass * neuclass = GenoOperators::parseNeuroClass(temp);
+			if (neuclass != NULL)
+			{
+				n1->parent->removeChild(n1);
+				f4_node *n2 = new f4_node('[', n1->parent, n1->parent->pos);
+				n2->addChild(n1);
+				n1->parent = n2;
+				neuronid = -1;
+				for (int i = 0; i < g->count(); i++)
+				{
+					f4_node *gcur = g->ordNode(i);
+					temp = (char*)gcur->name.c_str();
+					NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
+					if (neuclass != NULL)
+					{
+						neulist.push_back(neuclass);
+					}
+					if (gcur == par)
+					{
+						neuronid = neulist.size()-1;
+					}
+				}
+				if (neuronid == -1)
+				{
+					return GENOPER_OPFAIL;
+				}
+				linkNodeMakeRandom(n2, neuronid, neulist);
+			}
 		}
 			break;
@@ -204,5 +256,5 @@
 			// add neuron modifier
 			n1->parent->removeChild(n1);
-			n2 = new f4_node(':', n1->parent, n1->parent->pos);
+			f4_node *n2 = new f4_node(':', n1->parent, n1->parent->pos);
 			nparNodeMakeRandom(n2);
 			n2->addChild(n1);
@@ -214,7 +266,7 @@
 			// add repetition ('#')
 			// repeated code (left child) is the original, right child is empty, count is 2
-			n3 = n1->parent;
+			f4_node *n3 = n1->parent;
 			n3->removeChild(n1);
-			n2 = new f4_node('#', n3, n3->pos);
+			f4_node *n2 = new f4_node('#', n3, n3->pos);
 			n2->i1 = 2;
 			n2->addChild(n1);
@@ -228,5 +280,5 @@
 			// choose a simple node from ADD_SIMPLE_CODES
 			n1->parent->removeChild(n1);
-			n2 = new f4_node(ADD_SIMPLE_CODES[randomN(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
+			f4_node *n2 = new f4_node(ADD_SIMPLE_CODES[randomN(strlen(ADD_SIMPLE_CODES))], n1->parent, n1->parent->pos);
 			n2->addChild(n1);
 			n1->parent = n2;
@@ -258,5 +310,5 @@
 			case 1:  // one child
 			{
-				n2 = n1->parent;
+				f4_node *n2 = n1->parent;
 				n2->removeChild(n1);
 				if (NULL != n1->child)
@@ -281,5 +333,5 @@
 			{
 				// two children
-				n2 = n1->parent;
+				f4_node *n2 = n1->parent;
 				n2->removeChild(n1);
 				// n1 has two children. pick one randomly 50-50, destroy other
@@ -318,5 +370,5 @@
 		while (1)
 		{
-			if (strchr(MUT_CHAN_CODES, n1->name)) break;
+			if (strchr(MUT_CHAN_CODES, n1->name[0])) break;
 			// try a new one
 			n1 = g->child->randomNode();
@@ -324,15 +376,41 @@
 			if (i >= 20) return GENOPER_OPFAIL;
 		}
-		switch (n1->name)
+		switch (n1->name[0])
 		{
 		case '<':
+		{
 			// swap children
-			n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
+			f4_node *n2 = n1->child; n1->child = n1->child2; n1->child2 = n2;
+		}
 			break;
 		case '[':
-			linkNodeChangeRandom(n1);
+		{
+			neuronid = -1;
+			for (int i = 0; i < g->count(); i++)
+			{
+				f4_node *gcur = g->ordNode(i);
+				char *temp = (char*)gcur->name.c_str();
+				NeuroClass *neuclass = GenoOperators::parseNeuroClass(temp);
+				if (neuclass != NULL)
+				{
+					neulist.push_back(neuclass);
+				}
+				if (gcur == n1)
+				{
+					neuronid = neulist.size()-1;
+				}
+			}
+			if (neuronid == -1)
+			{
+				return GENOPER_OPFAIL;
+			}
+			linkNodeChangeRandom(n1, neuronid, neulist);
+		}
 			break;
+
 		case '#':
+		{
 			repeatNodeChangeRandom(n1);
+		}
 			break;
 		}
@@ -348,10 +426,9 @@
 
 // make a random [ node
-void Geno_f4::linkNodeMakeRandom(f4_node * nn) const
-{
-	int i;
+void Geno_f4::linkNodeMakeRandom(f4_node *nn, int neuid, vector<NeuroClass*> neulist) const
+{
 	float prob1;
-
-	i = 0;
+	NeuroClass *nc = NULL;
+
 	// 35% chance one of *GTS
 	prob1 = rnd01;
@@ -360,24 +437,30 @@
 	{
 		// '*', 'G', 'T', or 'S', 1/4 chance each
-		i = 1 + (int)(3.999f * rnd01);
-	}
-	nn->i1 = i;
-	nn->l1 = 0;
-	if (0 == i)
+		nc =  GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
+	}
+	if (nc != NULL)
+	{
+		nn->i1 = 1;
+		nn->s1 = nc->getName().c_str();
+		nn->l1 = 0;
+	}
+	else
 	{
 		// relative input link
-		nn->l1 = (int)(4.0f * (rnd01 - 0.5f));
+		int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
+		int relid = neuid - id;
+		nn->l1 = relid;
+		//nn->l1 = (int)(4.0f * (rnd01 - 0.5f));
 	}
 	// weight
-	nn->f1 = 10.0f * (rnd01 - 0.5f);
+	nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
+	//nn->f1 = 10.0f * (rnd01 - 0.5f);
 }
 
 // change a [ node
-void Geno_f4::linkNodeChangeRandom(f4_node * nn) const      //rewritten by M.K. - should work as before (not tested)
-{
-	int i;
-	float prob2;
-
+void Geno_f4::linkNodeChangeRandom(f4_node * nn, int neuid, std::vector<NeuroClass*> neulist) const      //rewritten by M.K. - should work as before (not tested)
+{
 	double probs[3] = { 0.1, 0.3, 0.6 };
+	NeuroClass *cl;
 	// 10% change type
 	// 30% change link
@@ -387,16 +470,27 @@
 	{
 	case 0: // change type
-		i = 0;
-		// * G, 10% chance each
-		prob2 = rnd01 - 0.10f;
-		if (prob2 < 0) i = 1; else { prob2 -= 0.10f; if (prob2 < 0) i = 2; }
-		nn->i1 = i;
+		// 80% for link, 20% for random sensor
+		if (rnd01 < 0.2f)
+		{
+			cl = GenoOperators::getRandomNeuroClassWithOutputAndNoInputs();
+			if (cl != NULL)
+			{
+				nn->i1 = 1;
+				nn->s1 = cl->name.c_str();
+				nn->l1 = 0;
+			}
+		}
 		break;
 	case 1: // change link
 		if (0 == nn->i1) // relative input link
-			nn->l1 += (int)(2.0f * (rnd01 - 0.5f));
+		{
+			int id = GenoOperators::getRandomNeuroClassWithOutput(neulist);
+			nn->l1 = neuid - id;
+		}
+			//nn->l1 += (int)(2.0f * (rnd01 - 0.5f));
 		break;
 	case 2: // change weight
-		nn->f1 += 1.0f * (rnd01 - 0.5f);
+		nn->f1 = GenoOperators::mutateNeuProperty(nn->f1,NULL,-1);
+		//nn->f1 += 1.0f * (rnd01 - 0.5f);
 		break;
 	}
