// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2020 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include #include #include #include #include #include "printconvmap.h" #include /** @file Sample code: Genotype converter class */ /// Sample Geno converter not using Model class. /// (This converter generates the same output for each input). /// Such a converter is responsible for doing valid f0 (or other format) output and storing temporary data. class GenoConv_Test : public GenoConverter { public: GenoConv_Test() { name = "Test Converter"; in_format = 'x'; } SString convert(SString &i, MultiMap *map, bool using_checkpoints) { return SString("after conversion..."); } ~GenoConv_Test() {} }; /// Sample Geno converter using Model class. /// (This converter generates the same output for each input). class GenoConv_Test2 : public GenoConverter { public: GenoConv_Test2() { name = "Test Converter #2"; in_format = 'y'; } SString convert(SString &i, MultiMap *map, bool using_checkpoints) { Model mod; mod.open(); mod.addFromString(Model::PartType, "0,0,0"); mod.addFromString(Model::PartType, "0,0,-1"); mod.addFromString(Model::JointType, "0,1"); mod.getPart(1)->p.y += 0.2; //as an example, directly modify position of part #1 mod.close(); return mod.getF0Geno().getGenes(); } ~GenoConv_Test2() {} }; /// Sample Geno converter supporting conversion mapping. /// The conversion is very simple: any sequence of /// (but not inside neurons) is replaced by the repeated sequence of the character. class GenoConv_Test3 : public GenoConverter { public: GenoConv_Test3() { name = "Test Converter #3"; in_format = "multiply"; out_format = '1'; mapsupport = 1; } SString convert(SString &in, MultiMap *map, bool using_checkpoints); ~GenoConv_Test3() {} }; /** main converting routine - most important: direct conversion map example */ SString GenoConv_Test3::convert(SString &in, MultiMap *map, bool using_checkpoints) { SString dst; const char* src = in.c_str(); const char* t; int insideneuron = 0; int n; for (t = src; *t; t++) { if (insideneuron && *t == ']') insideneuron = 0; if (*t == '[') insideneuron = 1; if ((!insideneuron) && isdigit(*t) && t[1]) { // special sequence detected! n = *t - '0'; t++; // *t will be repeated 'n' times for (int i = 0; i < n; i++) dst += *t; if (map) // fill in the map only if requested map->add(t - src, t - src, dst.length() - n, dst.length() - 1); // meaning: source character (t-src) becomes (dst.len()-n ... dst.len()-1) } else { dst += *t; if (map) map->add(t - src, t - src, dst.length() - 1, dst.length() - 1); // meaning: map single to single character: (t-src) into (dst.len()-1) } } return dst; } /// Sample Geno converter producing "f0s" genotype from the textual list of shapes, eg. "/*shapes*/ball,cube,cube" class GenoConv_Test4 : public GenoConverter { public: GenoConv_Test4() { name = "Test Converter #4"; in_format = "shapes"; out_format = "0s"; mapsupport = 1; } SString convert(SString &in, MultiMap *map, bool using_checkpoints); ~GenoConv_Test4() {} }; SString GenoConv_Test4::convert(SString &in, MultiMap *map, bool using_checkpoints) { SString result; int numparts=0; int input_pos=0, prev_input_pos=0; SString word; while(in.getNextToken(input_pos,word,',')) { Part::Shape sh; if (word=="cube") sh = Part::SHAPE_CUBOID; else if (word=="ball") sh = Part::SHAPE_ELLIPSOID; else if (word=="cylinder") sh = Part::SHAPE_CYLINDER; else return ""; SString add; add+=SString::sprintf("p:x=%g,sh=%d\n",numparts*2.0f,sh); if (numparts>0) add+=SString::sprintf("j:p1=%d,p2=%d,sh=1\n",numparts-1,numparts); if (map) // fill in the map only if requested map->add(prev_input_pos, prev_input_pos+word.length()-1, result.length(),result.length()+add.length()-1); result+=add; numparts++; prev_input_pos = input_pos; } return result; } /////////////////////////////////////////////// void printGen(Geno &g) { printf("Genotype:\n%s\nFormat: %s\nValid: %s\nComment: %s\n", g.getGenes().c_str(), g.getFormat().c_str(), g.isValid() ? "yes" : "no", g.getComment().c_str()); } static int goodWidthForFormat(const SString& genotype_format) { return Geno::formatIsOneOf(genotype_format, Geno::F0_FORMAT_LIST) ? 45 : 15; // more space for long f0 lines } // arguments: // genotype (or - meaning "read from stdin") [default: X, but try "/*shapes*/ball,cube,cylinder,cube"] // target format [default: 0] // "checkpoints" (just write this exact word) [default: not using checkpoints] int main(int argc, char *argv[]) { LoggerToStdout messages_to_stdout(LoggerBase::Enable); DefaultGenoConvManager gcm; gcm.addDefaultConverters(); gcm.addConverter(new GenoConv_Test()); gcm.addConverter(new GenoConv_Test2()); gcm.addConverter(new GenoConv_Test3()); gcm.addConverter(new GenoConv_Test4()); Geno::useConverters(&gcm); Geno::Validators validators; ModelGenoValidator model_validator; validators += &model_validator; Geno::useValidators(&validators); SString src; if (argc > 1) { src = argv[1]; if (src == "-") { StdioFILEDontClose in(stdin); src = ""; loadSString(&in, src, false); } } else src = "X"; SString dst = (argc > 2) ? argv[2] : Geno::F0_FORMAT_LIST; bool using_checkpoints = (argc > 3) ? (strcmp(argv[3], "checkpoints") == 0) : false; printf("*** Source genotype:\n"); Geno g1(src); printGen(g1); MultiMap m; Geno g2 = g1.getConverted(dst, &m, using_checkpoints); printf("*** Converted:\n"); printGen(g2); if (using_checkpoints) { // using Model with checkpoints Model m1(g2, Model::SHAPETYPE_UNKNOWN, false, true);//true=using_checkpoints printf("\nModel built from the converted f%s genotype has %d checkpoints\n", g2.getFormat().c_str(), m1.getCheckpointCount()); Model m2(g1, Model::SHAPETYPE_UNKNOWN, false, true);//true=using_checkpoints printf("Model built from the source f%s genotype has %d checkpoints\n", g1.getFormat().c_str(), m2.getCheckpointCount()); // accessing individual checkpoint models (if available) if (m1.getCheckpointCount() > 0) { int c = m1.getCheckpointCount() / 2; Model *cm = m1.getCheckpoint(c); printf("Checkpoint #%d (%d parts, %d joint, %d neurons)\n%s", c, cm->getPartCount(), cm->getJointCount(), cm->getNeuroCount(), cm->getF0Geno().getGenesAndFormat().c_str()); } } else { // there is no mapping for checkpoints so it's nothing interesting to see here in the checkpoints mode if (m.isEmpty()) printf("(conversion map not available)\n"); else { printf("Conversion map:\n"); m.print(); printConvMap(g1.getGenes(), g2.getGenes(), m, goodWidthForFormat(g1.getFormat())); printf("Reverse conversion map:\n"); MultiMap rm; rm.addReversed(m); rm.print(); printConvMap(g2.getGenes(), g1.getGenes(), rm, goodWidthForFormat(g2.getFormat())); } Model mod1(g1, Model::SHAPETYPE_UNKNOWN, 1); printf("\nModel map for f%s genotype:\n", g1.getFormat().c_str()); ModelDisplayMap dm1(mod1); dm1.print(goodWidthForFormat(g1.getFormat())); MultiMap mod1combined; mod1combined.addCombined(mod1.getMap(), dm1.getMap()); mod1combined.print(); Model mod2(g2, Model::SHAPETYPE_UNKNOWN, 1); printf("\nModel map for f%s genotype:\n", g2.getFormat().c_str()); ModelDisplayMap dm2(mod2); dm2.print(goodWidthForFormat(g2.getFormat())); MultiMap mod2combined; mod2combined.addCombined(mod2.getMap(), dm2.getMap()); mod2combined.print(); } return 0; }