#ifndef SPECIES_HPP #define SPECIES_HPP /* "Species" - a CoreWars evolver. Copyright (C) 2003 'Varfar' * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 1, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ /** * species.h * (c) Will Sutton, 2002 * the main header, exposes global information about the simulation; * * taxonomic groups -- in descending order -- are Kingdom, Phylum, Class, Order, Family, Genus, Species * more detailed classifications -- in descending order -- are: * domain * superkingdom * kingdom* * subkingdom * superphylum * phylum* (plural phyla) * subphylum * infraphylum * subterphylum * superclass * class* * subclass * infraclass * subterclass * supersection * section * subsection * infrasection * supercohort * cohort * subcohort * infracohort * subtercohort * superorder * order* * suborder * infraorder * superfamily * family* * subfamily * supertribe * tribe * subtribe * genus* (plural genera) * subgenus * superspecies * species* (plural species) * geographical race (synonym race, subspecies) * * in this simplified simulation, only a few are used: * * CKingdom: a collection of genera * CGenus: a collection of species * CSpecies: a collection of warriors * CWarrior : a warrior * * CSpecies come in two flavours; evolving species, and 'benchmark' species that assist in directing evolution * by weighing scores. Both CSpecies and CWarriors can be queried as to whether they are 'evolving' or 'bench'. * CSpecies and their CWarriors must have the same value for this 'evolving' flag. **/ /** global constants, expect compiler to treat this as #define **/ static const bool verbose = false, // lots of couts following program execution? silent = false, terse = !verbose && !silent, metrics = true, // time fights to generate performance statistics? safety_checks = true;// double check the warriors/core for corruption? const int PROGRESS_MOD = 4; extern int progress; extern const char *progress_twiddle; #ifdef SHOW_PROGRESS_TWIDDLE #define PROGRESS_TWIDDLE cout << progress_twiddle[progress++ % PROGRESS_MOD] << '\r' << flush; #else #define PROGRESS_TWIDDLE #endif /* forwards */ class CChromosomeType; class CWarrior; class CSpecies; class CGenus; class CKingdom; class CResumeFile; class CExecTrail; #include "hook.hpp" #include "exhaust.hpp" #include "rand.hpp" #include "ini.hpp" #include "error.hpp" #include "length.hpp" #include "operand.hpp" #include "fitness.hpp" #include "inst_gen.hpp" #include "reproduction.hpp" #include #include extern const float VERSION; // actually in kingdom.cpp #include "generation.hpp" #include "chromosome.hpp" #include "warrior.hpp" class CSpecies: public CHookable { public: typedef unsigned int TUid; CSpecies(CGenus *genus,const std::string &name,const bool evolving); // create an empty species ~CSpecies(); void clear(); /* this will delete all warriors from this species */ std::string name() const { return _name; } void read_ini(INIFile &ini); /* expects to be in the correct section */ void write_ini(std::ostream &os); void save(); bool is_evolving() const { return _evolving; } bool is_bench() const { return !_evolving; } int find(const CWarrior::TUid uid) const; // -1 if not found in this species int size() const { return _num_warriors; } int num_warriors() const { return size(); } /* returns a trivia number of warriors 'live' in this species at this time */ void ready(); /* this will blank all fitness metrics preceeding the fighting of a species */ int fight(CSpecies &enemy); /* this will actually do all the fights for a generation; returns number of rounds fought */ CWarrior *selection(); /* this will do selection on all the warriors in this species; returns the best */ CGenus *genus() const { return _genus; } CKingdom *kingdom() const; CFitness *fitness() const { return _fitness; } CLength *length() const { return _length; } CInstGenerator *freq() const { return _freq; } COperand *operands() const { return _operands; } CReproduction *reproduction() const { return _reproduction; } CExecTrail *exec_trail() const { return _exec_trail; } CFitness::NUM fitness_weighting() const { return _fitness_weighting; } TUid uid() const { return _uid; } CWarrior *warrior(const CWarrior::TUid uid) const; /* fetch a particular warrior from this species; NULL if not present */ unsigned int num_chromosomes() const { return _num_chromosomes; } unsigned int start_chromosome() const { return _start_chromosome; } CChromosomeType *chromosome(const unsigned int i) const; protected: TUid _uid; static TUid _uid_seq; CResumeFile *_resume; bool _resuming; CWarrior **_warrior, // warriors in this species **_next; // a holder while doing selection bool *_survives; // a flag to keep track of who survives during selection int _num_warriors; std::string _name; bool _evolving; /* immutable species are benchmarks only; they do not 'evolve' */ CGenus *_genus; // parent CFitness *_fitness; // might be referencing CGenus::_fitness if not overriden CFitness::NUM _fitness_weighting; // a balance to magnify species with a small number of warriors static const CFitness::NUM DEFAULT_FITNESS_WEIGHTING; CLength *_length; // might be CGenus::_length if not overriden CInstGenerator *_freq; // might be CGenus::_freq if not overriden COperand *_operands; // might be CGenus::_operands if not overriden CReproduction *_reproduction; // might be CGenus::_reproduction if not overriden CExecTrail *_exec_trail; // might be null CFitness::NUM _min, _sum; // these variables are used in rnd() for selection; see scores(..) // subdivision of each warrior into chromosomes bool _auto_chromosome; // wasn't there any chromosomes defined for this species? unsigned int _num_chromosomes, _start_chromosome; CChromosomeType **_chromosome; /* This returns a random warrior index based upon fitness */ int rnd() const; /* This returns the minimum and sum (adjusted relative to min) scores for this species; these are the numbers needed to do roulette selection of the warriors based upon fitness. The min is actually 1 less than the true min, so even the worst warriors have a small chance of being selected */ int scores(CFitness::NUM &min,CFitness::NUM &sum) const; /* returns index of best too */ /* this sorts the warriors into score order, best in 0 */ void sort(); }; #include "genus.hpp" //TODO: This seems to be a little bit back-to-front; we ought to pass a stream to a warrior and ask it to serialise? class CSpeciesFile { friend class CSpecies; public: CSpeciesFile(const std::string species,const CGeneration::NUM generation); CSpeciesFile(const CSpecies &species,const CGeneration::NUM generation); ~CSpeciesFile(); std::string const &filename() const { return _filename; } protected: CGeneration::NUM _num; FILE *_f; std::string _filename; void set_filename(const std::string name,const CGeneration::NUM generation); void open_file(); typedef struct { enum { // plenty of room for more flags in future NONE = 0, HAS_INFO = 1, HAS_BENCH = 2 }; unsigned short int options; CWarrior::TUid uid, mother, father; CGeneration::NUM generation; unsigned int num_chromosomes, start; } HEADER; static const int MAX_INFO_LEN = 256; char _info[MAX_INFO_LEN]; static const size_t _header_size = sizeof(HEADER), _insn_size = sizeof(insn_st); void writeWarrior(const CWarrior &warrior); void readWarrior(CWarrior &warrior); }; #include "kingdom.hpp" #endif // ifndef SPECIES_HPP