/* "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. */ #include "inst_gen_markov.hpp" #include "species.hpp" #include "exhaust.hpp" #include "opcode_branch_lookup.hpp" #include "rand.hpp" using namespace std; /******* CInstGeneratorMarkov implementation *********************/ const float CInstGeneratorMarkov::DEFAULT_DAT = 0.1F; // 10% CInstGeneratorMarkov::CInstGeneratorMarkov() { _type = MARKOV; // important line! CORESIZE = 0; opcodes = 0; opcode = 0; opcode_modifiers = 0; readonly = true; _filename = ""; } CInstGeneratorMarkov::~CInstGeneratorMarkov() { clear(); readonly = true; } void CInstGeneratorMarkov::write_ini(ostream &os) { os << "inst_gen=" << impl_desc(type()) << endl; os << "markov_file=" << _filename << endl; if(DEFAULT_DAT != _dat) os << "markov_dats=" << _dat << endl; } void CInstGeneratorMarkov::write_override_ini(ostream &os,const CInstGenerator *parent) { if(parent == this) // nothing to do? return; os << "inst_gen=" << impl_desc(type()) << endl; if(same_type(this,parent)) { if(((CInstGeneratorMarkov*)parent)->_filename != _filename) { os << "markov_file=" << _filename << endl; os << "markov_dats=" << _dat << endl; } else if(((CInstGeneratorMarkov*)parent)->_dat != _dat) // overriden? os << "markov_dats=" << _dat << endl; } else { if(DEFAULT_DAT != _dat) os << "markov_dats=" << _dat << endl; } } void CInstGeneratorMarkov::read_ini_impl(INIFile &ini) { KeyValuePair *kvp; kvp = ini.get("markov_file"); if(0 == kvp) PANIC(MISC,"markov_file key expected",NULL); // null?! kvp->getValueAsString(_filename); load(_filename.c_str()); kvp = ini.get("markov_dats"); if(0 != kvp) { _dat = kvp->getValueAsFloat(DEFAULT_DAT); if((0.0F > _dat) || (1.0F <= _dat)) PANIC(MISC,"markov_dat must be between 0.0 and 1.0",NULL); } else _dat = DEFAULT_DAT; } CInstGenerator *CInstGeneratorMarkov::read_override_ini_impl(INIFile &ini) { string filename; CInstGeneratorMarkov *ret = this; KeyValuePair *kvp; kvp = ini.get("markov_file"); if(0 != kvp) { // specified? kvp->getValueAsString(filename); if(_filename != filename) { ret = new CInstGeneratorMarkov(); ret->read_ini_impl(ini); } } kvp = ini.get("markov_dats"); if(0 != kvp) { float dat = kvp->getValueAsFloat(DEFAULT_DAT); if(dat != ret->_dat) { ret = new CInstGeneratorMarkov(*this); ret->_dat = dat; if((0.0F > ret->_dat) || (1.0F <= ret->_dat)) PANIC(MISC,"markov_dat must be between 0.0 and 1.0",NULL); } } return ret; } unsigned CInstGeneratorMarkov::opcode_modifier_2_index(const unsigned opcode_modifier) const { //TODO: binary search? this is sorted btw.. for(unsigned i=0; i 0) && (_dat >= CRand::frand(1.0F)); } void CInstGeneratorMarkov::suggest_instruction(insn_t &instruction,const MODE /*mode*/) { instruction.in = 0; unsigned prev = INVALID_INDEX, curr = INVALID_INDEX, opmod = INVALID_INDEX; if((index() > 0) && (index() < chromosome()->len())) prev = opcode_modifier_2_index(chromosome()->code(index()-1).opcode_modifier()); if(INVALID_INDEX != prev) { opmod = opcode[prev].suggest_opcode_modifier(); // is index if(INVALID_INDEX != opmod) opmod = opcode[prev].markov[opmod].get_opcode_modifier(); // to actual opcode/modifier } if(INVALID_INDEX == opmod) { opmod = opcode[suggest_opcode_modifier()].key.get_opcode_modifier(); } instruction.set_opcode_modifier(opmod); curr = opcode_modifier_2_index(opmod); if(INVALID_INDEX != curr) { //cout << MNEMONIC_OPCODE(instruction.opcode()] << '.' << MNEMONIC_MODIFIER[instruction.modifier()] << " is known" << endl; // set appropriate values instruction.set_addrmode_a((ADDRMODE)opcode[curr].addrmode_a.suggest()); instruction.set_addrmode_b((ADDRMODE)opcode[curr].addrmode_b.suggest()); chromosome()->type()->operands()->rnd(instruction,COperand::A); chromosome()->type()->operands()->rnd(instruction,COperand::B); } else { //cout << MNEMONIC_OPCODE(instruction.opcode()] << '.' << MNEMONIC_MODIFIER[instruction.modifier()] << " is unknown" << endl; // make stuff up instruction.set_addrmode_a((ADDRMODE)CRand::irand(ADDRMODE_LAST)); instruction.set_addrmode_b((ADDRMODE)CRand::irand(ADDRMODE_LAST)); chromosome()->type()->operands()->rnd(instruction,COperand::A); chromosome()->type()->operands()->rnd(instruction,COperand::B); } if(safety_checks) { if(!instruction.valid(chromosome()->warrior()->species()->kingdom()->coresize())) { cerr << "bad instruction in chromosome()[" << index() << ']' << endl; PANIC(MISC,"corrupt warrior from markov",NULL); } } } void CInstGeneratorMarkov::clear() { for(int i=0; i= 0xFFFF) PANIC(MISC,"coresize isn\'t valid",NULL); opcodes = OPCODE_MODIFIER_LAST; opcode = new CFreq[opcodes]; for(unsigned i=0; i