1 /** 2 * Copyright: © 2012-2014 Anton Gushcha 3 * License: Subject to the terms of the MIT license, as written in the included LICENSE file. 4 * Authors: NCrashed <ncrashed@gmail.com>, 5 * LeMarwin <lemarwin42@gmail.com>, 6 * Nazgull09 <nazgull90@gmail.com> 7 */ 8 module devol.individ; 9 10 import std.variant; 11 import std.array; 12 import std.random; 13 import std.conv; 14 15 import devol.serializable; 16 import devol.world; 17 18 import dyaml.all; 19 20 public 21 { 22 import devol.std.line; 23 } 24 25 interface IndAbstract 26 { 27 void initialize(WorldAbstract world); 28 @property string name(); 29 @property void name(string name); 30 31 @property Line[] program(); 32 @property void program(Line[] val); 33 @property size_t getGenomeSize(); 34 35 @property Line[] memory(); 36 37 @property double fitness(); 38 @property void fitness(double val); 39 40 @property Line[] invals(); 41 @property Line[] outvals(); 42 @property void invals(Line[] val); 43 @property void outvals(Line[] val); 44 45 @property IndAbstract dup(); 46 47 @property string programString(); 48 49 Node saveYaml(); 50 51 string genDot(); 52 } 53 54 class Individ : IndAbstract, ISerializable 55 { 56 this() 57 { 58 mProgram = new Line[0]; 59 mMemory = new Line[0]; 60 mName = autogenName(); 61 } 62 63 private string autogenName() 64 { 65 enum alphabet = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; 66 size_t length = uniform!"[]"(5,8); 67 auto builder = appender!string; 68 foreach(i; 0..length) 69 { 70 builder.put(alphabet[uniform(0, alphabet.length)]); 71 } 72 return builder.data; 73 } 74 75 @property string name() 76 { 77 return mName; 78 } 79 80 @property void name(string name) 81 { 82 mName = name; 83 } 84 85 this(Individ ind) 86 { 87 this(); 88 loadFrom(ind); 89 } 90 91 void loadFrom(Individ ind) 92 { 93 this.program = ind.program; 94 this.memory = ind.memory; 95 this.invals = ind.invals; 96 this.outvals = ind.outvals; 97 this.fitness = ind.fitness; 98 } 99 100 @property Line[] program() 101 { 102 return mProgram; 103 } 104 105 size_t getGenomeSize() 106 { 107 size_t genome; 108 foreach(line; mProgram) 109 { 110 genome += line.leafs; 111 } 112 return genome; 113 } 114 115 @property Line[] memory() 116 { 117 return mMemory; 118 } 119 120 @property void memory(Line[] val) 121 { 122 mMemory = val; 123 } 124 125 @property void program(Line[] val) 126 { 127 mProgram = val; 128 } 129 130 @property string programString() 131 { 132 auto s = ""; 133 foreach( line; mProgram ) 134 { 135 s ~= line.tostring ~ "\n"; 136 } 137 return s; 138 } 139 140 @property string memoryString() 141 { 142 auto s = ""; 143 foreach( line; mMemory ) 144 { 145 s ~= line.tostring ~ "/0x0A"; 146 } 147 return s; 148 } 149 150 151 @property double fitness() 152 { 153 return mFitness; 154 } 155 156 @property void fitness(double val) 157 { 158 mFitness = val; 159 } 160 161 @property Line[] invals() 162 { 163 return inVals; 164 } 165 166 @property Line[] outvals() 167 { 168 return outVals; 169 } 170 171 @property void invals(Line[] val) 172 { 173 inVals = val; 174 } 175 176 @property void outvals(Line[] val) 177 { 178 outVals = val; 179 } 180 181 @property Individ dup() 182 { 183 auto ind = new Individ(); 184 foreach(line; mProgram) 185 ind.mProgram ~= line.dup; 186 foreach(line; mMemory) 187 ind.mMemory ~= line.dup; 188 foreach(line; inVals) 189 ind.inVals ~= line.dup; 190 foreach(line; outVals) 191 ind.outVals ~= line.dup; 192 return ind; 193 } 194 195 void initialize(WorldAbstract world) {} 196 197 void saveBinary(OutputStream stream) 198 { 199 stream.write(cast(ulong)mProgram.length); 200 foreach(line; mProgram) 201 { 202 line.saveBinary(stream); 203 } 204 205 stream.write(cast(ulong)mMemory.length); 206 foreach(line; mMemory) 207 { 208 line.saveBinary(stream); 209 } 210 211 stream.write(cast(ulong)inVals.length); 212 foreach(line; inVals) 213 { 214 line.saveBinary(stream); 215 } 216 217 stream.write(cast(ulong)outVals.length); 218 foreach(line; outVals) 219 { 220 line.saveBinary(stream); 221 } 222 223 stream.write(mFitness); 224 stream.write(mName); 225 } 226 227 Node saveYaml() 228 { 229 auto map = ["name": Node(name), 230 "fitness": Node(fitness)]; 231 232 auto programBuilder = appender!(Node[]); 233 foreach(line; mProgram) 234 { 235 programBuilder.put(line.saveYaml); 236 } 237 if(programBuilder.data.length > 0) 238 { 239 map["program"] = Node(programBuilder.data); 240 } 241 242 auto memoryBuilder = appender!(Node[]); 243 foreach(line; mMemory) 244 { 245 memoryBuilder.put(line.saveYaml); 246 } 247 if(memoryBuilder.data.length > 0) 248 { 249 map["memory"] = Node(memoryBuilder.data); 250 } 251 252 auto invalsBuilder = appender!(Node[]); 253 foreach(line; inVals) 254 { 255 invalsBuilder.put(line.saveYaml); 256 } 257 if(invalsBuilder.data.length > 0) 258 { 259 map["invals"] = Node(invalsBuilder.data); 260 } 261 262 auto outvalsBuilder = appender!(Node[]); 263 foreach(line; outVals) 264 { 265 outvalsBuilder.put(line.saveYaml); 266 } 267 if(outvalsBuilder.data.length > 0) 268 { 269 map["outvals"] = Node(outvalsBuilder.data); 270 } 271 272 return Node(map); 273 } 274 275 static Individ loadBinary(InputStream stream) 276 { 277 Line[] loadLineArray(size_t length) 278 { 279 auto builder = appender!(Line[]); 280 foreach(i; 0..length) 281 { 282 char[] mark; 283 stream.read(mark); 284 assert(mark.idup == "line", "Mark is "~mark.idup); 285 286 auto line = Line.loadBinary(stream); 287 builder.put(line); 288 } 289 return builder.data; 290 } 291 292 auto ind = new Individ; 293 294 ulong programLength; 295 stream.read(programLength); 296 ind.mProgram = loadLineArray(cast(size_t)programLength); 297 298 ulong memoryLength; 299 stream.read(memoryLength); 300 ind.mMemory = loadLineArray(cast(size_t)memoryLength); 301 302 ulong inValsLength; 303 stream.read(inValsLength); 304 ind.inVals = loadLineArray(cast(size_t)inValsLength); 305 306 ulong outValsLength; 307 stream.read(outValsLength); 308 ind.outVals = loadLineArray(cast(size_t)outValsLength); 309 310 stream.read(ind.mFitness); 311 char[] buff; 312 stream.read(buff); 313 ind.mName = buff.idup; 314 315 return ind; 316 } 317 318 static Individ loadYaml(Node node) 319 { 320 auto ind = new Individ; 321 322 ind.mName = node["name"].as!string; 323 ind.mFitness = node["fitness"].as!double; 324 325 auto builder = appender!(Line[]); 326 if(node.containsKey("program")) 327 { 328 foreach(Node subnode; node["program"]) 329 { 330 builder.put(Line.loadYaml(subnode)); 331 } 332 } 333 ind.mProgram = builder.data; 334 335 builder = appender!(Line[]); 336 if(node.containsKey("memory")) 337 { 338 foreach(Node subnode; node["memory"]) 339 { 340 builder.put(Line.loadYaml(subnode)); 341 } 342 } 343 ind.mMemory = builder.data; 344 345 builder = appender!(Line[]); 346 if(node.containsKey("invals")) 347 { 348 foreach(Node subnode; node["invals"]) 349 { 350 builder.put(Line.loadYaml(subnode)); 351 } 352 } 353 ind.inVals = builder.data; 354 355 builder = appender!(Line[]); 356 if(node.containsKey("outvals")) 357 { 358 foreach(Node subnode; node["outvals"]) 359 { 360 builder.put(Line.loadYaml(subnode)); 361 } 362 } 363 ind.outVals = builder.data; 364 365 return ind; 366 } 367 368 string genDot() 369 { 370 size_t nameIndex = 0; 371 auto builder = appender!string; 372 373 builder.put("digraph \""); 374 builder.put(mName); 375 builder.put("\" {\n"); 376 377 string nodeName = "p"~to!string(nameIndex++); 378 379 builder.put(nodeName); 380 builder.put("; \n"); 381 382 builder.put(nodeName); 383 builder.put("[label=\""); 384 builder.put("root"); 385 builder.put("\"] ;\n"); 386 387 foreach(line; mProgram) 388 { 389 string lineNode; 390 builder.put(line.genDot(nameIndex, lineNode)); 391 392 builder.put(nodeName); 393 builder.put(" -> "); 394 builder.put(lineNode); 395 builder.put(";\n"); 396 } 397 398 builder.put("}\n"); 399 return builder.data; 400 } 401 402 protected 403 { 404 Line[] mProgram; 405 Line[] mMemory; 406 407 Line[] inVals; 408 Line[] outVals; 409 410 double mFitness; 411 string mName; 412 } 413 }