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