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