Index: /cpp/frams/Makefile-SDK
===================================================================
--- /cpp/frams/Makefile-SDK	(revision 1006)
+++ /cpp/frams/Makefile-SDK	(revision 1007)
@@ -5,5 +5,5 @@
 include frams/Makefile-SDK-files
 
-SDK_TESTS=genoconv_test genomanipulation geno_test genooper_test genooper_test_fTest neuro_test loader_test_geno loader_test_param saver_test_geno serial_test multiline_f0_test f0_variants_test full_props shapeconvert part_shapes neuro_layout_test geometry_apices_test geometry_info_test geometry_surface_test geometry_volume_test simil_test simil_unittests paramtree_stdin_test paramtree_paramlist_test mutableparam_test
+SDK_TESTS=genoconv_test genomanipulation geno_test genooper_test genooper_test_fTest neuro_test loader_test_geno loader_test_param saver_test_geno serial_test multiline_f0_test f0_variants_test full_props shapeconvert part_shapes neuro_layout_test geometry_apices_test geometry_info_test geometry_surface_test geometry_volume_test simil_test simil_unittests paramtree_stdin_test paramtree_paramlist_test mutableparam_test evol_test
 
 sdk_tests: $(SDK_TESTS)
@@ -12,5 +12,5 @@
 
 SDK_BUILD_CONFIG= -include frams/config/sdk_build_config.h
-CXXFLAGS= -I$(CURDIR) -std=c++17 $(SDK_BUILD_CONFIG) $(CXXWARNINGS) -g
+CXXFLAGS= -I$(CURDIR) -std=gnu++17 $(SDK_BUILD_CONFIG) $(CXXWARNINGS) -g
 
 AR=ar
@@ -101,7 +101,10 @@
 	$(CXX) $(MUTABLEPARAM_TEST_OBJS) $(LDFLAGS) -o $@
 
+evol_test: $(EVOL_TEST_OBJS)
+	$(CXX) $(EVOL_TEST_OBJS) $(LDFLAGS) -o $@
+
 #############################################
 
-ALL_OBJS=$(GENOMANIPULATION_OBJS) $(GENOCONV_TEST_OBJS) $(GENO_TEST_OBJS) $(NEURO_TEST_OBJS) $(LOADER_TEST_OBJS) $(SERIAL_TEST_OBJS) $(MULTILINE_F0_OBJS) $(F0_VARIANTS_OBJS) $(FULL_PROPS_OBJS) $(PART_SHAPES_OBJS) $(NEURO_LAYOUT_TEST_OBJS) $(GENOOPER_TEST_OBJS) $(GEOMETRY_APICES_TEST_OBJS) $(GEOMETRY_INFO_TEST_OBJS) $(GEOMETRY_SURFACE_TEST_OBJS) $(GEOMETRY_VOLUME_TEST_OBJS) $(SIMIL_TEST_OBJS) $(SIMIL_UNITTESTS_OBJS) $(PARAMTREE_STDIN_TEST_OBJS) $(PARAMTREE_PARAMLIST_TEST_OBJS) $(MUTABLEPARAM_TEST_OBJS)
+ALL_OBJS=$(GENOMANIPULATION_OBJS) $(GENOCONV_TEST_OBJS) $(GENO_TEST_OBJS) $(NEURO_TEST_OBJS) $(LOADER_TEST_OBJS) $(SERIAL_TEST_OBJS) $(MULTILINE_F0_OBJS) $(F0_VARIANTS_OBJS) $(FULL_PROPS_OBJS) $(PART_SHAPES_OBJS) $(NEURO_LAYOUT_TEST_OBJS) $(GENOOPER_TEST_OBJS) $(GEOMETRY_APICES_TEST_OBJS) $(GEOMETRY_INFO_TEST_OBJS) $(GEOMETRY_SURFACE_TEST_OBJS) $(GEOMETRY_VOLUME_TEST_OBJS) $(SIMIL_TEST_OBJS) $(SIMIL_UNITTESTS_OBJS) $(PARAMTREE_STDIN_TEST_OBJS) $(PARAMTREE_PARAMLIST_TEST_OBJS) $(MUTABLEPARAM_TEST_OBJS) $(EVOL_TEST_OBJS)
 
 include common/Makefile-maintain
Index: /cpp/frams/Makefile-SDK-files
===================================================================
--- /cpp/frams/Makefile-SDK-files	(revision 1006)
+++ /cpp/frams/Makefile-SDK-files	(revision 1007)
@@ -101,2 +101,4 @@
 
 MUTABLEPARAM_TEST_OBJS=frams/_demos/mutableparam_test.o $(STDOUT_LOGGER_OBJS) common/virtfile/stdiofile.o $(SDK_OBJS) frams/param/mutableparam.o frams/param/mutparamlist.o frams/param/paramtrans.o
+
+EVOL_TEST_OBJS=frams/_demos/evol_test.o $(SDK_OBJS) $(GENOCONV_AND_GENMAN_SDK_OBJS) $(STDOUT_LOGGER_OBJS)
Index: /cpp/frams/_demos/evol_test.cpp
===================================================================
--- /cpp/frams/_demos/evol_test.cpp	(revision 1007)
+++ /cpp/frams/_demos/evol_test.cpp	(revision 1007)
@@ -0,0 +1,157 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 2019-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+
+#include <vector>
+#include "common/loggers/loggertostdout.h"
+#include "frams/genetics/preconfigured.h"
+#include "frams/genetics/genman.h"
+#include "frams/model/model.h"
+
+
+struct Individual
+{
+	Geno geno;
+	double fitness;
+};
+
+double criterion(char symbol, double value)
+{
+	return isupper(symbol) ? value : -value;
+}
+
+void evaluate_fitness(Individual &ind, const char *fitness_def)
+{
+	SString genotype = ind.geno.getGenes();
+	Model model = Model(ind.geno, Model::SHAPETYPE_UNKNOWN);
+	double fitness = 0;
+	const char *p = fitness_def;
+	while (*p)
+	{
+		switch (*p)
+		{
+		case 'l':
+		case 'L':
+			fitness += criterion(*p, genotype.length());
+			break;
+		case 'p':
+		case 'P':
+			fitness += criterion(*p, model.getPartCount());
+			break;
+		case 'j':
+		case 'J':
+			fitness += criterion(*p, model.getJointCount());
+			break;
+		case 'n':
+		case 'N':
+			fitness += criterion(*p, model.getNeuroCount());
+			break;
+		case 'c':
+		case 'C':
+			fitness += criterion(*p, model.getConnectionCount());
+			break;
+			// TODO add more criteria as described in main() below
+		default:
+			printf("Unknown fitness criterion symbol: '%c'\n", *p);
+			exit(3);
+		}
+		p++;
+	}
+	ind.fitness = fitness;
+}
+
+int tournament(const vector<Individual> &population, int tournament_size)
+{
+	int best = -1;
+	for (int i = 0; i < tournament_size; i++)
+	{
+		int rnd = rndUint(population.size());
+		if (best == -1) best = rnd;
+		else if (population[rnd].fitness > population[best].fitness) //assume maximization
+			best = rnd;
+	}
+	return best;
+}
+
+
+/** A minimalistic steady-state evolutionary algorithm. */
+int main(int argc, char *argv[])
+{
+	PreconfiguredGenetics genetics;
+	LoggerToStdout messages_to_stdout(LoggerBase::Enable);
+	GenMan genman;
+
+	bool deterministic;
+	int pop_size, nr_evals;
+	double prob_mut, prob_xover;
+	const char* format;
+	const char* fitness_def;
+
+	if (argc < 8)
+	{
+		printf("Too few parameters!\n");
+		printf("Command line: <deterministic?_0_or_1> <population_size> <nr_evaluations> <prob_mut> <prob_xover> <genetic_format> <fitness_definition>\n");
+		printf("Example: 1 10 50 0.5 0.5 4 NC\n\n\n");
+		printf("Fitness definition is a sequence of capital (+1 weight) and small (-1 weight) letters.\n");
+		printf("Each letter corresponds to one fitness criterion, and they are all weighted and added together.\n");
+		printf("  l or L - genotype length in characters.\n");
+		printf("  p or P - the number of Parts.\n");
+		printf("  j or J - the number of Joints.\n");
+		printf("  n or N - the number of Neurons.\n");
+		printf("  c or C - the number of neural Connections.\n");
+		//TODO add b - bounding box volume (from Model), s - surface area (from geometry), v - volume (from geometry), h,w,d - three consecutive dimensions (from geometry)
+
+		return 1;
+	}
+
+	deterministic = atoi(argv[1]) == 1;
+	pop_size = atoi(argv[2]);
+	nr_evals = atoi(argv[3]);
+	prob_mut = atof(argv[4]);
+	prob_xover = atof(argv[5]);
+	format = argv[6];
+	fitness_def = argv[7];
+
+	if (!deterministic)
+		rndGetInstance().randomize();
+
+	vector<Individual> population(pop_size);
+	for (Individual& ind : population)
+	{
+		ind.geno = genman.getSimplest(format);
+		if (ind.geno.getGenes() == "")
+		{
+			printf("Could not get the simplest genotype for format '%s'\n", format);
+			return 2;
+		}
+		evaluate_fitness(ind, fitness_def);
+	}
+	for (int i = 0; i < nr_evals; i++)
+	{
+		int selected_positive = tournament(population, max(2, int(sqrt(population.size()) / 2))); //moderate positive selection pressure
+		int selected_negative = rndUint(population.size()); //random negative selection
+
+		double rnd = rndDouble(prob_mut + prob_xover);
+		if (rnd < prob_mut)
+		{
+			population[selected_negative].geno = genman.mutate(population[selected_positive].geno);
+			//TODO handle failed mutation
+			evaluate_fitness(population[selected_negative], fitness_def);
+		}
+		else
+		{
+			//TODO crossover
+		}
+
+		if (i % population.size() == 0 || i == nr_evals - 1)
+			printf("Evaluation %d\t...\n", i); //TODO print min,avg,max fitness \t min,avg,max genotype length \t min,avg,max parts \t min,avg,max neurons
+	}
+	for (const Individual& ind : population)
+	{
+		printf("%.1f\t", ind.fitness);
+		printf("%s\n", ind.geno.getGenes().c_str());
+	}
+
+	return 0;
+}
