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 "distribution.hpp"
20 #include "error.hpp"
21 #include "rand.hpp"
22 
23 using namespace std;
24 
25 /***** CDistribution class implementation *************/
26 
CDistribution()27 CDistribution::CDistribution() {
28 	_context = "";
29 	_data = 0;
30 	_size = 0;
31 }
32 
CDistribution(const string & context,const int min,const int max)33 CDistribution::CDistribution(const string &context,const int min,const int max) {
34 	_context = context;
35 	_data = 0;
36 	_size = 0;
37 	set(min,max);
38 }
39 
~CDistribution()40 CDistribution::~CDistribution() {
41 	if(0 != _data) // allocated?
42 		delete[] _data;
43 }
44 
set(const int min,const int max)45 void CDistribution::set(const int min,const int max) {
46 	if(min >= max)
47 		PANIC(MISC,"distribution has invalid length",NULL);
48 	_size = 2;
49 	if(0 != _data) // already allocated?
50 		delete[] _data;
51 	_data = new int[_size];
52 	_data[0] = min;
53 	_data[1] = max;
54 }
55 
read_ini(INIFile & ini,bool required)56 void CDistribution::read_ini(INIFile &ini,bool required) {
57 	KeyValuePair *kvp;
58 	int i;
59 	string num;
60 	// get size
61 	kvp = ini.get(_context + "_num_points");
62 	if(0 == kvp)
63 		if(required) {
64 			PANIC(MISC,_context.c_str(),"_num_points expected")
65 		} else {
66 			return;
67 		}
68 	_size = kvp->getValueAsInt();
69 	if(_size < 2)
70 		PANIC(MISC,_context.c_str(),"invalid _num_points");
71 	// allocate
72 	delete[] _data;
73 	_data = new int[_size];
74 	// and load
75 	for(i=0; i<_size; ++i) {
76 		// prepare num
77 		num = _context;
78 		num += '_';
79 		string_append(num,i);
80 		// get key
81 		kvp = ini.get(num); if(0 == kvp) PANIC(MISC,num.c_str(),"expected");
82 		// and set it
83 		_data[i] = kvp->getValueAsInt();
84 		// check sequence
85 		if(i > 0) { // not the first?
86 			if(_data[i] <= _data[i-1])
87 				PANIC(MISC,num.c_str(),"value out of sequence");
88 		}
89 	}
90 }
91 
read_override_ini(INIFile & ini,ImplFactoryCallback factory)92 CDistribution *CDistribution::read_override_ini(INIFile &ini,ImplFactoryCallback factory) {
93 	CDistribution *ret = this;
94 	KeyValuePair *kvp;
95 	int i;
96 	string num;
97 	// get size
98 	kvp = ini.get(_context + "_num_points");
99 	if(0 == kvp)
100 		return ret; // nothing specified?
101 	ret = factory(*this);
102 	ret->_size = kvp->getValueAsInt();
103 	if(ret->_size < 2)
104 		PANIC(MISC,_context.c_str(),"invalid _num_points");
105 	// allocate
106 	ret->_data = new int[ret->_size];
107 	// and load
108 	for(i=0; i<ret->_size; ++i) {
109 		// prepare num
110 		num = _context;
111 		num += '_';
112 		string_append(num,i);
113 		// get key
114 		kvp = ini.get(num); if(0 == kvp) PANIC(MISC,num.c_str(),"expected");
115 		// and set it
116 		ret->_data[i] = kvp->getValueAsInt();
117 		// check sequence
118 		if(i > 0) { // not the first?
119 			if(ret->_data[i] <= ret->_data[i-1])
120 				PANIC(MISC,num.c_str(),"value out of sequence");
121 		}
122 	}
123 	return ret;
124 }
125 
write_ini(ostream & os)126 void CDistribution::write_ini(ostream &os) {
127 	int i;
128 	if(0 == _data) // not allocated?
129 		PANIC(MISC,_context.c_str(),"distribution not allocated");
130 	os << _context << "_num_points=" << _size << endl;
131 	for(i=0; i<_size; ++i) {
132 		os << _context << '_' << i << "=" << _data[i] << endl;
133 	}
134 }
135 
write_override_ini(ostream & os,const CDistribution * parent)136 void CDistribution::write_override_ini(ostream &os,const CDistribution *parent) {
137 	if(this == parent) // not overriden?
138 		return;
139 	write_ini(os);
140 }
141 
rnd() const142 int CDistribution::rnd() const { /* return a random number within this distribution */
143 	const int i = CRand::irand(_size-1); // target value
144 	int	x = _data[i],
145 		y = _data[i+1],
146 		ret = (x + CRand::irand(y - x));
147 	if(!ok(ret)) // out of range??
148 		PANIC(BAD_CRand,"beyond distribution range",NULL);
149 	// done
150 	return ret;
151 }
152