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 "species.hpp"
20 #include "rand.hpp"
21 
22 #include "exec_trail.hpp"
23 
24 #include <time.h>
25 
26 #include <iostream>
27 #include <fstream>
28 #include <iomanip>
29 using namespace std;
30 
31 #ifdef SHOW_PROGRESS_TWIDDLE
32 int progress = 0;
33 const char *progress_twiddle = "-\\|/";
34 #endif // ifdef SHOW_PROGRESS_TWIDDLE
35 
36 /***** CResumeFile class declaration/implementation ********/
37 
38 class CResumeFile {
39 	public:
CResumeFile(CSpecies * species)40 		CResumeFile(CSpecies *species): _species(species) {
41 			// name of this file?
42 			_name = "species-";
43 			_name += species->name();
44 			_name += "-resume.dat";
45 			_write_count = 0;
46 		}
openForRead()47 		bool openForRead() {
48 			CGeneration::NUM gen;
49 			_write_count = 0;
50 			// try to open existing file..
51 			_file.clear();
52 			_file.open(_name.c_str(),ios::in|ios::out|ios::binary);
53 			if(!_file.is_open()) return false;
54 			// check generation
55 			_file.read((char*)&gen,sizeof(gen));
56 			if(!_file.good() || (_species->kingdom()->generation() != gen)
57 				|| _file.eof()) {
58 				close();
59 				return false;
60 			}
61 			return true;
62 		}
openForWrite()63 		void openForWrite() { // write
64 			CGeneration::NUM gen = _species->kingdom()->generation();
65 			_write_count = 0;
66 			// (re)create file
67 			_file.clear();
68 			_file.open(_name.c_str(),ios::out|ios::binary);
69 			// write generation
70 			_file.write((char*)&gen,sizeof(gen));
71 			flush();
72 		}
swapFromReadToWrite()73 		void swapFromReadToWrite() {
74 			_write_count = 0;
75 			_file.clear();
76 		}
read(CWarrior::FIGHT_DATA & fight)77 		bool read(CWarrior::FIGHT_DATA &fight) {
78 			if(!_file.good())
79 				return false;
80 			_file.read((char*)&fight,sizeof(fight));
81 			return _file.good();
82 		}
write(const CWarrior::FIGHT_DATA & fight)83 		void write(const CWarrior::FIGHT_DATA &fight) {
84 			if(_file.good()) {
85 				_file.write((const char*)&fight,sizeof(fight));
86 				if(++_write_count >= WRITE_FLUSH) {
87 					flush();
88 					_write_count = 0;
89 				}
90 			}
91 		}
flush()92 		void flush() {
93 			if(_file.good()) {
94 				_file.flush();
95 			}
96 		}
close()97 		void close() {
98 			_file.close();
99 		}
100 	private:
101 		static const int WRITE_FLUSH = 15; // every n records, flush
102 		CSpecies *_species;
103 		string _name;
104 		fstream _file;
105 		int _write_count;
106 };
107 
108 
109 /***** CSpeciesFile class implementation *******************/
110 
CSpeciesFile(const string species,const CGeneration::NUM generation)111 CSpeciesFile::CSpeciesFile(const string species,const CGeneration::NUM generation) {
112 	set_filename(species,generation);
113 	open_file();
114 }
115 
CSpeciesFile(const CSpecies & species,const CGeneration::NUM generation)116 CSpeciesFile::CSpeciesFile(const CSpecies &species,const CGeneration::NUM generation) {
117 	set_filename(species.name(),generation);
118 	open_file();
119 }
120 
~CSpeciesFile()121 CSpeciesFile::~CSpeciesFile() {
122 	fclose(_f);
123 }
124 
set_filename(const string name,const CGeneration::NUM generation)125 void CSpeciesFile::set_filename(const string name,const CGeneration::NUM generation) {
126 	// build filename
127 	_filename = "species-";
128 	_filename += name;
129 	_filename += '-';
130 	string_append(_filename,generation);
131 	_filename += ".dat";
132 }
133 
open_file()134 void CSpeciesFile::open_file() {
135 	// open file
136 	_f = fopen(_filename.c_str(),"r+b");
137 	if(0 == _f) { // can't open file, probably doesn't exist?
138 		_f = fopen(_filename.c_str(),"w+b");
139 		if(0 == _f) { // couldn't create a file either
140 			PANIC(CANNOT_OPEN_GENERATION_FILE,_filename.c_str(),NULL);
141 		}
142 	}
143 }
144 
writeWarrior(const CWarrior & warrior)145 void CSpeciesFile::writeWarrior(const CWarrior &warrior) {
146 	unsigned int i, j;
147 	CFitness::NUM num;
148 	HEADER header;
149 	// prepare header
150 	header.options = HEADER::NONE;
151 	if(0 < warrior.info().length())
152 		header.options |= HEADER::HAS_INFO;
153 	if(warrior.is_benchmarked())
154 		header.options |= HEADER::HAS_BENCH;
155 	header.uid = warrior.uid();
156 	header.generation = warrior.generation();
157 	header.mother = warrior.mother();
158 	header.father = warrior.father();
159 	header.start = warrior.start_idx();
160 	header.num_chromosomes = warrior.species()->num_chromosomes();
161 	// write header
162 	if(1 != fwrite(&header,_header_size,1,_f))
163 		PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write header");
164 	// write optional parts
165 	if(HEADER::HAS_INFO == (header.options & HEADER::HAS_INFO)) {
166 		i = warrior.info().length()+1; // remember space for \0
167 		if(MAX_INFO_LEN <= i)
168 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"info length too long");
169 		if(1 != fwrite(&i,sizeof(i),1,_f))
170 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write info length");
171 		if(i != fwrite(warrior.info().c_str(),1,i,_f))
172 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write info");
173 	}
174 	if(HEADER::HAS_BENCH == (header.options & HEADER::HAS_BENCH)) {
175 		i = warrior.benchmark_count();
176 		if(1 != fwrite(&i,sizeof(i),1,_f))
177 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write benchmark_count");
178 		num = warrior.benchmark();
179 		if(1 != fwrite(&num,sizeof(num),1,_f))
180 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write benchmark");
181 	}
182 	// write body
183 	for(i=0; i<header.num_chromosomes; ++i) {
184 		CChromosome &chromosome = *warrior.chromosome(i);
185 		j = chromosome.len(); // reuse this!
186 		if(1 != fwrite(&j,sizeof(j),1,_f))
187 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write chromosome length");
188 		for(j=0; j<chromosome.len(); ++j) {
189 			if(1 != fwrite(&chromosome.code(j),_insn_size,1,_f))
190 				PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not write body");
191 		}
192 	}
193 }
194 
readWarrior(CWarrior & warrior)195 void CSpeciesFile::readWarrior(CWarrior &warrior) {
196 	unsigned int i, j, clen;
197 	CFitness::NUM num;
198 	HEADER header;
199 	// read header
200 	if(1 != fread(&header,_header_size,1,_f))
201 		PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read header");
202 	// prepare warrior
203 	warrior.set_uid(header.uid);
204 	warrior.set_generation(header.generation);
205 	warrior.set_parents(header.mother,header.father);
206 	warrior.set_start(header.start);
207 	if(warrior.species()->num_chromosomes() != header.num_chromosomes)
208 		PANIC(MISC,"bad number of chromosomes in file",NULL);
209 	// read optional parts
210 	if(HEADER::HAS_INFO == (header.options & HEADER::HAS_INFO)) {
211 		if(1 != fread(&i,sizeof(i),1,_f))
212 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read info length");
213 		if(MAX_INFO_LEN <= i)
214 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"info length too long");
215 		if(i != fread(_info,1,i,_f))
216 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read info");
217 		warrior.set_info(_info);
218 	} else {
219 		warrior.clear_info();
220 	}
221 	if(HEADER::HAS_BENCH == (header.options & HEADER::HAS_BENCH)) {
222 		if(1 != fread(&i,sizeof(i),1,_f))
223 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read benchmark count");
224 		if(1 != fread(&num,sizeof(num),1,_f))
225 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read benchmark sum");
226 		warrior.set_benchmark(num,i);
227 	} else
228 		warrior.set_benchmark(0,0);
229 	// read body
230 	for(i=0; i<header.num_chromosomes; ++i) {
231 		CChromosome &chromosome = *warrior.chromosome(i);
232 		if(1 != fread(&clen,sizeof(clen),1,_f))
233 			PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read chromosome length");
234 		chromosome.set_len(clen);
235 		for(j=0; j<clen; j++) {
236 			if(1 != fread(&chromosome.code(j),_insn_size,1,_f))
237 				PANIC(GENERATION_FILE_ERROR,_filename.c_str(),"could not read body");
238 		}
239 	}
240 }
241 
242 /***** CSpecies class implementation *******************/
243 
244 CSpecies::TUid CSpecies::_uid_seq = 0; // init it
245 const CFitness::NUM CSpecies::DEFAULT_FITNESS_WEIGHTING = 1.0F; // no affect
246 
CSpecies(CGenus * genus,const string & name,const bool evolving)247 CSpecies::CSpecies(CGenus *genus,const string &name,const bool evolving): // create an empty species
248 	CHookable(), _name(name), _evolving(evolving), _genus(genus) {
249 	_uid = ++_uid_seq; // set unique uid
250 	/* inherit defaults */
251 	_fitness_weighting = DEFAULT_FITNESS_WEIGHTING;
252 	_fitness = _genus->fitness();
253 	_length = _genus->length();
254 	_freq = _genus->freq();
255 	_operands = _genus->operands();
256 	_reproduction = _genus->reproduction();
257 	_exec_trail = 0;
258 	_chromosome = 0;
259 	_num_chromosomes = 0;
260 	_start_chromosome = 0;
261 	_warrior = 0;
262 	_next = 0;
263 	_num_warriors = 0;
264 	_survives = 0;
265 	_resume = 0;
266 	_resuming = false;
267 }
268 
~CSpecies()269 CSpecies::~CSpecies() {
270 	// delete all species
271 	clear();
272 	delete _exec_trail; //TODO: ophaned COpcodeMap
273 	// delele chromosomes
274 	for(int i=0; i<_num_chromosomes; i++)
275 		delete _chromosome[i];
276 	// delete anything not inherited
277 	if(genus()->fitness() != _fitness)
278 		delete _fitness;
279 	if(genus()->length() != _length)
280 		delete _length;
281 	if(genus()->freq() != _freq)
282 		delete _freq;
283 	if(genus()->operands() != _operands)
284 		delete _operands;
285 	if(genus()->reproduction() != _reproduction)
286 		delete _reproduction;
287 	if(0 != _resume)
288 		delete _resume;
289 }
290 
clear()291 void CSpecies::clear() { /* removes all warriors from this species */
292 	int i;
293 	if(0 == _warrior) // not allocated?
294 		return;
295 	for(i=0; i<_num_warriors; i++) {
296 		delete _warrior[i];
297 	}
298 	_num_warriors = 0;
299 	delete[] _warrior;
300 	delete[] _survives;
301 	delete[] _next; // pointers not 'owned'
302 	delete[] _chromosome;
303 	_warrior = 0;
304 	_next = 0;
305 	_survives = 0;
306 }
307 
find(const CWarrior::TUid uid) const308 int CSpecies::find(const CWarrior::TUid uid) const { // -1 if not found in this species
309 	int i;
310 	for(i=_num_warriors-1; i>=0; --i) { // seek backwards, since more recent warriors are more likely to be interesting
311 		if(uid == _warrior[i]->uid())
312 			return i;
313 	}
314 	return -1; // not found
315 }
316 
read_ini(INIFile & ini)317 void CSpecies::read_ini(INIFile &ini) {
318 	int i, tries;
319 	string num;
320 	CSpeciesFile *file;
321 	KeyValuePair *kvp;
322 	clear();
323 	// uid
324 	kvp = ini.get("uid"); if(0 == kvp) { // not specified?
325 		if(0 != kingdom()->generation()) { // not first generation? this is an error
326 			PANIC(MISC,name().c_str(),"uid expected");
327 		}
328 	} else { // uid specified
329 		_uid = kvp->getValueAsInt();
330 	}
331 	// evolving?
332 	kvp = ini.get("evolving"); if(0 == kvp) PANIC(MISC,"evolving expected",NULL);
333 	_evolving = kvp->getValueAsBool();
334 	// load some defaults; these might be overloaded
335 	_fitness = _fitness->read_override_ini(ini);
336 	_length = _length->read_override_ini(ini);
337 	_freq = CInstGenerator::read_override_ini(_freq,ini);
338 	_operands = COperand::read_override_ini(_operands,ini);
339 	_reproduction = _reproduction->read_override_ini(ini);
340 	// exec trail specified?
341 	kvp = ini.get("exec_trail");
342 	if(0 != kvp) {
343 		_exec_trail = new CExecTrail(new COpcodeMap()); // hmm
344 		if(!_exec_trail->load_from_file(kvp->getValueAsChar()))
345 			PANIC(MISC,_exec_trail->filename().c_str(),"could not load exec trail from file");
346 	}
347 	// fitness weighting specified?
348 	kvp = ini.get("fitness_weighting");
349 	if(0 != kvp) {
350 		_fitness_weighting = kvp->getValueAsFloat();
351 	}
352 	// split into several chromosomes?
353 	kvp = ini.get("num_chromosomes");
354 	if(!_evolving) {
355 		_auto_chromosome = true; // avoids lots of writing/reading of ini entries later etc
356 		if(0 != kvp)
357 			PANIC(MISC,"chromosomes specified for a benchmark warrior",NULL);
358 	} else if(0 != kvp) {
359 		_auto_chromosome = false;
360 		_num_chromosomes = kvp->getValueAsInt();
361 		if((_num_chromosomes <= 0) || (_num_chromosomes >= length()->max()))
362 			PANIC(MISC,name().c_str(),"invalid number of chromosomes specified");
363 		_chromosome = new CChromosomeType*[_num_chromosomes];
364 		for(i=0; i<_num_chromosomes; i++) {
365 			// prepare the number of this chromosome as a string to search for
366 			num = "chromosome_";
367 			string_append(num,i);
368 			// and get it
369 			kvp = ini.get(num); if (0 == kvp) PANIC(MISC,name().c_str(),"chromosome expected");
370 			// and create it
371 			if(verbose) { // debug output
372 				cout << "\t\tadding " << kvp->getValueAsChar() << endl;
373 			}
374 			_chromosome[i] = new CChromosomeType(this,kvp->getValueAsChar());
375 		}
376 		// start specified?
377 		kvp = ini.get("start_chromosome");
378 		if(0 != kvp) {
379 			_start_chromosome = kvp->getValueAsInt();
380 			if(_start_chromosome > _num_chromosomes)
381 				PANIC(MISC,_name.c_str(),"start chromosome is greater than the number of chromosomes in the specices");
382 		}
383 	} else {
384 		_auto_chromosome = true;
385 		_num_chromosomes = 1;
386 		_chromosome = new CChromosomeType*[1];
387 		_chromosome[0] = new CChromosomeType(this);
388 	}
389 	// how many warriors?
390 	kvp = ini.get("num_warriors"); if(0 == kvp) PANIC(MISC,"num_warriors expected",NULL);
391 	_num_warriors = kvp->getValueAsInt();
392 	_warrior = new CWarrior*[_num_warriors];
393 	_next = new CWarrior*[_num_warriors];
394 	_survives = new bool[_num_warriors];
395 	// load chromosomes
396 	if(!_auto_chromosome) {
397 		for(i=0; i<_num_chromosomes; i++) {
398 			if(verbose) { // debug output
399 				cout << "\t\tloading " << _chromosome[i]->name() << endl;
400 			}
401 			_chromosome[i]->read_ini(ini);
402 		}
403 	}
404 	// load them if benchmark
405 	if(is_bench()) {
406 		for(i=0; i<_num_warriors; ++i) {
407 			// prepare index number
408 			num = "warrior_";
409 			string_append(num,i);
410 			// get it
411 			kvp = ini.get(num); if(0 == kvp) { // hmm
412 				PANIC(MISC,num.c_str(),"expected");
413 			} else {
414 				kvp->getValueAsString(num); // reuse string
415 				if(verbose) { // debug output
416 					cout << "\t\tbench " << i << '=' << num << endl;
417 				}
418 				_warrior[i] = new CWarrior(this,num);
419 				_warrior[i]->code_check();
420 			}
421 		}
422 	} else { // evolving
423 		num = "species-";
424 		num += _name;
425 		num += "-";
426 		string_append(num,kingdom()->generation());
427 		num += ".dat";
428 		if(file_exists(num) || (0 != kingdom()->generation())) { // not first generation, so load them?
429 			file = new CSpeciesFile(*this,kingdom()->generation());
430 			for(i=0; i<_num_warriors; ++i) {
431 				_warrior[i] = new CWarrior(this,0); // uid will be overriden, no need to use up uidspace
432 				file->readWarrior(*_warrior[i]);
433 			}
434 			delete file;
435 		} else { // first generation, so create some random warriors
436 			if(kingdom()->in_experiment()) {
437 				for(i=0; i<_num_warriors; ++i) {
438 					_warrior[i] = new CWarrior(this);
439 					if(!silent) { // debug info
440 						cout << "\t\tgenerating " << _name << ':' << _warrior[i]->uid() << " .. ";
441 					}
442 					tries = 0;
443 					do {
444 						tries++;
445 						_warrior[i]->clear();
446 						_warrior[i]->set_info("generated from random");
447 						for(int j=0; j<num_chromosomes(); j++) {
448 							chromosome(j)->reproduction()->generateCompletelyRandom(*(_warrior[i]->chromosome(j)));
449 						}
450 					} while(!CReproduction::fit_enough(*_warrior[i]));
451 					if(!silent) { // debug info
452 						cout << "took " << tries << " tries";
453 						if(verbose) {
454 							cout << ':' << endl;
455 							_warrior[i]->rc(cout);
456 						}
457 						cout << endl;
458 					}
459 				}
460 			} else { // lazy load?
461 				for(i=0; i<_num_warriors; ++i) {
462 					_warrior[i] = 0; // null
463 				}
464 			}
465 		}
466 	}
467 }
468 
write_ini(ostream & os)469 void CSpecies::write_ini(ostream &os) {
470 	int i;
471 	os	<< "uid=" << _uid << endl
472 		<< "evolving=" << _evolving << endl;
473 	// dump misc stuff
474 	_fitness->write_override_ini(os,_genus->fitness());
475 	_length->write_override_ini(os,_genus->length());
476 	_freq->write_override_ini(os,_genus->freq());
477 	_operands->write_override_ini(os,_genus->operands());
478 	_reproduction->write_override_ini(os,_genus->reproduction());
479 	// exec trail?
480 	if(_exec_trail) {
481 		os << "exec_trail=" << _exec_trail->filename() << endl;
482 	}
483 	// fitness weighting?
484 	if(_fitness_weighting != DEFAULT_FITNESS_WEIGHTING) { // non-default?
485 		os << "fitness_weighting=" << _fitness_weighting << endl;
486 	}
487 	// chromosomes
488 	if(!_auto_chromosome) {
489 		os << "num_chromosomes=" << _num_chromosomes << endl;
490 		for(i=0; i<_num_chromosomes; ++i)
491 			os << "chromosome_" << i << '=' << _chromosome[i]->name() << endl;
492 		if(0 != _start_chromosome)
493 			os << "start_chromosome=" << _start_chromosome << endl;
494 	}
495 	// list warriors
496 	os << "num_warriors=" << size() << endl;
497 	if(is_bench()) {
498 		for(i=0; i<_num_warriors; ++i) {
499 			os << "warrior_" << i << '=' << _warrior[i]->filename() << endl;
500 		}
501 	} else { // is evolver
502 		save();
503 	}
504 	// print each chromosome
505 	if(!_auto_chromosome) {
506 		for(i=0; i<_num_chromosomes; ++i)
507 			_chromosome[i]->write_ini(os);
508 	}
509 }
510 
save()511 void CSpecies::save() {
512 	int i;
513 	CSpeciesFile *file;
514 	if(is_bench()) // no point?
515 		return;
516 	file = new CSpeciesFile(*this,kingdom()->generation());
517 	for(i=0; i<_num_warriors; ++i) {
518 		file->writeWarrior(*_warrior[i]);
519 	}
520 	delete file;
521 }
522 
ready()523 void CSpecies::ready() { /* this will blank all fitness metrics preceeding the fighting of a generation */
524 	int i;
525 	for(i=0; i<_num_warriors; ++i) {
526 		_warrior[i]->ready();
527 	}
528 	// resume support
529 	if(0 != _resume)
530 		delete _resume;
531 	if(is_evolving()) {
532 		_resume = new CResumeFile(this);
533 		_resuming = _resume->openForRead();
534 		if(!_resuming)
535 			_resume->openForWrite();
536 	} else
537 		_resuming = false;
538 }
539 
fight(CSpecies & enemy)540 int CSpecies::fight(CSpecies &enemy) { /* this will actually do all the fights for a generation; returns number of rounds fought */
541 	CWarrior::FIGHT_DATA data;
542 	int i, j, count=0, resumed = 0;
543 	for(i=0; i<_num_warriors; ++i) {
544 		for(j=0; j<enemy._num_warriors; ++j) {
545 			// try to resume..
546 			if(_resuming) {
547 				if(_resume->read(data)) {
548 					// sanity check
549 					if(data.src != _warrior[i]->uid())
550 						PANIC(BAD_RESUMEFILE,"src uid failed",NULL);
551 					if(data.dest != enemy._warrior[j]->uid())
552 						PANIC(BAD_RESUMEFILE,"dest uid failed",NULL);
553 					// do the actual scoring
554 					count += _warrior[i]->fight(*enemy._warrior[j],data,false);
555 					// done, so next enemy
556 					resumed++;
557 					continue;
558 				} else {
559 					if(!silent && (0 < resumed)) {
560 						cout << "(loaded " << resumed << " fights from " << name() << "\'s resume log)" << endl;
561 					}
562 					// failed, so no more resumes
563 					_resuming = false;
564 					_resume->swapFromReadToWrite();
565 					// drop through
566 				}
567 			}
568 			// actually fight
569 			PROGRESS_TWIDDLE
570 			count += _warrior[i]->fight(*enemy._warrior[j],data);
571 			if(is_evolving()) {
572 				_resume->write(data);
573 			}
574 		}
575 	}
576 	if(0 != _resume) {
577 		_resume->flush();
578 	}
579 	if(!silent && _resuming && (0 < resumed)) {
580 		cout << "(loaded all " << resumed << " fights from " << name() << "\'s resume log)" << endl;
581 	}
582 	return count;
583 }
584 
selection()585 CWarrior *CSpecies::selection() { /* this will do selection on all the warriors in this species; returns pointer to the best too */
586 	// there is bound to be a better way than this
587 	int i, j, tries,
588 		mother, father, best,
589 		benchmark_n, benchmark_score, benchmark_sum = 0;
590 	bool ok;
591 	fstream red;
592 	string name, note;
593 	if(!_evolving) // no point with benchmark warriors
594 		return 0;
595 	_resume->close();
596 	// ready survives table
597 	for(i=0; i<_num_warriors; ++i) { // clear survives flags
598 		_survives[i] = false;
599 	}
600 	// prepare for benchmarking?
601 	if(0 != kingdom()->benchmark()) {
602 		sort();
603 	}
604 	// best always survives
605 	best = scores(_min,_sum);
606 	_next[0] = _warrior[best];
607 	_survives[best] = true;
608 	// benchmark the better ones?
609 	if(0 != kingdom()->benchmark()) {
610 		if(verbose) {
611 			cout << "\tbenchmarking " << _name << endl;
612 		}
613 		// how many warriors to test?
614 		benchmark_n = (int)(_num_warriors * kingdom()->benchmark_n());
615 		if(0 == benchmark_n) benchmark_n = 1; // always at least the first(best) warrior
616 		if(benchmark_n > _num_warriors) PANIC(MISC,"bad benchmark_n",NULL);
617 		// and do it
618 		for(i=0; i<benchmark_n; ++i) {
619 			if(!silent) {
620 				cout << "\t\tbenchmarking " << _name << ':' << _warrior[i]->uid() << " .. " << flush;
621 			}
622 			// todo: make this use a variable number of rounds in the benchmark
623 			benchmark_score = 0;
624 			for(j=0; j<kingdom()->benchmark()->_num_warriors; ++j) {
625 				benchmark_score += _warrior[i]->fight(*kingdom()->benchmark()->_warrior[j],100,3,1,0);
626 			}
627 			benchmark_score = (int)((double)benchmark_score / (double)kingdom()->benchmark()->num_warriors()); // = score / num_warriors_in_bench / rounds_per_warrior * 100
628 			if(!silent) {
629 				cout << "scored " << benchmark_score << endl;
630 			}
631 			_warrior[i]->incorporate_benchmark(benchmark_score);
632 			benchmark_sum += benchmark_score;
633 			name = _name;
634 			name += "--";
635 			string_append(name,_warrior[i]->uid());
636 			name += ".red";
637 			note = ";benchmark ";
638 			string_append(note,(int)round(_warrior[i]->benchmark()));
639 			if(kingdom()->benchmark_candidate() <= benchmark_score) {
640 				note += " CANDIDATE!";
641 				if(!silent) {
642 					cout << "Warrior " << name << " is a CANDIDATE with a benchmark score of " << benchmark_score << endl;
643 				}
644 			}
645 			red.clear();
646 			red.open(name.c_str(),ios_base::out|ios_base::trunc);
647 			if(red) {
648 				_warrior[i]->red(red,note.c_str());
649 			} else {
650 				cerr << "WARNING: could not write to " << name << endl;
651 			}
652 			red.close();
653 		}
654 	} else { // just save the best of this generation
655 		name = _name;
656 		name += "-";
657 		string_append(name,kingdom()->generation());
658 		name += ".red";
659 		red.clear();
660 		red.open(name.c_str(),ios_base::out|ios_base::trunc);
661 		if(red) {
662 			_warrior[best]->red(red);
663 		} else {
664 			cerr << "WARNING: could not write to " << name << endl;
665 		}
666 		red.close();
667 	}
668 	// and adjust the value to return (since best is always moved to _next[0])
669 	best = 0;
670 	// and select the rest
671 	for(i=1; i<_num_warriors; ++i) { // for each new warrior; note base 1
672 		ok = false;
673 		do {
674 			if(reproduction()->survive()) { // does a warrior from the old generation survive?
675 				j = rnd(); // get a random one
676 				if(_survives[j]) { // already surviving?
677 					continue;
678 				}
679 				_survives[j] = true;
680 				_next[i] = _warrior[j];
681 				if(verbose) {
682 					cout << _next[i]->uid() << " survives" << endl;
683 				}
684 			} else { // breed a warrior
685 				mother = rnd(); // get a random one
686 				do {
687 					father = rnd(); // get a random one
688 				} while(father == mother); // until different
689 				_next[i] = new CWarrior(this,_warrior[mother]->uid(),_warrior[father]->uid());
690 				if(verbose) {
691 					cout << _next[i]->uid() << " born from " << _warrior[mother]->uid() << " and " << _warrior[father]->uid() << endl;
692 				}
693 				tries = 0;
694 				do {
695 					tries++;
696 					for(int j=0; j<num_chromosomes(); j++) {
697 						chromosome(j)->reproduction()->breed(*(_next[i]->chromosome(j)),*(_warrior[mother]->chromosome(j)),*(_warrior[father]->chromosome(j)));
698 					}
699 				} while(!CReproduction::fit_enough(*_next[i]));
700 				_next[i]->code_check();
701 				if(verbose) { // debug output
702 					cout << "generating " << _warrior[i]->uid() << " took " << tries << " tries:" << endl;
703 					_warrior[i]->rc(cout);
704 					cout << endl;
705 				}
706 			}
707 			ok = true; // if here, we have generated something
708 		} while(!ok);
709 	}
710 	// transfer next generation to this one
711 	for(i=0; i<_num_warriors; ++i) {
712 		if(!_survives[i]) { // clean up?
713 			delete _warrior[i];
714 		}
715 		_warrior[i] = _next[i];
716 	}
717 	// done
718 	return _warrior[best];
719 }
720 
721 /*	This returns a random warrior based upon fitness */
rnd() const722 int CSpecies::rnd() const {
723 	int i;
724 	const CFitness::NUM x = CRand::frand(_sum);
725 	CFitness::NUM y; fitness()->zero(y);
726 	do {
727 		for(i=0; i<_num_warriors; ++i) {
728 			y += (_warrior[i]->score() - _min); // based upon _min
729 			if(y > x) { // found it?
730 				return i;
731 			}
732 		}
733 		cerr << "WARNING: roulette off end of CSpecies for fitness" << endl;
734 	} while(true);
735 }
736 
737 /*	This returns the minimum and sum (adjusted relative to min) scores for this species;
738 	these are the numbers needed to do roulette selection of the warriors based upon fitness.
739 	The min is actually 1 less than the true min, so even the worst warriors have a small chance
740 	of being selected; returns index of the best too */
scores(CFitness::NUM & min,CFitness::NUM & sum) const741 int CSpecies::scores(CFitness::NUM &min,CFitness::NUM &sum) const {
742 	int i, ret = 0;
743 	CFitness::NUM max = _warrior[ret]->score();
744 	min = max;
745 	fitness()->zero(sum);
746 	// find min and max
747 	for(i=0; i<_num_warriors; ++i) {
748 		if(_warrior[i]->score() > max) {
749 			ret = i;
750 			max = _warrior[ret]->score();
751 		} else if(_warrior[i]->score() < min) {
752 			min = _warrior[i]->score();
753 		}
754 	}
755 	// work out sum, adjusted for min as a base
756 	min--;
757 	for(i=0; i<_num_warriors; ++i) {
758 		sum += _warrior[i]->score();
759 		sum -= _min;
760 	}
761 	if(sum <= 0.0F)
762 		PANIC(MISC,"error in CSpecies::scores(..)",NULL);
763 	return ret;
764 }
765 
766 /* this sorts the warriors into score order, best in 0 */
sort()767 void CSpecies::sort() {
768 	// TODO: replace this bubblesort?
769 	bool changed;
770 	int i, j, len = _num_warriors;
771 	CWarrior *swap;
772 	do {
773 		changed = false;
774 		len--;
775 		j=0;
776 		for(i=0; i<len; i++) {
777 			j++;
778 			if(_warrior[i]->score() < _warrior[j]->score()) {
779 				// swap the pointers over
780 				swap = _warrior[i];
781 				_warrior[i] = _warrior[j];
782 				_warrior[j] = swap;
783 				// and remember we've done something
784 				changed = true;
785 			}
786 		}
787 	} while(changed);
788 }
789 
chromosome(const unsigned int i) const790 CChromosomeType *CSpecies::chromosome(const unsigned int i) const {
791 	if(safety_checks)
792 		if(_num_chromosomes < i)
793 			PANIC(MISC,"chromosome index beyond range",NULL);
794 	return _chromosome[i];
795 }
796 
kingdom() const797 CKingdom *CSpecies::kingdom() const { return _genus->kingdom(); }
798 
warrior(const CWarrior::TUid uid) const799 CWarrior *CSpecies::warrior(const CWarrior::TUid uid) const { /* fetch a particular warrior from this species; NULL if not present */
800 	int i;
801 	CWarrior *ret = 0;
802 	for(i=0; i<_num_warriors; ++i) {
803 		if(_warrior[i]->uid() == uid) { // match?
804 			return _warrior[i];
805 		}
806 	}
807 	return 0; // not found
808 }
809 
810