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 "genus.hpp"
20 using namespace std;
21 
22 /***** CGenus class implementation *********************/
23 
CGenus(CKingdom * kingdom,const string & name)24 CGenus::CGenus(CKingdom *kingdom,const string &name): CHookable(), _kingdom(kingdom), _name(name) {
25 	// set some defaults to inherit from the parent
26 	_fitness = _kingdom->fitness();
27 	_length = _kingdom->length();
28 	_freq = _kingdom->freq();
29 	_operands = _kingdom->operands();
30 	_reproduction = _kingdom->reproduction();
31 	_species = 0;
32 	_num_species = 0;
33 }
34 
~CGenus()35 CGenus::~CGenus() {
36 	// delete all species
37 	clear();
38 	// delete anything not inherited
39 	if(kingdom()->fitness() != _fitness)
40 		delete _fitness;
41 	if(kingdom()->length() != _length)
42 		delete _length;
43 	if(kingdom()->freq() != _freq)
44 		delete _freq;
45 	if(kingdom()->operands() != _operands)
46 		delete _operands;
47 	if(kingdom()->reproduction() != _reproduction)
48 		delete _reproduction;
49 }
50 
clear()51 void CGenus::clear() { /* removes all species from this genus */
52 	int i;
53 	if(0 == _species) // not allocated?
54 		return;
55 	for(i=0; i<_num_species; i++) {
56 		delete _species[i];
57 	}
58 	_num_species = 0;
59 	delete[] _species;
60 	_species = 0;
61 }
62 
num_evolving_species() const63 int CGenus::num_evolving_species() const {
64 	int i, count=0;
65 	for(i=0; i<_num_species; ++i)
66 		if(_species[i]->is_evolving())
67 			count++;
68 	return count;
69 }
70 
num_evolved_warriors() const71 int CGenus::num_evolved_warriors() const {
72 	int i, count=0;
73 	for(i=0; i<_num_species; ++i)
74 		if(_species[i]->is_evolving())
75 			count += _species[i]->num_warriors();
76 	return count;
77 }
78 
num_warriors() const79 int CGenus::num_warriors() const { /* returns a trivia number of warriors 'live' in this genus at this time */
80 	int i, count=0;
81 	for(i=0; i<_num_species; ++i)
82 		count += _species[i]->num_warriors();
83 	return count;
84 }
85 
read_ini(INIFile & ini)86 void CGenus::read_ini(INIFile &ini) {
87 	KeyValuePair *kvp;
88 	int i;
89 	string num;
90 	clear();
91 	// load some defaults; these might be overloaded
92 	_fitness = _fitness->read_override_ini(ini);
93 	_length = _length->read_override_ini(ini);
94 	_freq = CInstGenerator::read_override_ini(_freq,ini);
95 	_operands = COperand::read_override_ini(_operands,ini);
96 	_reproduction = _reproduction->read_override_ini(ini);
97 	// how many species do we have?
98 	kvp = ini.get("num_species"); if(0 == kvp) PANIC(MISC,"num_species expected",NULL); _num_species = kvp->getValueAsInt();
99 	_species = new CSpecies*[_num_species];
100 	// load each species name
101 	for(i=0; i<_num_species; ++i) {
102 		// prepare the number of this species as a string to search for
103 		num = "";
104 		string_append(num,i);
105 		// and get it
106 		kvp = ini.get(num); if (0 == kvp) PANIC(MISC,"species expected",NULL);
107 		// and create it
108 		if(verbose) { // debug output
109 			cout << "\tadding " << kvp->getValueAsChar() << endl;
110 		}
111 		_species[i] = new CSpecies(this,kvp->getValueAsChar(),false);
112 	}
113 	// actually load each species
114 	for(i=0; i<_num_species; ++i) {
115 		// go to the correct section
116 		if(verbose) { // debug output
117 			cout << "\tloading " << _species[i]->name() << endl;
118 		}
119 		if(!ini.seek(_species[i]->name())) PANIC(MISC,_species[i]->name().c_str(),"species section not found");
120 		// and load it
121 		_species[i]->read_ini(ini);
122 	}
123 }
124 
write_ini(ostream & os)125 void CGenus::write_ini(ostream &os) {
126 	int i;
127 	// dump misc stuff
128 	_fitness->write_override_ini(os,_kingdom->fitness());
129 	_length->write_override_ini(os,_kingdom->length());
130 	_freq->write_override_ini(os,_kingdom->freq());
131 	_operands->write_override_ini(os,_kingdom->operands());
132 	_reproduction->write_override_ini(os,_kingdom->reproduction());
133 	// list species
134 	os << "num_species=" << _num_species << endl;
135 	for(i=0; i<_num_species; ++i) {
136 		os	<< i << '=' << _species[i]->name() << endl;
137 	}
138 	// dump the bodies of all the species declared
139 	for(i=0; i<_num_species; ++i) {
140 		os	<< endl
141 			<< '[' << _species[i]->name() << ']' << endl;
142 		_species[i]->write_ini(os);
143 	}
144 }
145 
save()146 void CGenus::save() {
147 	int i;
148 	for(i=0; i<_num_species; ++i) {
149 		_species[i]->save();
150 	}
151 }
152 
ready()153 void CGenus::ready() { /* this will blank all fitness metrics preceeding the fighting of a generation */
154 	int i;
155 	for(i=0; i<_num_species; ++i) {
156 		_species[i]->ready();
157 	}
158 }
159 
fight(CGenus & enemy)160 int CGenus::fight(CGenus &enemy) { /* this will actually do all the fights for a generation; returns number of rounds fought */
161 	int i, j, count = 0;
162 	for(i=0; i<_num_species; ++i) {
163 		if(_species[i]->is_bench()) // only if it is an evolving species; no point gathering WINNING points for benchmarks benchmarks
164 			continue;
165 		for(j=0; j<enemy._num_species; ++j) {
166 			if(verbose) { // debug output
167 				cout << "\tfight: " << _species[i]->name() << " vs. " << enemy._species[j]->name() << endl;
168 			}
169 			count += _species[i]->fight(*enemy._species[j]);
170 		}
171 	}
172 	return count;
173 }
174 
selection()175 CWarrior *CGenus::selection() { /* this will do selection on all the warriors in this genus; returns pointer to the best */
176 	int i;
177 	CWarrior *best = 0, *candidate;
178 	for(i=0; i<_num_species; ++i) {
179 		if(verbose) {
180 			cout << "breeding " << _species[i]->uid() << endl;
181 		}
182 		candidate = _species[i]->selection();
183 		if(0 == best) // not set?
184 			best = candidate;
185 		else if(0 != candidate) // this species did return a best (so is evolving)
186 			if(candidate->score() > best->score()) // beaten
187 				best = candidate;
188 	}
189 	return best;
190 }
191 
warrior(const CWarrior::TUid uid) const192 CWarrior *CGenus::warrior(const CWarrior::TUid uid) const { /* fetch a particular warrior from this genus; NULL if not present */
193 	int i;
194 	CWarrior *ret = 0;
195 	for(i=0; (i < _num_species) && (0 == ret); ++i) {
196 		ret = _species[i]->warrior(uid);
197 	}
198 	return ret;
199 }
200 
201 //*** array index accessors
202 
species(unsigned index) const203 CSpecies &CGenus::species(unsigned index) const {
204 	if(index >= _num_species)
205 		PANIC(MISC,"illegal CGenus species index",NULL);
206 	return *_species[index];
207 }
208