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.population;
9 
10 import std.stdio;
11 
12 import std.random;
13 import std.string;
14 import std.array;
15 import std.algorithm;
16 import std.conv;
17 import std.file;
18 
19 public
20 {
21 	import devol.individ;
22 }
23 
24 interface PopAbstract
25 {
26 	void genName(int size);
27 	@property string name();
28 	@property void name(string val);
29 	@property uint generation();
30 	@property void generation(uint val);
31 	@property ulong length();
32 	IndAbstract opIndex( uint i );
33 	IndAbstract[] opSlice( uint a, uint b );
34 	uint opDollar();
35 	int opApply(int delegate(ref IndAbstract) dg);
36 }
37 
38 static string getDefChars()
39 {
40 	string ret = "qwertyuiopasdfghjklzxcvbnm";
41 	return ret ~ toUpper(ret);
42 }
43 
44 alias Population!(getDefChars, Individ) StdPop;
45 
46 class Population(alias nameChecker, IndType)
47 	if ( is(typeof(nameChecker()) == string) )
48 	: PopAbstract
49 {
50 public:
51 	static int 		DefNameLength = 10;
52 	static string 	DefNameChars = getDefChars();
53 	 
54 	alias IndType IndividType;
55 	
56 	@property uint generation()
57 	{
58 		return iGeneration;
59 	}
60 	
61 	@property void generation(uint val)
62 	{
63 		//if (val < iGeneration) return;
64 		iGeneration = val;
65 	}
66 	
67 	this()
68 	{
69 		inds = new IndType[0];
70 	}
71 	
72 	this(uint size)
73 	{
74 		inds = new IndType[size];
75 		foreach( ref ind; inds)
76 		{
77 			ind = new IndType;
78 		}
79 	}
80 	
81 	void genName(int size = DefNameLength)
82 	{
83 		auto buff = new char[size];
84 		string chars = nameChecker();
85 		foreach(ref c; buff)
86 		{
87 			c = chars[uniform(0,chars.length)];
88 		}
89 		mName = buff.idup;
90 	}
91 	
92 	@property string name()
93 	{
94 		return mName;
95 	}
96 	 
97 	@property void name(string val)
98 	{
99 		string chars = nameChecker();
100 		foreach(i,c; val)
101 		{
102 			if ( chars.find(c).empty )
103 			{
104 				val = val[0..i] ~ chars[uniform(0,chars.length)] ~ val[i+1..$];
105 			}
106 		}
107 		mName = val;
108 	}
109 	
110 	@property ulong length()
111 	{
112 		return inds.length;
113 	}
114 	
115 	IndType opIndex( uint i )
116 	{
117 		return inds[i];
118 	}
119 	
120 	IndAbstract[] opSlice( uint a, uint b )
121 	{
122 		return cast(IndAbstract[])(inds[a..b]);
123 	}
124 	
125 	uint opDollar()
126 	{
127 		return cast(uint)(inds.length);
128 	}
129 	
130 	int opApply(int delegate(ref IndAbstract) dg)
131 	{
132 		int result = 0;
133 		
134 		foreach( i,ref ind; inds)
135 		{
136 			IndAbstract inda = (ind);
137 			result = dg(inda);
138 			if (result) break;
139 		}
140 		return result;
141 	}
142 	
143 	auto opBinary(string m)(IndType val)
144 		if (m == "~")
145 	{
146 		inds ~= val;
147 		return this;
148 	}
149 	
150 	void addIndivid(IndType val)
151 	{
152 		if (val is null) return;
153 		inds ~= val;
154 	}
155 	
156 	void saveBests(string filename)
157 	{
158 		if (inds.length == 0) return;
159 
160 		auto sortedInds = inds.sort!"a.fitness > b.fitness";
161 		
162 		IndType best;
163 		int k = 0;
164 		
165 		File* f;
166 		try
167 		{
168 		    mkdirRecurse(filename);
169 			f = new File(filename~mName~"_g"~to!string(iGeneration), "w");
170 		
171 			do
172 			{
173 				best = sortedInds[k++];
174 				f.writeln("Individ №", k,":");
175 				f.writeln(best.programString());
176 				f.writeln("==================================");
177 			} while( k < sortedInds.length && sortedInds[k].fitness >= best.fitness);
178 		} catch(Exception e)
179 		{
180 			writeln("FAILED TO CREATE FILE TO WRITE RESULTED INDIVIDS!!");
181 		}
182 	}
183 	
184 	void saveAll(string filename)
185 	{
186 		File* f;
187 		try
188 		{
189 		    mkdirRecurse(filename);
190 			f = new File(filename~mName~"_g"~to!string(iGeneration), "w");
191 			
192 			foreach(i,ind;inds)
193 			{
194 				f.writeln("Individ №", i,":");
195 				f.writeln(ind.programString());
196 				f.writeln("==================================");			
197 			}	
198 		} catch(Exception e)
199 		{
200 			writeln("FAILED TO CREATE FILE TO WRITE RESULTED INDIVIDS!!");
201 		}
202 	}
203 	
204 	@property auto dup()
205 	{
206 		auto ret = new Population!(nameChecker, IndType);
207 		ret.iGeneration = iGeneration;
208 		foreach(ind;inds)
209 			ret.inds ~= ind.dup;
210 		ret.mName = mName;
211 		return ret;
212 	}
213 	
214 	void clear()
215 	{
216 		inds.clear();
217 	}
218 	
219     protected
220     {
221     	uint iGeneration;
222     	IndType[] inds;
223     	string mName = "";
224     }
225 }