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 }