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