1 
2 /* "Species" - a CoreWars evolver.  Copyright (C) 2003 'Varfar'
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 1, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #include "reproduction.hpp"
20 #include "species.hpp"
21 #include "rand.hpp"
22 #include "opcode_branch_lookup.hpp"
23 using namespace std;
24 
25 namespace { // anon
26 
27 	const bool FITNESS_BIAS_DEFAULT = false; // a bit of backwards compatibility
28 	const bool ADJUST_ADDRESSING_DEFAULT = true;
29 
30 	// this is a YACE style dummy warrior to be killed by an evolving candidate, just to check the evolving candidate has _some_ teeth
31 	warrior_t runtest_dummy;
32 	bool runtest_dummy_flag = false; // need to create the runtest_dummy?
33 
34 /*	void randomInstruction(CWarrior &warrior,const int index) {
35 		warrior.code[index].in = OP(warrior.species()->freq()->get_random_opcode(warrior,index),CRand::irand(MODIFIER_LAST),CRand::irand(ADDRMODE_LAST),CRand::irand(ADDRMODE_LAST));
36 		warrior.code[index].a = warrior.operands()->rnd();
37 		warrior.code[index].b = warrior.operands()->rnd();
38 	} */
39 
40 	/* this check will ensure that there is a SPL, JMP or MOV.I between start and DAT */
loops(const CWarrior & warrior)41 	bool loops(const CWarrior &warrior) {
42 		unsigned int i;
43 		for(i=warrior.start_idx(); i<warrior.len(); i++) {
44 			switch(warrior.code(i).opcode()) {
45 				// oh no, dead!
46 				case DAT:
47 					return false;
48 				// instructions that (might) loop
49 				case SPL:
50 				case DJN:
51 				case JMZ:
52 				case JMN:
53 				case JMP:
54 					// could check for bad indirects?
55 					// could discourage JMP-0?
56 					return true;
57 				// possible imp?
58 				case MOV:
59 					// check it is a .I
60 					if(mI == warrior.code(i).modifier())
61 						return true;
62 					// could check for bad indirects?
63 				// else continue to next instruction
64 				default:
65 					break;
66 			}
67 		}
68 		// if here, doesn't loop
69 		return false;
70 	}
71 
72 	/* this check will run the warrior for a short time in a mars to see if it commits suicide */
runtest(const CWarrior & warrior)73 	bool runtest(const CWarrior &warrior) {
74 		const char *RUNTEST_DUMMY_FILENAME = "runtest_dummy.rc";
75 		const unsigned int
76 			RUNTEST_DUMMY_LEN = 12,
77 			RUNTEST_DUMMY_POS = warrior.kingdom()->coresize() >> 1;
78 		unsigned int i;
79 		if(!runtest_dummy_flag) {
80 /*			// header
81 			runtest_dummy.start=1;
82 			runtest_dummy.len = RUNTEST_DUMMY_LEN;
83 			// a djnstream-resistant bit
84 			i=0;
85 			runtest_dummy.code[i].in = OP(JMP, mF, IMMEDIATE, DIRECT); // a jmp #n is a wimp
86 			runtest_dummy.code[i].a = 5 + i; // some colour
87 			runtest_dummy.code[i].b = 10 + i; // some colour
88 			// body
89 			for(i=1; i<(RUNTEST_DUMMY_LEN-1); i++) {
90 				runtest_dummy.code[i].in = OP(NOP, mF, DIRECT, DIRECT);
91 				runtest_dummy.code[i].a = 5 + i; // some colour
92 				runtest_dummy.code[i].b = 10 + i; // some colour
93 			}
94 			// loop back to beginning
95 			i = RUNTEST_DUMMY_LEN-1;
96 			runtest_dummy.code[i].in = OP(JMP, mF, DIRECT, DIRECT);
97 			runtest_dummy.code[i].a = warrior.kingdom()->coresize()-runtest_dummy.len+2; // loop
98 			runtest_dummy.code[i].b = 10 + i; // some colour
99 			// done
100 			//discore(runtest_dummy.code,0,runtest_dummy.len,warrior.kingdom()->coresize());/* and print to stdout. */
101 			cout << "loading dynamic runtest dummy \"" << RUNTEST_DUMMY_FILENAME << "\".." << endl;
102 			asm_fname(RUNTEST_DUMMY_FILENAME,&runtest_dummy,warrior.kingdom()->coresize());
103 			runtest_dummy_flag = true;
104 		}
105 		sim_clear_core();
106 		sim_reset_pspaces();
107 		warrior.load(0);
108 		sim_load_warrior(RUNTEST_DUMMY_POS,&(runtest_dummy.code[0]),runtest_dummy.len);
109 		warrior.kingdom()->core_check();
110 		switch(sim(2,warrior.start_idx(),RUNTEST_DUMMY_POS+runtest_dummy.start,warrior.kingdom()->cycles(),0)) {
111 			case  0: // warrior won
112 				return true;
113 			case 1: // runtest_dummy won
114 			case 2: // tie
115 				return false;
116 			case -1:
117 			default:
118 				PANIC(MARS,"runtest","critical mars error");
119 		}
120 		return false; // hmm, dumb compiler
121 	}
122 
123 } // anon namespace
124 
125 /***** CReproduction class implementation *************/
126 
127 const char
128 	*CReproduction::MUTATION_DESCS[CReproduction::MUTATION_LAST] = {
129 		"mutation_none","mutation_opcode","mutation_modifier","mutation_addrmode_a","mutation_addrmode_b","mutation_operand_a","mutation_operand_b"},
130 	*CReproduction::RANDOM_COMPONENT_DESCS[CReproduction::RANDOM_COMPONENT_LAST] = {
131 		"random_none","random_crossover","random_insert","random_replace","random_delete"},
132 	*CReproduction::CROSSOVER_DESCS[CReproduction::CROSSOVER_LAST] = {
133 		"random"};
134 
CReproduction()135 CReproduction::CReproduction() {
136 	// at first, mutation is 0 (100% of mutation is in _mutation[NONE])
137 	int i;
138 	_crossover = CROSSOVER_RANDOM;
139 	for(i=0; i<MUTATION_LAST; ++i)
140 		_mutation[(MUTATION)i] = 0.0F;
141 	for(i=0; i<RANDOM_COMPONENT_LAST; ++i)
142 		_crossover_random[(RANDOM_COMPONENT)i] = 0.0F;
143 	_mutation[MUT_NONE] = 1.0F;
144 	_mutation_sum = _mutation[MUT_NONE];
145 	_survive = 1.0F; // never
146 	_dat_padding = 0.0F; // never
147 	_fitness_bias = FITNESS_BIAS_DEFAULT;
148 	_adjust_addressing = ADJUST_ADDRESSING_DEFAULT;
149 }
150 
read_ini(INIFile & ini)151 void CReproduction::read_ini(INIFile &ini) {
152 	KeyValuePair *kvp;
153 	int i;
154 	// crossover
155 	kvp = ini.get("crossover"); if(0 == kvp) PANIC(MISC,"crossover expected",NULL);
156 	_crossover = crossover(kvp->getValueAsChar());
157 	// crossover-type-specific vars
158 	switch(_crossover) {
159 		case CROSSOVER_RANDOM:
160 			_crossover_random_sum = 0.0F;
161 			for(i=0; i<RANDOM_COMPONENT_LAST; i++) {
162 				kvp = ini.get(random_component_desc((RANDOM_COMPONENT)i)); if(0 == kvp) PANIC(MISC,random_component_desc((RANDOM_COMPONENT)i)," expected");
163 				_crossover_random[(RANDOM_COMPONENT)i] = kvp->getValueAsFloat();
164 				if(0.0F > _crossover_random[(RANDOM_COMPONENT)i]) PANIC(MISC,random_component_desc((RANDOM_COMPONENT)i)," cannot be negative");
165 				_crossover_random_sum += _crossover_random[(RANDOM_COMPONENT)i];
166 			}
167 			if(0.0F >= _crossover_random_sum) PANIC(MISC,"sum of random crossover components cannot be negative nor zero",NULL);
168 			kvp = ini.get("adjust_addressing");
169 			if(0 != kvp) { // specified?
170 				_adjust_addressing = kvp->getValueAsBool(ADJUST_ADDRESSING_DEFAULT);
171 			}
172 			break;
173 		default:
174 			PANIC(MISC,"bad crossover type",NULL);
175 	}
176 	// survive
177 	kvp = ini.get("survive"); if(0 == kvp) PANIC(MISC,"survive expected",NULL);
178 	_survive = kvp->getValueAsFloat();
179 	if((0.0F > _survive) || (_survive >= 1.0F))
180 		PANIC(MISC,"survive must be between 0 and 1",NULL);
181 	// mutation
182 	for(i=0; i<MUTATION_LAST; ++i) {
183 		kvp = ini.get(mutation_desc((MUTATION)i)); if(0 == kvp) PANIC(MISC,mutation_desc((MUTATION)i)," expected");
184 		_mutation_sum -= _mutation[(MUTATION)i];
185 		_mutation[(MUTATION)i] = kvp->getValueAsFloat();
186 		if(_mutation[(MUTATION)i] < 0.0F)
187 			PANIC(MISC,mutation_desc((MUTATION)i),"must be >= 0");
188 		_mutation_sum += _mutation[(MUTATION)i];
189 	}
190 	if(_mutation_sum <= 0.0F)
191 		PANIC(MISC,"sum mutation rate is invalid",NULL);
192 }
193 
read_override_ini(INIFile & ini)194 CReproduction *CReproduction::read_override_ini(INIFile &ini) /* loads values; if any values are
195 	specified, then a copy of this reproduction will be made; all unspecified values in the new
196 	class will be "inherited" from this one, and any specified values will be overriden.  If nothing
197 	is specified, then this will be returned */ {
198 	CReproduction *ret = this;
199 	KeyValuePair *kvp;
200 	int i;
201 	// crossover
202 	kvp = ini.get("crossover");
203 	if(0 != kvp) { // specified? override then
204 		if(!kvp->isValue(crossover_desc(_crossover))) { // different?
205 			ret = new CReproduction(*this); // create a copy to return
206 			ret->_crossover = crossover(kvp->getValueAsChar());
207 		}
208 	}
209 	// get crossover-type-specific vars
210 	switch(ret->_crossover) {
211 		case CROSSOVER_RANDOM:
212 			for(i=0; i<RANDOM_COMPONENT_LAST; i++) {
213 				kvp = ini.get(random_component_desc((RANDOM_COMPONENT)i));
214 				if(0 != kvp) { // specified?  override then
215 					if(this == ret) { // nothing previously overriden?
216 						ret = new CReproduction(*this); // create a copy to return
217 						if(_crossover != ret->_crossover) {
218 							ret->_crossover_random_sum = 0.0F;
219 							for(int j=0; j<RANDOM_COMPONENT_LAST; j++)
220 								ret->_crossover_random[(RANDOM_COMPONENT)j] = 0.0F;
221 						}
222 					}
223 					ret->_crossover_random_sum -= ret->_crossover_random[(RANDOM_COMPONENT)i];
224 					ret->_crossover_random[(RANDOM_COMPONENT)i] = kvp->getValueAsFloat();
225 					ret->_crossover_random_sum += ret->_crossover_random[(RANDOM_COMPONENT)i];
226 					if(0.0F > _crossover_random[(RANDOM_COMPONENT)i])
227 						PANIC(MISC,random_component_desc((RANDOM_COMPONENT)i)," cannot be negative");
228 				}
229 			}
230 			kvp = ini.get("adjust_addressing");
231 			if(0 != kvp) { // set?
232 				if(kvp->getValueAsBool(ret->_adjust_addressing) != ret->_adjust_addressing) { // changed?
233 					if(this == ret) { // nothing previously overriden?
234 						ret = new CReproduction(*this); // create a copy to return
235 					}
236 					ret->_adjust_addressing = !ret->_adjust_addressing; // and toggle it
237 				}
238 			}
239 			break;
240 		default:
241 			PANIC(MISC,"bad crossover type",NULL);
242 	}
243 	// survive
244 	kvp = ini.get("survive");
245 	if(0 != kvp) { // specified?  override then
246 		if(this == ret) // crossover not already overriden?
247 			ret = new CReproduction(*this); // create a copy to return
248 		ret->_survive = kvp->getValueAsFloat();
249 		if((0.0F > _survive) || (_survive >= 1.0F))
250 			PANIC(MISC,"survive must be between 0 and 1",NULL);
251 	}
252 	// mutation
253 	for(i=0; i<MUTATION_LAST; ++i) {
254 		kvp = ini.get(mutation_desc((MUTATION)i));
255 		if(0 != kvp) { // specified?
256 			if(this == ret) { // crossover wasn't override?
257 				ret = new CReproduction(*this); // create a copy to return
258 			}
259 			ret->_mutation_sum -= ret->_mutation[(MUTATION)i];
260 			ret->_mutation[(MUTATION)i] = kvp->getValueAsFloat();
261 			if(ret->_mutation[(MUTATION)i] < 0.0F)
262 				PANIC(MISC,mutation_desc((MUTATION)i),"must be >= 0");
263 			ret->_mutation_sum += ret->_mutation[(MUTATION)i];
264 		}
265 	}
266 	if(ret->_mutation_sum <= 0.0F)
267 		PANIC(MISC,"sum mutation rate is invalid",NULL);
268 	// done
269 	return ret;
270 }
271 
write_ini(ostream & os)272 void CReproduction::write_ini(ostream &os) {
273 	int i;
274 	os << "crossover=" << crossover_desc(_crossover) << endl;
275 	// crossover type specific vars
276 	switch(_crossover) {
277 		case CROSSOVER_RANDOM:
278 			for(i=0; i<RANDOM_COMPONENT_LAST; i++) {
279 				os << random_component_desc((RANDOM_COMPONENT)i) << "=" << _crossover_random[(RANDOM_COMPONENT)i] << endl;
280 			}
281 			if(ADJUST_ADDRESSING_DEFAULT != _adjust_addressing) {
282 				os << "adjust_addressing=" << _adjust_addressing << endl;
283 			}
284 			break;
285 		default:
286 			PANIC(MISC,"bad crossover type",NULL);
287 	}
288 	os << "survive=" << _survive << endl;
289 	for(i=0; i<MUTATION_LAST; ++i) {
290 		os << mutation_desc((MUTATION)i) << '=' << _mutation[(MUTATION)i] << endl;
291 	}
292 }
293 
write_override_ini(ostream & os,const CReproduction * parent)294 void CReproduction::write_override_ini(ostream &os,const CReproduction *parent) {
295 	int i;
296 	if(this == parent) // not overriden?
297 		return;
298 	// crossover
299 	if(parent->_crossover != _crossover) {
300 		os << "crossover=" << crossover_desc(_crossover) << endl;
301 	}
302 	// crossover-type-specific vars
303 	switch(_crossover) {
304 		case CROSSOVER_RANDOM:
305 			for(i=0; i<RANDOM_COMPONENT_LAST; i++) {
306 				if((parent->_crossover != _crossover) || (parent->_crossover_random[(RANDOM_COMPONENT)i] != _crossover_random[(RANDOM_COMPONENT)i])) {
307 					os << random_component_desc((RANDOM_COMPONENT)i) << "=" << _crossover_random[(RANDOM_COMPONENT)i] << endl;
308 				}
309 			}
310 			if(parent->_adjust_addressing != _adjust_addressing) {
311 				os << "adjust_addressing=" << _adjust_addressing << endl;
312 			}
313 			break;
314 		default:
315 			PANIC(MISC,"bad crossover type",NULL);
316 	}
317 	// survive
318 	if(parent->_survive != _survive) {
319 		os << "survive=" << _survive << endl;
320 	}
321 	// mutation
322 	for(i=0; i<MUTATION_LAST; ++i) {
323 		if(parent->_mutation[(MUTATION)i] != _mutation[(MUTATION)i]) {
324 			os << mutation_desc((MUTATION)i) << '=' << _mutation[(MUTATION)i] << endl;
325 		}
326 	}
327 }
328 
crossover_random() const329 CReproduction::RANDOM_COMPONENT CReproduction::crossover_random() const { // should there be something? prob controlled by _crossover_random[]
330 	const NUM x = CRand::frand(_crossover_random_sum);
331 	NUM y = 0.0F;
332 	do {
333 		for(int i=0; i<RANDOM_COMPONENT_LAST; i++) {
334 			y += _crossover_random[(RANDOM_COMPONENT)i];
335 			if(y > x) // found it?
336 				return (RANDOM_COMPONENT)i;
337 		}
338 		cerr << "WARNING: roulette past end in CReproduction:crossover_random()" << endl;
339 	} while(true);
340 }
341 
survive() const342 bool CReproduction::survive() const { // should a member of the current generation survive? prob controlled by _survive
343 	return (CRand::frand(1.0F) <= _survive);  // _survive is a percenhooke
344 }
345 
mutation() const346 CReproduction::MUTATION CReproduction::mutation() const { // should there be mutation? prob controlled by _entropy
347 	const NUM x = CRand::frand(_mutation_sum);
348 	NUM y = 0.0F;
349 	int i;
350 	do {
351 		for(i=0; i<MUTATION_LAST; ++i) {
352 			y += _mutation[(MUTATION)i];
353 			if(y > x) { // found it?
354 				return (MUTATION)i;
355 			}
356 		}
357 		cerr << "WARNING: roulette past end in CReproduction:mutation()" << endl;
358 	} while(true);
359 }
360 
361 /* generates a completely random warrior using instruction biases in genus */
generateCompletelyRandom(CChromosome & chromosome)362 void CReproduction::generateCompletelyRandom(CChromosome &chromosome) {
363 	unsigned int i;
364 	//warrior.clear_info();
365 	// random length and start
366 	chromosome.rnd_len();
367 	if(chromosome.is_start())
368 		chromosome.set_start(CRand::irand(chromosome.len()));
369 	// generate random instructions
370 	chromosome.type()->freq()->set_chromosome(&chromosome);
371 	for(i=0; i<chromosome.len(); i++) {
372 		chromosome.type()->freq()->set_chromosome_index(i);
373 		chromosome.type()->freq()->suggest_instruction(chromosome.code(i),CInstGenerator::FORWARD);
374 	}
375 }
376 
mutate(CChromosome & chromosome,const int i) const377 void CReproduction::mutate(CChromosome &chromosome,const int i) const { // apply mutation to an instruction in a gene
378 	//TODO: farm this out to CInstGen?
379 	// do mutation
380 	insn_t &in = chromosome.code(i); // easier on the eyes
381 try_again:
382 	switch(mutation()) {
383 		case CReproduction::MUT_OPCODE:
384 			in.set_opcode((OPCODE)CRand::irand(MODIFIER_LAST));
385 			break;
386 		case CReproduction::MUT_MODIFIER:
387 			if(1 < EFFECTIVE_MODIFIERS(in.opcode())) {
388 				MODIFIER mod;
389 				do {
390 					mod = EFFECTIVE_MODIFIER(in.opcode(),(MODIFIER)CRand::irand(MODIFIER_LAST));
391 				} while(in.modifier() == mod);
392 				in.set_modifier(mod);
393 			} else
394 				goto try_again;
395 			break;
396 		case CReproduction::MUT_ADDRMODE_A:
397 			in.set_addrmode_a((ADDRMODE)CRand::irand(ADDRMODE_LAST));
398 			break;
399 		case CReproduction::MUT_OPERAND_A:
400 			chromosome.type()->operands()->rnd(in,COperand::A);
401 			break;
402 		case CReproduction::MUT_ADDRMODE_B:
403 			in.set_addrmode_b((ADDRMODE)CRand::irand(ADDRMODE_LAST));
404 			break;
405 		case CReproduction::MUT_OPERAND_B:
406 			chromosome.type()->operands()->rnd(in,COperand::B);
407 			break;
408 		case CReproduction::MUT_NONE: // drop through
409 		default:
410 			break;
411 	}
412 	// checks?
413 	if(safety_checks) {
414 		if(!chromosome.code(i).valid(chromosome.type()->species()->kingdom()->coresize()))
415 			PANIC(MISC,"bad instruction",NULL);
416 	}
417 }
418 
419 /* generates a new chromosome based upon two parents; despite the param naming, warriors are not sexed.
420    chromosome stub must have been created (but contents are wiped) */
breed(CChromosome & chromosome,const CChromosome & mother,const CChromosome & father)421 void CReproduction::breed(CChromosome &chromosome,const CChromosome &mother,const CChromosome &father) {
422 	switch(_crossover) {
423 		case CROSSOVER_RANDOM:
424 			breed_random(chromosome,mother,father);
425 			return;
426 	}
427 	PANIC(MISC,"bad crossover",NULL);
428 }
429 
fit_enough(CWarrior & warrior)430 bool CReproduction::fit_enough(CWarrior &warrior) {
431 	// do checks
432 	if(!loops(warrior))
433 		return false;
434 	if(!runtest(warrior))
435 		return false;
436 	// if here, ok
437 	return true;
438 }
439 
440 namespace { // anon
441 
copy_instruction(CChromosome & chromosome,const int chromosome_idx,const CChromosome & parent,const int parent_idx,const field_t ajdustment,const field_t coresize)442 	void copy_instruction(CChromosome &chromosome,const int chromosome_idx,const CChromosome &parent,const int parent_idx,const field_t ajdustment,const field_t coresize) {
443 		insn_t &dest = chromosome.code(chromosome_idx);
444 		if(parent.len() > parent_idx) { // not off the end?
445 			const insn_t &src = parent.code(parent_idx);
446 			dest.in = src.in;
447 			dest.a = src.a;
448 			if(dest.a < chromosome_idx) { // need ajustment?
449 				dest.a += ajdustment;
450 				while(coresize <= dest.a) // fold?
451 					dest.a -= coresize;
452 			}
453 			dest.b = src.b;
454 			if(dest.b < chromosome_idx) { // need ajustment?
455 				dest.b += ajdustment;
456 				while(coresize <= dest.b) // fold?
457 					dest.b -= coresize;
458 			}
459 			if(parent_idx == parent.start())
460 				chromosome.set_start(chromosome_idx);
461 		} else { // off the end then
462 			chromosome.type()->freq()->set_chromosome_index(chromosome_idx);
463 			chromosome.type()->freq()->suggest_instruction(dest,CInstGenerator::FORWARD);
464 		}
465 	}
466 
adjust_addressing_before(CChromosome & chromosome,const int current,const field_t coresize)467 	void adjust_addressing_before(CChromosome &chromosome,const int current,const field_t coresize) {
468 		for(int i=0; i<current; i++) {
469 			if((chromosome.code(i).a >= current) && (chromosome.code(i).a < chromosome.len())) {
470 				if(coresize == ++chromosome.code(i).a) // inc, possibly fold?
471 					chromosome.code(i).a = 0;
472 
473 			}
474 			if((chromosome.code(i).b >= current) && (chromosome.code(i).b < chromosome.len())) {
475 				if(coresize == ++chromosome.code(i).b) // inc, possibly fold?
476 					chromosome.code(i).b = 0;
477 			}
478 		}
479 	}
480 
481 } // anon namespace
482 
breed_random(CChromosome & chromosome,const CChromosome & mother,const CChromosome & father)483 void CReproduction::breed_random(CChromosome &chromosome,const CChromosome &mother,const CChromosome &father) {
484 	unsigned int i;
485 	bool parent_mother = true; // start with mother
486 	const field_t coresize = chromosome.type()->species()->kingdom()->coresize(); // cache it
487 	const CChromosome *parent = &mother;
488 	string &info = chromosome.info(); // straighter code
489 	info = "";
490 	// random length and start
491 	chromosome.rnd_len(); // a random length within bounds
492 	if(chromosome.is_start())
493 		chromosome.set_start(CRand::irand(chromosome.len())); // a default, might be inherited from parent
494 	// generate instructions
495 	chromosome.type()->freq()->set_chromosome(&chromosome);
496 	chromosome.clear();
497 	int cursor = 0, adjustment = 0;
498 	bool next = false;
499 	RANDOM_COMPONENT rnd = crossover_random();
500 	for(i=0; i<chromosome.len();) {
501 		switch(rnd) { // do crossover
502 			case RND_NONE:
503 				info += 'c';
504 				copy_instruction(chromosome,i,*parent,cursor,adjustment,coresize);
505 				cursor++;
506 				next = true;
507 				break;
508 			case RND_CROSSOVER:
509 				info += 'x';
510 				parent_mother = !parent_mother;
511 				parent = (parent_mother ? &mother: &father);
512 				rnd = RND_NONE;
513 				break;
514 			case RND_INSERT:
515 				info += 'i';
516 				if(0 == i) {
517 					rnd = RND_NONE;
518 					break;
519 				} else if(i < (chromosome.len()-1)) { // room?
520 					if(_adjust_addressing) adjustment++;
521 					chromosome.code(i).set_clear();
522 					copy_instruction(chromosome,i+1,*parent,cursor,adjustment,coresize);
523 					if(_adjust_addressing) adjust_addressing_before(chromosome,i,coresize);
524 					chromosome.type()->freq()->set_chromosome_index(i);
525 					chromosome.type()->freq()->suggest_instruction(chromosome.code(i),CInstGenerator::INSERT);
526 					cursor++;
527 					i++;
528 				} else {
529 					chromosome.type()->freq()->set_chromosome_index(i);
530 					chromosome.type()->freq()->suggest_instruction(chromosome.code(i),CInstGenerator::FORWARD);
531 				}
532 				next = true;
533 				break;
534 			case RND_REPLACE:
535 				info += 'r';
536 				if(0 == i) {
537 					rnd = RND_NONE;
538 					break;
539 				} else if(i < (chromosome.len()-1)) { // room?
540 					chromosome.code(i).set_clear();
541 					copy_instruction(chromosome,i+1,*parent,cursor+1,adjustment,coresize);
542 					chromosome.type()->freq()->set_chromosome_index(i);
543 					chromosome.type()->freq()->suggest_instruction(chromosome.code(i),CInstGenerator::INSERT);
544 					cursor++;
545 					i++;
546 				} else {
547 					chromosome.type()->freq()->set_chromosome_index(i);
548 					chromosome.type()->freq()->suggest_instruction(chromosome.code(i),CInstGenerator::FORWARD);
549 				}
550 				cursor++;
551 				next = true;
552 				break;
553 			case RND_DELETE:
554 				info += 'd';
555 				cursor++;
556 				if(0 < adjustment)
557 					adjustment--;
558 				rnd = RND_NONE;
559 				break;
560 			default:
561 				PANIC(MISC,"bad RANDOM_COMPONENT",NULL);
562 		}
563 		if(next) {
564 			mutate(chromosome,i);
565 			i++;
566 			rnd = crossover_random();
567 			next = false;
568 		}
569 	}
570 	// set info
571 	if(safety_checks)
572 		chromosome.check(coresize);
573 }
574 
mutation_desc(const CReproduction::MUTATION mutation)575 const char *CReproduction::mutation_desc(const CReproduction::MUTATION mutation) {
576 	if((0 <= mutation) && (mutation < MUTATION_LAST))
577 		return MUTATION_DESCS[mutation];
578 	return 0; // bad
579 }
580 
random_component_desc(const CReproduction::RANDOM_COMPONENT component)581 const char *CReproduction::random_component_desc(const CReproduction::RANDOM_COMPONENT component) {
582 	if((0 <= component) && (component < RANDOM_COMPONENT_LAST))
583 		return RANDOM_COMPONENT_DESCS[component];
584 	return 0; // bad
585 }
586 
crossover_desc(const CReproduction::CROSSOVER crossover)587 const char *CReproduction::crossover_desc(const CReproduction::CROSSOVER crossover) {
588 	if((0 <= crossover) && (crossover < CROSSOVER_LAST))
589 		return CROSSOVER_DESCS[crossover];
590 	return 0; // bad
591 }
592 
crossover(const char * desc)593 CReproduction::CROSSOVER CReproduction::crossover(const char *desc) {
594 	int i;
595 	for(i=0; i<CROSSOVER_LAST; ++i) {
596 		if(strcasecmp(desc,CROSSOVER_DESCS[(CROSSOVER)i]) == 0)
597 			return (CROSSOVER)i;
598 	}
599 	PANIC(MISC,"bad crossover type",NULL);
600 }
601