add some hacky code to allow passing sfc files with -b
[openc2e.git] / genomeFile.cpp
blob0a1c036d447db221f6e49902021301c6aab9fc47
1 /*
2 * genomeFile.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Sat 13 Nov 2004.
6 * Copyright (c) 2004-2006 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
19 #include "genome.h"
20 #include "streamutils.h"
21 #include <typeinfo>
22 #include <exception>
23 #include <iostream>
25 geneNote *genomeFile::findNote(uint8 type, uint8 subtype, uint8 which) {
26 for (vector<gene *>::iterator x = genes.begin(); x != genes.end(); x++) {
27 gene *t = *x;
28 if ((uint8)t->type() == type)
29 if ((uint8)t->subtype() == subtype)
30 if ((uint8)t->note.which == which)
31 return &t->note;
33 if (typeid(*t) == typeid(organGene))
34 for (vector<gene *>::iterator y = ((organGene *)t)->genes.begin(); y != ((organGene *)t)->genes.end(); y++) {
35 gene *s = *y;
36 if ((uint8)s->type() == type)
37 if ((uint8)s->subtype() == subtype)
38 if ((uint8)s->note.which == which)
39 return &s->note;
43 return 0;
46 void genomeFile::readNotes(istream &s) {
47 if (cversion == 3) {
48 uint16 gnover = read16(s);
49 uint16 nosvnotes = read16(s);
50 std::cout << "we have " << nosvnotes << " notes" << std::endl;
52 for (int i = 0; i < nosvnotes; i++) {
53 uint16 type = read16(s);
54 uint16 subtype = read16(s);
55 uint16 which = read16(s);
56 uint16 rule = read16(s);
58 // TODO: we currently skip all the notes (note that there are 18 and then 1!)
59 for (int i = 0; i < 19; i++) {
60 uint16 skip = read16(s);
61 uint8 *dummy = new uint8[skip]; s.read((char *)dummy, skip); delete[] dummy;
65 uint16 ver = 0;
67 while (ver != 0x02) {
68 if (s.fail() || s.eof()) throw genomeException("c3 gno loading broke ... second magic not present");
69 ver = read16(s);
73 uint16 noentries = read16(s);
75 for (int i = 0; i < noentries; i++) {
76 uint16 type = read16(s);
77 uint16 subtype = read16(s);
78 uint32 which = read32(s);
80 geneNote *n = findNote(type, subtype, which);
82 uint16 buflen = read16(s);
83 char *buffer = new char[buflen + 1];
84 s.read(buffer, buflen); buffer[buflen] = 0;
85 if (n != 0) n->description = buffer;
86 buflen = read16(s);
87 delete[] buffer; buffer = new char[buflen + 1];
88 s.read(buffer, buflen); buffer[buflen] = 0;
89 if (n != 0) n->comments = buffer;
90 delete[] buffer;
94 void genomeFile::writeNotes(ostream &s) const {
95 // TODO
98 gene *genomeFile::nextGene(istream &s) {
99 uint8 majic[3];
100 s.read((char *)majic, 3);
101 if (strncmp((char *)majic, "gen", 3) != 0) throw genomeException("bad majic for a gene");
103 s >> majic[0];
104 if (majic[0] == 'd') return 0;
105 if (majic[0] != 'e')
106 throw genomeException("bad majic at stage2 for a gene");
108 uint8 type, subtype;
109 s >> type >> subtype;
111 gene *g = 0;
113 // the switch statement of doom... is there a better way to do this?
114 switch (type) {
115 case 0:
116 switch (subtype) {
117 case 0:
118 switch (cversion) {
119 case 1: g = new oldBrainLobeGene(cversion); break;
120 case 2: g = new oldBrainLobeGene(cversion); break;
121 case 3: g = new c2eBrainLobeGene(cversion); break;
122 default: g = 0; break;
123 } break;
124 case 1: g = new organGene(cversion, true); break;
125 case 2: g = new c2eBrainTractGene(cversion); break;
126 } break;
127 case 1:
128 switch (subtype) {
129 case 0: g = new bioReceptorGene(cversion); break;
130 case 1: g = new bioEmitterGene(cversion); break;
131 case 2: g = new bioReactionGene(cversion); break;
132 case 3: g = new bioHalfLivesGene(cversion); break;
133 case 4: g = new bioInitialConcentrationGene(cversion); break;
134 case 5: g = new bioNeuroEmitterGene(cversion); break;
135 } break;
136 case 2:
137 switch (subtype) {
138 case 0: g = new creatureStimulusGene(cversion); break;
139 case 1: g = new creatureGenusGene(cversion); break;
140 case 2: g = new creatureAppearanceGene(cversion); break;
141 case 3: g = new creaturePoseGene(cversion); break;
142 case 4: g = new creatureGaitGene(cversion); break;
143 case 5: g = new creatureInstinctGene(cversion); break;
144 case 6: g = new creaturePigmentGene(cversion); break;
145 case 7: g = new creaturePigmentBleedGene(cversion); break;
146 case 8: g = new creatureFacialExpressionGene(cversion); break;
147 } break;
148 case 3:
149 switch (subtype) {
150 case 0: g = new organGene(cversion, false); break;
151 } break;
154 if (g == 0) throw genomeException("genefactory failed");
156 if (((typeid(*g) == typeid(bioReactionGene))
157 || (typeid(*g) == typeid(bioEmitterGene)))
158 || (typeid(*g) == typeid(bioReceptorGene))) {
159 if (currorgan == 0) {
160 if (cversion == 1) genes.push_back(g); // Creatures 1 doesn't have organs
161 else throw genomeException("reaction/emitter/receptor without an attached organ");
162 } else currorgan->genes.push_back(g);
163 } else {
164 genes.push_back(g);
165 if (typeid(*g) == typeid(organGene))
166 if (!((organGene *)g)->isBrain())
167 currorgan = (organGene *)g;
170 s >> *g;
172 return g;
175 istream &operator >> (istream &s, genomeFile &f) {
176 char majic[3]; s.read(majic, 3);
177 if (strncmp((char *)majic, "gen", 3) == 0) {
178 s >> majic[0];
179 if (majic[0] == 'e') f.cversion = 1;
180 else throw genomeException("bad majic for genome");
182 s.seekg(0, std::ios::beg);
183 } else {
184 if (strncmp((char *)majic, "dna", 3) != 0) throw genomeException("bad majic for genome");
186 s >> majic[0];
187 f.cversion = majic[0] - 48; // 48 = ASCII '0'
188 if ((f.cversion < 1) || (f.cversion > 3)) throw genomeException("unsupported genome version in majic");
191 //std::cout << "creaturesGenomeFile: reading genome of version " << (unsigned int)f.cversion << ".\n";
192 f.currorgan = 0;
193 while (f.nextGene(s) != 0);
194 f.currorgan = 0;
195 //std::cout << "creaturesGenomeFile: read " << (unsigned int)f.genes.size() << " top-level genes.\n";
197 return s;
200 ostream &operator << (ostream &s, const genomeFile &f) {
201 s << "dna" << char(f.cversion + 48); // 48 = ASCII '0'
203 // iterate through genes
204 for (vector<gene *>::iterator x = ((genomeFile &)f).genes.begin(); x != ((genomeFile &)f).genes.end(); x++)
205 s << **x;
207 s << "gend";
209 return s;
212 gene *genomeFile::getGene(uint8 type, uint8 subtype, unsigned int seq) {
213 unsigned int c = 0;
214 for (vector<gene *>::iterator i = genes.begin(); i != genes.end(); i++) {
215 if ((*i)->type() == type)
216 if ((*i)->subtype() == subtype) {
217 c++;
218 if (seq == c) return *i;
222 return 0;
225 uint8 geneFlags::operator () () const {
226 return ((_mutable?1:0) + (dupable?2:0) + (delable?4:0) + (maleonly?8:0) +
227 (femaleonly?16:0) + (notexpressed?32:0) + (reserved1?64:0) + (reserved2?128:0));
230 void geneFlags::operator () (uint8 f) {
231 _mutable = ((f & 1) != 0);
232 dupable = ((f & 2) != 0);
233 delable = ((f & 4) != 0);
234 maleonly = ((f & 8) != 0);
235 femaleonly = ((f & 16) != 0);
236 notexpressed = ((f & 32) != 0);
237 reserved1 = ((f & 64) != 0);
238 reserved2 = ((f & 128) != 0);
241 ostream &operator << (ostream &s, const gene &g) {
242 s << "gene" << g.type() << g.subtype();
244 s << g.note.which << g.header.generation << uint8(g.header.switchontime) << g.header.flags();
245 if (g.cversion > 1) s << g.header.mutweighting;
246 if (g.cversion == 3) s << g.header.variant;
248 g.write(s);
250 return s;
253 istream &operator >> (istream &s, gene &g) {
254 uint8 b;
255 s >> g.note.which >> g.header.generation >> b;
256 g.header.switchontime = (lifestage)b;
257 s >> b;
258 g.header.flags(b);
259 if (g.cversion > 1) s >> g.header.mutweighting;
260 if (g.cversion == 3) s >> g.header.variant;
262 g.read(s);
264 return s;
267 void bioEmitterGene::write(ostream &s) const {
268 s << organ << tissue << locus << chemical << threshold << rate << gain;
269 uint8 flags = (clear?1:0) + (digital?2:0) + (invert?4:0);
270 s << flags;
273 void bioEmitterGene::read(istream &s) {
274 s >> organ >> tissue >> locus >> chemical >> threshold >> rate >> gain;
275 uint8 flags;
276 s >> flags;
277 clear = ((flags & 1) != 0);
278 digital = ((flags & 2) != 0);
279 invert = ((flags & 4) != 0);
282 void bioHalfLivesGene::write(ostream &s) const {
283 for (int i = 0; i < 256; i++) {
284 s << halflives[i];
288 void bioHalfLivesGene::read(istream &s) {
289 for (int i = 0; i < 256; i++) {
290 s >> halflives[i];
294 void bioInitialConcentrationGene::write(ostream &s) const {
295 s << chemical << quantity;
298 void bioInitialConcentrationGene::read(istream &s) {
299 s >> chemical >> quantity;
302 void bioNeuroEmitterGene::write(ostream &s) const {
303 for (int i = 0; i < 3; i++) {
304 s << lobes[i] << neurons[i];
306 s << rate;
307 for (int i = 0; i < 4; i++) {
308 s << chemical[i] << quantity[i];
312 void bioNeuroEmitterGene::read(istream &s) {
313 for (int i = 0; i < 3; i++) {
314 s >> lobes[i] >> neurons[i];
316 s >> rate;
317 for (int i = 0; i < 4; i++) {
318 s >> chemical[i] >> quantity[i];
322 void bioReactionGene::write(ostream &s) const {
323 for (int i = 0; i < 4; i++) {
324 s << quantity[i];
325 s << reactant[i];
328 s << rate;
331 void bioReactionGene::read(istream &s) {
332 for (int i = 0; i < 4; i++) {
333 s >> quantity[i];
334 s >> reactant[i];
337 s >> rate;
340 void bioReceptorGene::write(ostream &s) const {
341 s << organ << tissue << locus << chemical << threshold << nominal << gain;
342 uint8 flags = (inverted?1:0) + (digital?2:0);
343 s << flags;
346 void bioReceptorGene::read(istream &s) {
347 s >> organ >> tissue >> locus >> chemical >> threshold >> nominal >> gain;
348 uint8 flags;
349 s >> flags;
350 inverted = ((flags & 1) != 0);
351 digital = ((flags & 2) != 0);
354 void c2eBrainLobeGene::write(ostream &s) const {
355 for (int i = 0; i < 4; i++) s << id[i];
357 write16(s, updatetime, false);
358 write16(s, x, false);
359 write16(s, y, false);
361 s << width << height;
362 s << red << green << blue;
363 s << WTA << tissue << initrulealways;
365 for (int i = 0; i < 7; i++) s << spare[i];
366 for (int i = 0; i < 48; i++) s << initialiserule[i];
367 for (int i = 0; i < 48; i++) s << updaterule[i];
370 void c2eBrainLobeGene::read(istream &s) {
371 for (int i = 0; i < 4; i++) s >> id[i];
373 updatetime = read16(s, false);
374 x = read16(s, false);
375 y = read16(s, false);
377 s >> width >> height;
378 s >> red >> green >> blue;
379 s >> WTA >> tissue >> initrulealways;
381 for (int i = 0; i < 7; i++) s >> spare[i];
382 for (int i = 0; i < 48; i++) s >> initialiserule[i];
383 for (int i = 0; i < 48; i++) s >> updaterule[i];
386 void c2eBrainTractGene::write(ostream &s) const {
387 write16(s, updatetime, false);
388 for (int i = 0; i < 4; i++) s << srclobe[i];
389 write16(s, srclobe_lowerbound, false);
390 write16(s, srclobe_upperbound, false);
391 write16(s, src_noconnections, false);
392 for (int i = 0; i < 4; i++) s << destlobe[i];
393 write16(s, destlobe_lowerbound, false);
394 write16(s, destlobe_upperbound, false);
395 write16(s, dest_noconnections, false);
396 s << migrates << norandomconnections << srcvar << destvar << initrulealways;
397 for (int i = 0; i < 5; i++) s << spare[i];
398 for (int i = 0; i < 48; i++) s << initialiserule[i];
399 for (int i = 0; i < 48; i++) s << updaterule[i];
402 void c2eBrainTractGene::read(istream &s) {
403 updatetime = read16(s, false);
404 for (int i = 0; i < 4; i++) s >> srclobe[i];
405 srclobe_lowerbound = read16(s, false);
406 srclobe_upperbound = read16(s, false);
407 src_noconnections = read16(s, false);
408 for (int i = 0; i < 4; i++) s >> destlobe[i];
409 destlobe_lowerbound = read16(s, false);
410 destlobe_upperbound = read16(s, false);
411 dest_noconnections = read16(s, false);
412 s >> migrates >> norandomconnections >> srcvar >> destvar >> initrulealways;
413 for (int i = 0; i < 5; i++) s >> spare[i];
414 for (int i = 0; i < 48; i++) s >> initialiserule[i];
415 for (int i = 0; i < 48; i++) s >> updaterule[i];
418 void creatureAppearanceGene::write(ostream &s) const {
419 s << part << variant;
420 if (cversion > 1) s << species;
423 void creatureAppearanceGene::read(istream &s) {
424 s >> part >> variant;
425 if (cversion > 1) s >> species;
428 void creatureFacialExpressionGene::write(ostream &s) const {
429 write16(s, expressionno);
430 s << weight;
432 for (int i = 0; i < 4; i++) {
433 s << drives[i] << amounts[i];
437 void creatureFacialExpressionGene::read(istream &s) {
438 expressionno = read16(s);
439 s >> weight;
441 for (int i = 0; i < 4; i++) {
442 s >> drives[i] >> amounts[i];
446 void creatureGaitGene::write(ostream &s) const {
447 s << drive;
449 for (int i = 0; i < gaitLength(); i++) {
450 s << pose[i];
454 void creatureGaitGene::read(istream &s) {
455 s >> drive;
457 for (int i = 0; i < gaitLength(); i++) {
458 s >> pose[i];
462 void creatureGenusGene::write(ostream &s) const {
463 s << genus;
465 const char *b;
467 // TODO: we read past the end of the returned buffer here!
468 b = mum.c_str();
469 for (int i = 0; i < ((cversion == 3) ? 32 : 4); i++) s << b[i];
470 b = dad.c_str();
471 for (int i = 0; i < ((cversion == 3) ? 32 : 4); i++) s << b[i];
474 void creatureGenusGene::read(istream &s) {
475 s >> genus;
477 char buf[33];
478 unsigned int len = ((cversion == 3) ? 32 : 4);
480 s.read(buf, len);
481 buf[len] = 0;
482 mum = (char *)buf;
484 s.read(buf, len);
485 buf[len] = 0;
486 dad = (char *)buf;
489 void creatureInstinctGene::write(ostream &s) const {
490 for (int i = 0; i < 3; i++) {
491 s << lobes[i] << neurons[i];
494 s << action;
495 s << drive;
496 s << level;
499 void creatureInstinctGene::read(istream &s) {
500 for (int i = 0; i < 3; i++) {
501 s >> lobes[i] >> neurons[i];
504 s >> action;
505 s >> drive;
506 s >> level;
509 void creaturePigmentGene::write(ostream &s) const {
510 s << color << amount;
513 void creaturePigmentGene::read(istream &s) {
514 s >> color >> amount;
517 void creaturePigmentBleedGene::write(ostream &s) const {
518 s << rotation << swap;
521 void creaturePigmentBleedGene::read(istream &s) {
522 s >> rotation >> swap;
525 void creaturePoseGene::write(ostream &s) const {
526 s << poseno;
528 for (int i = 0; i < poseLength(); i++) {
529 s << pose[i];
533 void creaturePoseGene::read(istream &s) {
534 s >> poseno;
536 for (int i = 0; i < poseLength(); i++) {
537 s >> pose[i];
541 void creatureStimulusGene::write(ostream &s) const {
542 s << stim << significance << sensoryneuron << intensity;
543 uint8 flags = (modulate?1:0) + (addoffset?2:0) + (whenasleep?4:0);
544 if (silent[0]) flags += 16;
545 if (silent[1]) flags += 32;
546 if (silent[2]) flags += 64;
547 if (silent[3]) flags += 128;
548 s << flags;
550 for (int i = 0; i < 4; i++) {
551 s << drives[i] << amounts[i];
555 void creatureStimulusGene::read(istream &s) {
556 s >> stim >> significance >> sensoryneuron >> intensity;
557 uint8 flags;
558 s >> flags;
559 modulate = ((flags & 1) != 0);
560 addoffset = ((flags & 2) != 0);
561 whenasleep = ((flags & 4) != 0);
563 for (int i = 0; i < 4; i++) {
564 s >> drives[i] >> amounts[i];
567 silent[0] = ((flags & 16) != 0);
568 silent[1] = ((flags & 32) != 0);
569 silent[2] = ((flags & 64) != 0);
570 silent[3] = ((flags & 128) != 0);
573 void oldBrainLobeGene::write(ostream &s) const {
574 s << x << y << width << height << perceptflag << nominalthreshold << leakagerate << reststate << inputgain;
575 s.write((char *)staterule, (cversion == 1) ? 8 : 12);
576 s << flags;
578 s << dendrite1 << dendrite2;
581 void oldBrainLobeGene::read(istream &s) {
582 s >> x >> y >> width >> height >> perceptflag >> nominalthreshold >> leakagerate >> reststate >> inputgain;
583 s.read((char *)staterule, (cversion == 1) ? 8 : 12);
584 s >> flags;
586 s >> dendrite1 >> dendrite2;
589 void organGene::write(ostream &s) const {
590 s << clockrate << damagerate << lifeforce << biotickstart << atpdamagecoefficient;
592 // iterate through children
593 for (vector<gene *>::iterator x = ((organGene *)this)->genes.begin(); x != ((organGene *)this)->genes.end(); x++)
594 s << **x;
597 void organGene::read(istream &s) {
598 s >> clockrate >> damagerate >> lifeforce >> biotickstart >> atpdamagecoefficient;
601 ostream &operator << (ostream &s, const oldDendriteInfo &i) {
602 s << i.srclobe << i.min << i.max << i.spread << i.fanout << i.minLTW << i.maxLTW;
603 s << i.minstr << i.maxstr << i.migrateflag << i.relaxsuscept << i.relaxSTW << i.LTWgainrate;
605 s << i.strgain;
606 s.write((char *)i.strgainrule, (i.cversion == 1) ? 8 : 12);
607 s << i.strloss;
608 s.write((char *)i.strlossrule, (i.cversion == 1) ? 8 : 12);
609 s.write((char *)i.susceptrule, (i.cversion == 1) ? 8 : 12);
610 s.write((char *)i.relaxrule, (i.cversion == 1) ? 8 : 12);
612 if (i.cversion == 2) {
613 s.write((char *)i.backproprule, 12);
614 s.write((char *)i.forproprule, 12);
617 return s;
620 istream &operator >> (istream &s, oldDendriteInfo &i) {
621 s >> i.srclobe >> i.min >> i.max >> i.spread >> i.fanout >> i.minLTW >> i.maxLTW;
622 s >> i.minstr >> i.maxstr >> i.migrateflag >> i.relaxsuscept >> i.relaxSTW >> i.LTWgainrate;
624 s >> i.strgain;
625 s.read((char *)i.strgainrule, (i.cversion == 1) ? 8 : 12);
626 s >> i.strloss;
627 s.read((char *)i.strlossrule, (i.cversion == 1) ? 8 : 12);
628 s.read((char *)i.susceptrule, (i.cversion == 1) ? 8 : 12);
629 s.read((char *)i.relaxrule, (i.cversion == 1) ? 8 : 12);
631 if (i.cversion == 2) {
632 s.read((char *)i.backproprule, 12);
633 s.read((char *)i.forproprule, 12);
636 return s;
639 /* vim: set noet: */