1 /*
2 * cOrganism.cc
3 * Avida
4 *
5 * Called "organism.cc" prior to 12/5/05.
6 * Copyright 1999-2011 Michigan State University. All rights reserved.
7 * Copyright 1993-2003 California Institute of Technology.
8 *
9 *
10 * This file is part of Avida.
11 *
12 * Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
14 *
15 * Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License along with Avida.
19 * If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include "cOrganism.h"
24
25 #include "avida/core/WorldDriver.h"
26
27 #include "cAvidaContext.h"
28 #include "cBioGroup.h"
29 #include "cContextPhenotype.h"
30 #include "cDeme.h"
31 #include "cEnvironment.h"
32 #include "cHardwareBase.h"
33 #include "cHardwareManager.h"
34 #include "cInstSet.h"
35 #include "cOrgSensor.h"
36 #include "cOrgSinkMessage.h"
37 #include "cPopulationCell.h"
38 #include "cStateGrid.h"
39 #include "cStringUtil.h"
40 #include "cTaskContext.h"
41 #include "cWorld.h"
42 #include "cStats.h"
43 #include "nHardware.h"
44
45 #include <algorithm>
46 #include <iomanip>
47 #include <utility>
48
49 using namespace std;
50 using namespace Avida;
51
52
cOrganism(cWorld * world,cAvidaContext & ctx,const Genome & genome,int parent_generation,eBioUnitSource src,const cString & src_args)53 cOrganism::cOrganism(cWorld* world, cAvidaContext& ctx, const Genome& genome, int parent_generation, eBioUnitSource src,
54 const cString& src_args)
55 : m_world(world)
56 , m_phenotype(world, parent_generation, world->GetHardwareManager().GetInstSet(genome.GetInstSet()).GetNumNops())
57 , m_src(src)
58 , m_src_args(src_args)
59 , m_initial_genome(genome)
60 , m_interface(NULL)
61 , m_lineage_label(-1)
62 , m_lineage(NULL)
63 , m_org_list_index(-1)
64 , m_org_display(NULL)
65 , m_queued_display_data(NULL)
66 , m_display(false)
67 , m_input_pointer(0)
68 , m_input_buf(world->GetEnvironment().GetInputSize())
69 , m_output_buf(world->GetEnvironment().GetOutputSize())
70 , m_received_messages(RECEIVED_MESSAGES_SIZE)
71 , m_cur_sg(0)
72 , m_sent_value(0)
73 , m_sent_active(false)
74 , m_test_receive_pos(0)
75 , m_pher_drop(false)
76 , frac_energy_donating(m_world->GetConfig().ENERGY_SHARING_PCT.Get())
77 , m_max_executed(-1)
78 , m_is_running(false)
79 , m_is_sleeping(false)
80 , m_is_dead(false)
81 , killed_event(false)
82 , m_net(NULL)
83 , m_msg(0)
84 , m_opinion(0)
85 , m_neighborhood(0)
86 , m_self_raw_materials(world->GetConfig().RAW_MATERIAL_AMOUNT.Get())
87 , m_other_raw_materials(0)
88 , m_num_donate(0)
89 , m_num_donate_received(0)
90 , m_amount_donate_received(0)
91 , m_num_reciprocate(0)
92 , m_failed_reputation_increases(0)
93 , m_tag(make_pair(-1, 0))
94 , m_northerly(0)
95 , m_easterly(0)
96 , m_forage_target(-1)
97 , m_has_set_ft(false)
98 , m_teach(false)
99 , m_parent_teacher(false)
100 , m_parent_ft(-1)
101 , m_parent_group(world->GetConfig().DEFAULT_GROUP.Get())
102 , m_beggar(false)
103 , m_guard(false)
104 , m_num_guard(0)
105 , m_num_deposits(0)
106 , m_amount_deposited(0)
107 , m_num_point_mut(0)
108 , m_av_in_index(-1)
109 , m_av_out_index(-1)
110 {
111 // initializing this here because it may be needed during hardware creation:
112 m_id = m_world->GetStats().GetTotCreatures();
113
114 m_hardware = m_world->GetHardwareManager().Create(ctx, this, m_initial_genome);
115
116 initialize(ctx);
117 }
118
119
120
initialize(cAvidaContext & ctx)121 void cOrganism::initialize(cAvidaContext& ctx)
122 {
123 m_phenotype.SetInstSetSize(m_hardware->GetInstSet().GetSize());
124
125 if (m_world->GetConfig().DEATH_METHOD.Get() > DEATH_METHOD_OFF) {
126 m_max_executed = m_world->GetConfig().AGE_LIMIT.Get();
127 if (m_world->GetConfig().AGE_DEVIATION.Get() > 0.0) {
128 m_max_executed += (int) (ctx.GetRandom().GetRandNormal() * m_world->GetConfig().AGE_DEVIATION.Get());
129 }
130 if (m_world->GetConfig().DEATH_METHOD.Get() == DEATH_METHOD_MULTIPLE) {
131 m_max_executed *= m_initial_genome.GetSize();
132 }
133
134 // m_max_executed must be positive or an organism will not die!
135 if (m_max_executed < 1) m_max_executed = 1;
136 }
137
138 m_repair = (m_world->GetConfig().POINT_MUT_REPAIR_START.Get());
139
140 if (m_world->GetConfig().NET_ENABLED.Get()) m_net = new cNetSupport();
141
142 // randomize the amout of raw materials an organism has at its
143 // disposal.
144 if (m_world->GetConfig().RANDOMIZE_RAW_MATERIAL_AMOUNT.Get()) {
145 int raw_mat = m_world->GetConfig().RAW_MATERIAL_AMOUNT.Get();
146 m_self_raw_materials = m_world->GetRandom().GetUInt(0, raw_mat+1);
147 }
148 }
149
150
151
~cOrganism()152 cOrganism::~cOrganism()
153 {
154 assert(m_is_running == false);
155 delete m_hardware;
156 delete m_interface;
157 if(m_net) delete m_net;
158 if(m_msg) delete m_msg;
159 if(m_opinion) delete m_opinion;
160 for (int i = 0; i < m_parasites.GetSize(); i++) delete m_parasites[i];
161 if (m_neighborhood) delete m_neighborhood;
162 delete m_org_display;
163 delete m_queued_display_data;
164 }
165
~cNetSupport()166 cOrganism::cNetSupport::~cNetSupport()
167 {
168 while (pending.GetSize()) delete pending.Pop();
169 for (int i = 0; i < received.GetSize(); i++) delete received[i];
170 }
171
SetOrgInterface(cAvidaContext & ctx,cOrgInterface * org_interface)172 void cOrganism::SetOrgInterface(cAvidaContext& ctx, cOrgInterface* org_interface)
173 {
174 delete m_interface;
175 m_interface = org_interface;
176
177 HardwareReset(ctx);
178 }
179
GetStateGrid() const180 const cStateGrid& cOrganism::GetStateGrid() const { return m_world->GetEnvironment().GetStateGrid(m_cur_sg); }
181
GetVitality() const182 double cOrganism::GetVitality() const {
183 double mean_age = m_world->GetStats().SumCreatureAge().Ave();
184 double age_stddev = m_world->GetStats().SumCreatureAge().StdDeviation();
185 int org_age = m_phenotype.GetAge();
186 const int resource = m_world->GetConfig().COLLECT_SPECIFIC_RESOURCE.Get();
187 double res_level = 0.0;
188 if (resource >= 0)
189 res_level = m_phenotype.GetCurRBinAvail(resource);
190 double vitality = 0.0;
191
192 if (org_age < (mean_age - age_stddev) || org_age > (mean_age + age_stddev)) {
193 vitality = m_world->GetConfig().VITALITY_BIN_EXTREMES.Get() * res_level;
194 } else {
195 vitality = m_world->GetConfig().VITALITY_BIN_CENTER.Get() * res_level;
196 }
197
198 return vitality;
199 }
200
UpdateOrgDisplay()201 bool cOrganism::UpdateOrgDisplay() {
202 if (m_queued_display_data != NULL) {
203 delete m_org_display;
204 m_org_display = m_queued_display_data;
205 m_queued_display_data = NULL;
206 return true;
207 }
208 else return false;
209 }
210
SetSimpDisplay(int display_part,int value)211 void cOrganism::SetSimpDisplay(int display_part, int value)
212 {
213 if (m_org_display == NULL) {
214 m_org_display = new sOrgDisplay;
215 m_display = true;
216 m_org_display->distance = -99;
217 m_org_display->direction = -99;
218 m_org_display->value = -99;
219 m_org_display->message = -99;
220
221 }
222 switch (display_part) {
223 case 0:
224 m_org_display->distance = value;
225 case 1:
226 m_org_display->direction = value;
227 case 3:
228 m_org_display->value = value;
229 default:
230 m_org_display->message = value;
231 }
232 }
233
GetRBinsTotal()234 double cOrganism::GetRBinsTotal()
235 {
236 double total = 0;
237 for(int i = 0; i < m_phenotype.GetCurRBinsAvail().GetSize(); i++) {
238 total += m_phenotype.GetCurRBinsAvail()[i];
239 }
240
241 return total;
242 }
243
SetRBins(const tArray<double> & rbins_in)244 void cOrganism::SetRBins(const tArray<double>& rbins_in)
245 {
246 m_phenotype.SetCurRBinsAvail(rbins_in);
247 }
248
SetRBin(const int index,const double value)249 void cOrganism::SetRBin(const int index, const double value)
250 {
251 m_phenotype.SetCurRBinAvail(index, value);
252 }
253
AddToRBin(const int index,const double value)254 void cOrganism::AddToRBin(const int index, const double value)
255 {
256 m_phenotype.AddToCurRBinAvail(index, value);
257 if (value > 0) {
258 m_phenotype.AddToCurRBinTotal(index, value);
259 }
260 }
261
IncCollectSpecCount(const int spec_id)262 void cOrganism::IncCollectSpecCount(const int spec_id)
263 {
264 int current_count = m_phenotype.GetCurCollectSpecCount(spec_id);
265 m_phenotype.SetCurCollectSpecCount(spec_id, current_count + 1);
266 }
267
ReceiveValue()268 int cOrganism::ReceiveValue()
269 {
270 assert(m_interface);
271 const int out_value = m_interface->ReceiveValue();
272 return out_value;
273 }
274
SellValue(const int data,const int label,const int sell_price)275 void cOrganism::SellValue(const int data, const int label, const int sell_price)
276 {
277 if (m_sold_items.GetSize() < 10)
278 {
279 assert (m_interface);
280 m_interface->SellValue(data, label, sell_price, m_id);
281 m_world->GetStats().AddMarketItemSold();
282 }
283 }
284
BuyValue(const int label,const int buy_price)285 int cOrganism::BuyValue(const int label, const int buy_price)
286 {
287 assert (m_interface);
288 const int receive_value = m_interface->BuyValue(label, buy_price);
289 if (receive_value != 0)
290 {
291 // put this value in storage place for recieved values
292 m_received_messages.Add(receive_value);
293 // update loss of buy_price to merit
294 double cur_merit = GetPhenotype().GetMerit().GetDouble();
295 cur_merit -= buy_price;
296 UpdateMerit(cur_merit);
297 m_world->GetStats().AddMarketItemBought();
298 }
299 return receive_value;
300 }
301
302
DoInput(const int value)303 void cOrganism::DoInput(const int value)
304 {
305 DoInput(m_input_buf, m_output_buf, value);
306 }
307
308
DoInput(tBuffer<int> & input_buffer,tBuffer<int> & output_buffer,const int value)309 void cOrganism::DoInput(tBuffer<int>& input_buffer, tBuffer<int>& output_buffer, const int value)
310 {
311 input_buffer.Add(value);
312 m_phenotype.TestInput(input_buffer, output_buffer);
313 }
314
315
DoOutput(cAvidaContext & ctx,const bool on_divide,cContextPhenotype * context_phenotype)316 void cOrganism::DoOutput(cAvidaContext& ctx, const bool on_divide, cContextPhenotype* context_phenotype)
317 {
318 if (m_net) m_net->valid = false;
319 if(m_world->GetConfig().USE_AVATARS.Get()) doAVOutput(ctx, m_input_buf, m_output_buf, on_divide, false, context_phenotype);
320 else doOutput(ctx, m_input_buf, m_output_buf, on_divide, false, context_phenotype);
321 }
322
323
DoOutput(cAvidaContext & ctx,const int value)324 void cOrganism::DoOutput(cAvidaContext& ctx, const int value)
325 {
326 m_output_buf.Add(value);
327 NetValidate(ctx, value);
328 if(m_world->GetConfig().USE_AVATARS.Get()) doAVOutput(ctx, m_input_buf, m_output_buf, false, false);
329 else doOutput(ctx, m_input_buf, m_output_buf, false, false);
330 }
331
DoOutput(cAvidaContext & ctx,const int value,bool is_parasite,cContextPhenotype * context_phenotype)332 void cOrganism::DoOutput(cAvidaContext& ctx, const int value, bool is_parasite, cContextPhenotype* context_phenotype)
333 {
334 m_output_buf.Add(value);
335 NetValidate(ctx, value);
336 if(m_world->GetConfig().USE_AVATARS.Get()) doAVOutput(ctx, m_input_buf, m_output_buf, false, (bool)is_parasite, context_phenotype);
337 else doOutput(ctx, m_input_buf, m_output_buf, false, (bool)is_parasite, context_phenotype);
338 }
339
DoOutput(cAvidaContext & ctx,tBuffer<int> & input_buffer,tBuffer<int> & output_buffer,const int value)340 void cOrganism::DoOutput(cAvidaContext& ctx, tBuffer<int>& input_buffer, tBuffer<int>& output_buffer, const int value)
341 {
342 output_buffer.Add(value);
343 NetValidate(ctx, value);
344 if(m_world->GetConfig().USE_AVATARS.Get()) doAVOutput(ctx, input_buffer, output_buffer, false, false);
345 else doOutput(ctx, input_buffer, output_buffer, false, false);
346 }
347
348
doOutput(cAvidaContext & ctx,tBuffer<int> & input_buffer,tBuffer<int> & output_buffer,const bool on_divide,bool is_parasite,cContextPhenotype * context_phenotype)349 void cOrganism::doOutput(cAvidaContext& ctx,
350 tBuffer<int>& input_buffer,
351 tBuffer<int>& output_buffer,
352 const bool on_divide,
353 bool is_parasite,
354 cContextPhenotype* context_phenotype)
355 {
356 const int deme_id = m_interface->GetDemeID();
357 const tArray<double> & global_resource_count = m_interface->GetResources(ctx);
358 const tArray<double> & deme_resource_count = m_interface->GetDemeResources(deme_id, ctx);
359 const tArray< tArray<int> > & cell_id_lists = m_interface->GetCellIdLists();
360
361 tList<tBuffer<int> > other_input_list;
362 tList<tBuffer<int> > other_output_list;
363
364 // If tasks require us to consider neighbor inputs, collect them...
365 if (m_world->GetEnvironment().UseNeighborInput()) {
366 const int num_neighbors = m_interface->GetNumNeighbors();
367 for (int i = 0; i < num_neighbors; i++) {
368 m_interface->Rotate();
369 cOrganism * cur_neighbor = m_interface->GetNeighbor();
370 if (cur_neighbor == NULL) continue;
371
372 other_input_list.Push( &(cur_neighbor->m_input_buf) );
373 }
374 }
375
376 // If tasks require us to consider neighbor outputs, collect them...
377 if (m_world->GetEnvironment().UseNeighborOutput()) {
378 const int num_neighbors = m_interface->GetNumNeighbors();
379 for (int i = 0; i < num_neighbors; i++) {
380 m_interface->Rotate();
381 cOrganism * cur_neighbor = m_interface->GetNeighbor();
382 if (cur_neighbor == NULL) continue;
383
384 other_output_list.Push( &(cur_neighbor->m_output_buf) );
385 }
386 }
387
388 // Do the testing of tasks performed...
389
390
391 tArray<double> global_res_change(global_resource_count.GetSize());
392 global_res_change.SetAll(0.0);
393 tArray<double> deme_res_change(deme_resource_count.GetSize());
394 deme_res_change.SetAll(0.0);
395 tArray<cString> insts_triggered;
396
397 tBuffer<int>* received_messages_point = &m_received_messages;
398 if (!m_world->GetConfig().SAVE_RECEIVED.Get()) received_messages_point = NULL;
399
400 cTaskContext taskctx(this, input_buffer, output_buffer, other_input_list, other_output_list,
401 m_hardware->GetExtendedMemory(), on_divide, received_messages_point);
402
403 //combine global and deme resource counts
404 tArray<double> globalAndDeme_resource_count = global_resource_count + deme_resource_count;
405 tArray<double> globalAndDeme_res_change = global_res_change + deme_res_change;
406
407 // set any resource amount to 0 if a cell cannot access this resource
408 int cell_id=GetCellID();
409 if (cell_id_lists.GetSize())
410 {
411 for (int i=0; i<cell_id_lists.GetSize(); i++)
412 {
413 // if cell_id_lists have been set then we have to check if this cell is in the list
414 if (cell_id_lists[i].GetSize()) {
415 int j;
416 for (j=0; j<cell_id_lists[i].GetSize(); j++)
417 {
418 if (cell_id==cell_id_lists[i][j])
419 break;
420 }
421 if (j==cell_id_lists[i].GetSize())
422 globalAndDeme_resource_count[i]=0;
423 }
424 }
425 }
426
427 bool task_completed = m_phenotype.TestOutput(ctx, taskctx, globalAndDeme_resource_count,
428 m_phenotype.GetCurRBinsAvail(), globalAndDeme_res_change,
429 insts_triggered, is_parasite, context_phenotype);
430
431 // Handle merit increases that take the organism above it's current population merit
432 if (m_world->GetConfig().MERIT_INC_APPLY_IMMEDIATE.Get()) {
433 double cur_merit = m_phenotype.CalcCurrentMerit();
434 if (m_phenotype.GetMerit().GetDouble() < cur_merit) m_interface->UpdateMerit(cur_merit);
435 }
436
437 //disassemble global and deme resource counts
438 global_res_change = globalAndDeme_res_change.Subset(0, global_res_change.GetSize());
439 deme_res_change = globalAndDeme_res_change.Subset(global_res_change.GetSize(), globalAndDeme_res_change.GetSize());
440
441 if(m_world->GetConfig().ENERGY_ENABLED.Get() && m_world->GetConfig().APPLY_ENERGY_METHOD.Get() == 1 && task_completed) {
442 m_phenotype.RefreshEnergy();
443 m_phenotype.ApplyToEnergyStore();
444 double newMerit = m_phenotype.ConvertEnergyToMerit(m_phenotype.GetStoredEnergy() * m_phenotype.GetEnergyUsageRatio());
445 m_interface->UpdateMerit(newMerit);
446 if(GetPhenotype().GetMerit().GetDouble() == 0.0) {
447 GetPhenotype().SetToDie();
448 }
449 }
450 m_interface->UpdateResources(ctx, global_res_change);
451
452 //update deme resources
453 m_interface->UpdateDemeResources(ctx, deme_res_change);
454
455 for (int i = 0; i < insts_triggered.GetSize(); i++)
456 m_hardware->ProcessBonusInst(ctx, m_hardware->GetInstSet().GetInst(insts_triggered[i]));
457 }
458
doAVOutput(cAvidaContext & ctx,tBuffer<int> & input_buffer,tBuffer<int> & output_buffer,const bool on_divide,bool is_parasite,cContextPhenotype * context_phenotype)459 void cOrganism::doAVOutput(cAvidaContext& ctx,
460 tBuffer<int>& input_buffer,
461 tBuffer<int>& output_buffer,
462 const bool on_divide,
463 bool is_parasite,
464 cContextPhenotype* context_phenotype)
465 {
466 //Avatar output has to be seperate from doOutput to ensure avatars, not the true orgs, are triggering reactions
467 // const int deme_id = m_interface->GetDemeID();
468 const tArray<double> & avatar_resource_count = m_interface->GetAVResources(ctx);
469 // const tArray<double> & deme_resource_count = m_interface->GetDemeResources(deme_id, ctx); //todo: DemeAVResources
470 const tArray< tArray<int> > & cell_id_lists = m_interface->GetCellIdLists();
471
472 tList<tBuffer<int> > other_input_list;
473 tList<tBuffer<int> > other_output_list;
474
475 // If tasks require us to consider neighbor inputs, collect them...
476 if (m_world->GetEnvironment().UseNeighborInput()) {
477 const int num_neighbors = m_interface->GetAVNumNeighbors();
478 for (int i = 0; i < num_neighbors; i++) {
479 m_interface->Rotate();
480 const tArray<cOrganism*>& cur_neighbors = m_interface->GetFacedAVs();
481 for (int i = 0; i < cur_neighbors.GetSize(); i++) {
482 if (cur_neighbors[i] == NULL) continue;
483 other_input_list.Push( &(cur_neighbors[i]->m_input_buf) );
484 }
485 }
486 }
487
488 // If tasks require us to consider neighbor outputs, collect them...
489 if (m_world->GetEnvironment().UseNeighborOutput()) {
490 const int num_neighbors = m_interface->GetAVNumNeighbors();
491 for (int i = 0; i < num_neighbors; i++) {
492 m_interface->Rotate();
493 const tArray<cOrganism*>& cur_neighbors = m_interface->GetFacedAVs();
494 for (int i = 0; i < cur_neighbors.GetSize(); i++) {
495 if (cur_neighbors[i] == NULL) continue;
496 other_output_list.Push( &(cur_neighbors[i]->m_output_buf) );
497 }
498 }
499 }
500
501 // Do the testing of tasks performed...
502 tArray<double> avatar_res_change(avatar_resource_count.GetSize());
503 avatar_res_change.SetAll(0.0);
504 // tArray<double> deme_res_change(deme_resource_count.GetSize());
505 // deme_res_change.SetAll(0.0);
506 tArray<cString> insts_triggered;
507
508 tBuffer<int>* received_messages_point = &m_received_messages;
509 if (!m_world->GetConfig().SAVE_RECEIVED.Get()) received_messages_point = NULL;
510
511 cTaskContext taskctx(this, input_buffer, output_buffer, other_input_list, other_output_list,
512 m_hardware->GetExtendedMemory(), on_divide, received_messages_point);
513
514 //combine global and deme resource counts
515 tArray<double> avatarAndDeme_resource_count = avatar_resource_count; // + deme_resource_count;
516 tArray<double> avatarAndDeme_res_change = avatar_res_change; // + deme_res_change;
517
518 // set any resource amount to 0 if a cell cannot access this resource
519 int cell_id = m_interface->GetAVCellID();
520 if (cell_id_lists.GetSize())
521 {
522 for (int i=0; i<cell_id_lists.GetSize(); i++)
523 {
524 // if cell_id_lists have been set then we have to check if this cell is in the list
525 if (cell_id_lists[i].GetSize()) {
526 int j;
527 for (j=0; j<cell_id_lists[i].GetSize(); j++)
528 {
529 if (cell_id==cell_id_lists[i][j])
530 break;
531 }
532 if (j==cell_id_lists[i].GetSize())
533 avatarAndDeme_resource_count[i]=0;
534 }
535 }
536 }
537
538 bool task_completed = m_phenotype.TestOutput(ctx, taskctx, avatarAndDeme_resource_count,
539 m_phenotype.GetCurRBinsAvail(), avatarAndDeme_res_change,
540 insts_triggered, is_parasite, context_phenotype);
541
542 // Handle merit increases that take the organism above it's current population merit
543 if (m_world->GetConfig().MERIT_INC_APPLY_IMMEDIATE.Get()) {
544 double cur_merit = m_phenotype.CalcCurrentMerit();
545 if (m_phenotype.GetMerit().GetDouble() < cur_merit) m_interface->UpdateMerit(cur_merit);
546 }
547
548 //disassemble avatar and deme resource counts
549 avatar_res_change = avatarAndDeme_res_change.Subset(0, avatar_res_change.GetSize());
550 // deme_res_change = avatarAndDeme_res_change.Subset(avatar_res_change.GetSize(), avatarAndDeme_res_change.GetSize());
551
552 if(m_world->GetConfig().ENERGY_ENABLED.Get() && m_world->GetConfig().APPLY_ENERGY_METHOD.Get() == 1 && task_completed) {
553 m_phenotype.RefreshEnergy();
554 m_phenotype.ApplyToEnergyStore();
555 double newMerit = m_phenotype.ConvertEnergyToMerit(m_phenotype.GetStoredEnergy() * m_phenotype.GetEnergyUsageRatio());
556 m_interface->UpdateMerit(newMerit);
557 if(GetPhenotype().GetMerit().GetDouble() == 0.0) {
558 GetPhenotype().SetToDie();
559 }
560 }
561 m_interface->UpdateAVResources(ctx, avatar_res_change);
562 //update deme resources
563 // m_interface->UpdateDemeResources(ctx, deme_res_change);
564
565 for (int i = 0; i < insts_triggered.GetSize(); i++)
566 m_hardware->ProcessBonusInst(ctx, m_hardware->GetInstSet().GetInst(insts_triggered[i]));
567 }
568
NetGet(cAvidaContext & ctx,int & value,int & seq)569 void cOrganism::NetGet(cAvidaContext& ctx, int& value, int& seq)
570 {
571 assert(m_net);
572 seq = m_net->seq.GetSize();
573 m_net->seq.Resize(seq + 1);
574 value = ctx.GetRandom().GetUInt(1 << 16);
575 m_net->seq[seq].SetValue(value);
576 }
577
NetSend(cAvidaContext & ctx,int value)578 void cOrganism::NetSend(cAvidaContext& ctx, int value)
579 {
580 assert(m_net);
581 int index = -1;
582
583 // Search for previously sent value
584 for (int i = m_net->sent.GetSize() - 1; i >= 0; i--) {
585 if (m_net->sent[i].GetValue() == value) {
586 index = i;
587 m_net->sent[i].SetSent();
588 break;
589 }
590 }
591
592 // If not found, add new message
593 if (index == -1) {
594 index = m_net->sent.GetSize();
595 m_net->sent.Resize(index + 1);
596 m_net->sent[index] = cOrgSourceMessage(value);
597 }
598
599 // Test if this message will be dropped
600 const double drop_prob = m_world->GetConfig().NET_DROP_PROB.Get();
601 if (drop_prob > 0.0 && ctx.GetRandom().P(drop_prob)) {
602 m_net->sent[index].SetDropped();
603 return;
604 }
605
606 // Test if this message will be corrupted
607 int actual_value = value;
608 const double mut_prob = m_world->GetConfig().NET_MUT_PROB.Get();
609 if (mut_prob > 0.0 && ctx.GetRandom().P(mut_prob)) {
610 switch (m_world->GetConfig().NET_MUT_TYPE.Get())
611 {
612 case 0: // Flip a single random bit
613 actual_value ^= 1 << ctx.GetRandom().GetUInt(31);
614 m_net->sent[index].SetCorrupted();
615 break;
616 case 1: // Flip the last bit
617 actual_value ^= 1;
618 m_net->sent[index].SetCorrupted();
619 break;
620 default:
621 // invalid selection, no action
622 break;
623 }
624 }
625
626 assert(m_interface);
627 cOrgSinkMessage* msg = new cOrgSinkMessage(m_interface->GetCellID(), value, actual_value);
628 m_net->pending.Push(msg);
629 }
630
NetReceive(int & value)631 bool cOrganism::NetReceive(int& value)
632 {
633 assert(m_net && m_interface);
634 cOrgSinkMessage* msg = m_interface->NetReceive();
635 if (msg == NULL) {
636 value = 0;
637 return false;
638 }
639
640 m_net->received.Push(msg);
641 value = msg->GetActualValue();
642 return true;
643 }
644
NetValidate(cAvidaContext & ctx,int value)645 void cOrganism::NetValidate(cAvidaContext& ctx, int value)
646 {
647 if (!m_net) return;
648
649 m_net->valid = false;
650
651 if (0xFFFF0000 & value) return;
652
653 for (int i = 0; i < m_net->received.GetSize(); i++) {
654 cOrgSinkMessage* msg = m_net->received[i];
655 if (!msg->GetValidated() && (msg->GetOriginalValue() & 0xFFFF) == value) {
656 msg->SetValidated();
657 assert(m_interface);
658 m_net->valid = m_interface->NetRemoteValidate(ctx, msg);
659 break;
660 }
661 }
662 }
663
NetRemoteValidate(cAvidaContext & ctx,int value)664 bool cOrganism::NetRemoteValidate(cAvidaContext& ctx, int value)
665 {
666 assert(m_net);
667
668 bool found = false;
669 for (int i = m_net->last_seq; i < m_net->seq.GetSize(); i++) {
670 cOrgSeqMessage& msg = m_net->seq[i];
671 if (msg.GetValue() == value && !msg.GetReceived()) {
672 m_net->seq[i].SetReceived();
673 found = true;
674 break;
675 }
676 }
677 if (!found) return false;
678
679 m_net->valid = false;
680 int& completed = m_net->completed;
681 completed = 0;
682 while (m_net->last_seq < m_net->seq.GetSize() && m_net->seq[m_net->last_seq].GetReceived()) {
683 completed++;
684 m_net->last_seq++;
685 }
686
687 if (completed) {
688 assert(m_interface);
689 const tArray<double>& resource_count = m_interface->GetResources(ctx);
690
691 tList<tBuffer<int> > other_input_list;
692 tList<tBuffer<int> > other_output_list;
693
694 // If tasks require us to consider neighbor inputs, collect them...
695 if (m_world->GetEnvironment().UseNeighborInput()) {
696 const int num_neighbors = m_interface->GetNumNeighbors();
697 for (int i = 0; i < num_neighbors; i++) {
698 m_interface->Rotate();
699 cOrganism * cur_neighbor = m_interface->GetNeighbor();
700 if (cur_neighbor == NULL) continue;
701
702 other_input_list.Push( &(cur_neighbor->m_input_buf) );
703 }
704 }
705
706 // If tasks require us to consider neighbor outputs, collect them...
707 if (m_world->GetEnvironment().UseNeighborOutput()) {
708 const int num_neighbors = m_interface->GetNumNeighbors();
709 for (int i = 0; i < num_neighbors; i++) {
710 m_interface->Rotate();
711 cOrganism * cur_neighbor = m_interface->GetNeighbor();
712 if (cur_neighbor == NULL) continue;
713
714 other_output_list.Push( &(cur_neighbor->m_output_buf) );
715 }
716 }
717
718 // Do the testing of tasks performed...
719 m_output_buf.Add(value);
720 tArray<double> res_change(resource_count.GetSize());
721 tArray<cString> insts_triggered;
722
723 cTaskContext taskctx(this, m_input_buf, m_output_buf, other_input_list, other_output_list,
724 m_hardware->GetExtendedMemory());
725 m_phenotype.TestOutput(ctx, taskctx, resource_count, m_phenotype.GetCurRBinsAvail(), res_change, insts_triggered);
726 m_interface->UpdateResources(ctx, res_change);
727
728 for (int i = 0; i < insts_triggered.GetSize(); i++)
729 m_hardware->ProcessBonusInst(ctx, m_hardware->GetInstSet().GetInst(insts_triggered[i]));
730 }
731
732 return true;
733 }
734
HardwareReset(cAvidaContext & ctx)735 void cOrganism::HardwareReset(cAvidaContext& ctx)
736 {
737 if (m_world->GetEnvironment().GetNumStateGrids() > 0 && m_interface) {
738 // Select random state grid in the environment
739 m_cur_sg = m_interface->GetStateGridID(ctx);
740
741 const cStateGrid& sg = GetStateGrid();
742
743 tArray<int> sg_state(3 + sg.GetNumStates(), 0);
744
745 sg_state[0] = sg.GetInitialX();
746 sg_state[1] = sg.GetInitialY();
747 sg_state[2] = sg.GetInitialFacing();
748
749 m_hardware->SetupExtendedMemory(sg_state);
750 }
751
752 if (m_net) {
753 while (m_net->pending.GetSize()) delete m_net->pending.Pop();
754 for (int i = 0; i < m_net->received.GetSize(); i++) delete m_net->received[i];
755 m_net->received.Resize(0);
756 m_net->sent.Resize(0);
757 m_net->seq.Resize(0);
758 }
759
760 if (!m_world->GetConfig().INHERIT_OPINION.Get()) {
761 ClearOpinion();
762 }
763 delete m_org_display;
764 delete m_queued_display_data;
765 m_org_display = NULL;
766 m_queued_display_data = NULL;
767 m_display = false;
768 }
769
NotifyDeath(cAvidaContext & ctx)770 void cOrganism::NotifyDeath(cAvidaContext& ctx)
771 {
772 // Update Sleeping State
773 if (m_is_sleeping) {
774 m_is_sleeping = false;
775 GetDeme()->DecSleepingCount();
776 }
777
778 // Return currently stored internal resources to the world
779 if (m_world->GetConfig().USE_RESOURCE_BINS.Get() && m_world->GetConfig().RETURN_STORED_ON_DEATH.Get()) {
780 m_interface->UpdateResources(ctx, GetRBins());
781 }
782
783 // Make sure the group composition is updated.
784 if (m_world->GetConfig().USE_FORM_GROUPS.Get() && HasOpinion()) m_interface->LeaveGroup(GetOpinion().first);
785 }
786
787
788
InjectParasite(cBioUnit * parent,const cString & label,const Sequence & injected_code)789 bool cOrganism::InjectParasite(cBioUnit* parent, const cString& label, const Sequence& injected_code)
790 {
791 assert(m_interface);
792 return m_interface->InjectParasite(this, parent, label, injected_code);
793 }
794
ParasiteInfectHost(cBioUnit * parasite)795 bool cOrganism::ParasiteInfectHost(cBioUnit* parasite)
796 {
797 if (!m_hardware->ParasiteInfectHost(parasite)) return false;
798
799 m_parasites.Push(parasite);
800 return true;
801 }
802
ClearParasites()803 void cOrganism::ClearParasites()
804 {
805 for (int i = 0; i < m_parasites.GetSize(); i++) delete m_parasites[i];
806 m_parasites.Resize(0);
807 }
808
809
CalcMeritRatio()810 double cOrganism::CalcMeritRatio()
811 {
812 const double age = (double) m_phenotype.GetAge();
813 const double merit = m_phenotype.GetMerit().GetDouble();
814 return (merit > 0.0) ? (age / merit ) : age;
815 }
816
817
GetTestOnDivide() const818 bool cOrganism::GetTestOnDivide() const { return m_interface->TestOnDivide(); }
GetSterilizeUnstable() const819 int cOrganism::GetSterilizeUnstable() const { return m_world->GetConfig().STERILIZE_UNSTABLE.Get(); }
820
GetRevertFatal() const821 bool cOrganism::GetRevertFatal() const { return m_world->GetConfig().REVERT_FATAL.Get(); }
GetRevertNeg() const822 bool cOrganism::GetRevertNeg() const { return m_world->GetConfig().REVERT_DETRIMENTAL.Get(); }
GetRevertNeut() const823 bool cOrganism::GetRevertNeut() const { return m_world->GetConfig().REVERT_NEUTRAL.Get(); }
GetRevertPos() const824 bool cOrganism::GetRevertPos() const { return m_world->GetConfig().REVERT_BENEFICIAL.Get(); }
GetRevertTaskLoss() const825 bool cOrganism::GetRevertTaskLoss() const { return m_world->GetConfig().REVERT_TASKLOSS.Get(); }
GetRevertEquals() const826 bool cOrganism::GetRevertEquals() const { return m_world->GetConfig().REVERT_EQUALS.Get(); }
827
GetSterilizeFatal() const828 bool cOrganism::GetSterilizeFatal() const { return m_world->GetConfig().STERILIZE_FATAL.Get(); }
GetSterilizeNeg() const829 bool cOrganism::GetSterilizeNeg() const { return m_world->GetConfig().STERILIZE_DETRIMENTAL.Get(); }
GetSterilizeNeut() const830 bool cOrganism::GetSterilizeNeut() const { return m_world->GetConfig().STERILIZE_NEUTRAL.Get(); }
GetSterilizePos() const831 bool cOrganism::GetSterilizePos() const { return m_world->GetConfig().STERILIZE_BENEFICIAL.Get(); }
GetSterilizeTaskLoss() const832 bool cOrganism::GetSterilizeTaskLoss() const { return m_world->GetConfig().STERILIZE_TASKLOSS.Get(); }
GetNeutralMin() const833 double cOrganism::GetNeutralMin() const { return m_world->GetConfig().NEUTRAL_MIN.Get(); }
GetNeutralMax() const834 double cOrganism::GetNeutralMax() const { return m_world->GetConfig().NEUTRAL_MAX.Get(); }
835
836
PrintStatus(ostream & fp,const cString & next_name)837 void cOrganism::PrintStatus(ostream& fp, const cString& next_name)
838 {
839 fp << "---------------------------" << endl;
840 fp << "U:" << m_world->GetStats().GetUpdate() << endl;
841 m_hardware->PrintStatus(fp);
842 m_phenotype.PrintStatus(fp);
843 fp << endl;
844
845 fp << setbase(16) << setfill('0');
846
847 fp << "Input (env):";
848 for (int i = 0; i < m_input_buf.GetCapacity(); i++) {
849 int j = i; // temp holder, because GetInputAt self adjusts the input pointer
850 fp << " 0x" << setw(8) << m_interface->GetInputAt(j);
851 }
852 fp << endl;
853
854 fp << "Input (buf):";
855 for (int i = 0; i < m_hardware->GetInputBuf().GetNumStored(); i++) fp << " 0x" << setw(8) << m_hardware->GetInputBuf()[i];
856 fp << endl;
857
858 fp << "Output: ";
859 for (int i = 0; i < m_hardware->GetOutputBuf().GetNumStored(); i++) fp << " 0x" << setw(8) << m_hardware->GetOutputBuf()[i];
860 fp << endl;
861
862 fp << setfill(' ') << setbase(10);
863
864 fp << "---------------------------" << endl;
865 fp << "ABOUT TO EXECUTE: " << next_name << endl;
866 }
867
PrintMiniTraceStatus(cAvidaContext & ctx,ostream & fp,const cString & next_name)868 void cOrganism::PrintMiniTraceStatus(cAvidaContext& ctx, ostream & fp, const cString& next_name)
869 {
870 m_hardware->PrintMiniTraceStatus(ctx, fp, next_name);
871 }
872
PrintMiniTraceSuccess(ostream & fp,const int exec_success)873 void cOrganism::PrintMiniTraceSuccess(ostream & fp, const int exec_success)
874 {
875 m_hardware->PrintMiniTraceSuccess(fp, exec_success);
876 }
877
PrintFinalStatus(ostream & fp,int time_used,int time_allocated) const878 void cOrganism::PrintFinalStatus(ostream& fp, int time_used, int time_allocated) const
879 {
880 fp << "---------------------------" << endl;
881 m_phenotype.PrintStatus(fp);
882 fp << endl;
883
884 if (time_used == time_allocated) {
885 fp << endl << "# TIMEOUT: No offspring produced." << endl;
886 } else if (m_hardware->GetMemory().GetSize() == 0) {
887 fp << endl << "# ORGANISM DEATH: No offspring produced." << endl;
888 } else {
889 fp << endl;
890 fp << "# Final Memory: " << m_hardware->GetMemory().AsString() << endl;
891 fp << "# Child Memory: " << m_offspring_genome.GetSequence().AsString() << endl;
892 }
893 }
894
Divide_CheckViable(cAvidaContext & ctx)895 bool cOrganism::Divide_CheckViable(cAvidaContext& ctx)
896 {
897 // Make sure required task (if any) has been performed...
898 const int required_task = m_world->GetConfig().REQUIRED_TASK.Get();
899 const int immunity_task = m_world->GetConfig().IMMUNITY_TASK.Get();
900 if (m_world->GetConfig().REQUIRED_PRED_HABITAT.Get() != -1 || m_world->GetConfig().REQUIRED_PREY_HABITAT.Get() != -1) {
901 int habitat_required = -1;
902 double required_value = 0;
903 if (m_forage_target == -2) {
904 habitat_required = m_world->GetConfig().REQUIRED_PRED_HABITAT.Get();
905 required_value = m_world->GetConfig().REQUIRED_PRED_HABITAT_VALUE.Get();
906 }
907 else {
908 habitat_required = m_world->GetConfig().REQUIRED_PREY_HABITAT.Get();
909 required_value = m_world->GetConfig().REQUIRED_PREY_HABITAT_VALUE.Get();
910 }
911 if (habitat_required != -1) {
912 bool has_req_res = false;
913 const cResourceLib& resource_lib = m_world->GetEnvironment().GetResourceLib();
914 tArray<double> resource_count;
915 if (!m_world->GetConfig().USE_AVATARS.Get()) resource_count = m_interface->GetResources(ctx);
916 else resource_count = m_interface->GetAVResources(ctx);
917 for (int i = 0; i < resource_count.GetSize(); i ++) {
918 if (resource_lib.GetResource(i)->GetHabitat() == habitat_required && resource_count[i] >= required_value) {
919 has_req_res = true;
920 break;
921 }
922 }
923 if (!has_req_res) return false;
924 }
925 }
926
927 if (required_task != -1 && m_phenotype.GetCurTaskCount()[required_task] == 0) {
928 if (immunity_task ==-1 || m_phenotype.GetCurTaskCount()[immunity_task] == 0) {
929 Fault(FAULT_LOC_DIVIDE, FAULT_TYPE_ERROR,
930 cStringUtil::Stringf("Lacks required task (%d)", required_task));
931 return false; // (divide fails)
932 }
933 }
934
935 if (GetPhenotype().GetCurBonus() < m_world->GetConfig().REQUIRED_BONUS.Get()) return false;
936
937 const int required_reaction = m_world->GetConfig().REQUIRED_REACTION.Get();
938 const int immunity_reaction = m_world->GetConfig().IMMUNITY_REACTION.Get();
939 const int single_reaction = m_world->GetConfig().REQUIRE_SINGLE_REACTION.Get();
940
941 if (single_reaction == 0 && required_reaction != -1 && m_phenotype.GetCurReactionCount()[required_reaction] == 0 && \
942 m_phenotype.GetStolenReactionCount()[required_reaction] == 0) {
943 if (immunity_reaction == -1 || m_phenotype.GetCurReactionCount()[immunity_reaction] == 0) {
944 Fault(FAULT_LOC_DIVIDE, FAULT_TYPE_ERROR,
945 cStringUtil::Stringf("Lacks required reaction (%d)", required_reaction));
946 return false; // (divide fails)
947 }
948 }
949
950 if (single_reaction != 0)
951 {
952 bool toFail = true;
953 tArray<int> reactionCounts = m_phenotype.GetCurReactionCount();
954 for (int i=0; i<reactionCounts.GetSize(); i++) {
955 if (reactionCounts[i] > 0) toFail = false;
956 }
957
958 if (toFail) {
959 const tArray<int> stolenReactions = m_phenotype.GetStolenReactionCount();
960 for (int i = 0; i < stolenReactions.GetSize(); i++) {
961 if (stolenReactions[i] > 0) toFail = false;
962 }
963 }
964
965 if (toFail) {
966 Fault(FAULT_LOC_DIVIDE, FAULT_TYPE_ERROR, cStringUtil::Stringf("Lacks any reaction required for divide"));
967 return false; // (divide fails)
968 }
969 }
970
971 // Test for required resource availability (must be stored in an internal resource bin)
972 const int required_resource = m_world->GetConfig().REQUIRED_RESOURCE.Get();
973 const double required_resource_level = m_world->GetConfig().REQUIRED_RESOURCE_LEVEL.Get();
974 if (required_resource != -1 && required_resource_level > 0.0) {
975 const double resource_level = m_phenotype.GetCurRBinAvail(required_resource);
976 if (resource_level < required_resource_level) return false;
977 else AddToRBin(required_resource, -required_resource_level);
978 }
979
980 // Make sure the parent is fertile
981 if ( m_phenotype.IsFertile() == false ) {
982 Fault(FAULT_LOC_DIVIDE, FAULT_TYPE_ERROR, "Infertile organism");
983 return false; // (divide fails)
984 }
985
986 return true; // Organism has no problem with divide...
987 }
988
989
990 // This gets called after a successful divide to deal with the child.
991 // Returns true if parent lives through this process.
992
ActivateDivide(cAvidaContext & ctx,cContextPhenotype * context_phenotype)993 bool cOrganism::ActivateDivide(cAvidaContext& ctx, cContextPhenotype* context_phenotype)
994 {
995 assert(m_interface);
996 // Test tasks one last time before actually dividing, pass true so
997 // know that should only test "divide" tasks here
998 DoOutput(ctx, true, context_phenotype);
999
1000 // Activate the child! (Keep Last: may kill this organism!)
1001 return m_interface->Divide(ctx, this, m_offspring_genome);
1002 }
1003
1004
Fault(int fault_loc,int fault_type,cString fault_desc)1005 void cOrganism::Fault(int fault_loc, int fault_type, cString fault_desc)
1006 {
1007 (void) fault_loc;
1008 (void) fault_type;
1009 (void) fault_desc;
1010
1011 // FATAL_ERRORS
1012 #if 0
1013 if (fault_type == FAULT_TYPE_ERROR) {
1014 m_phenotype.IsFertile() = false;
1015 }
1016 #endif
1017
1018 // FATAL_WARNINGS
1019 #if 0
1020 if (fault_type == FAULT_TYPE_WARNING) {
1021 m_phenotype.IsFertile() = false;
1022 }
1023 #endif
1024
1025 // BREAKPOINTS
1026 #if 0
1027 m_phenotype.SetFault(fault_desc);
1028 #endif
1029
1030 m_phenotype.IncErrors();
1031 }
1032
NewTrial()1033 void cOrganism::NewTrial()
1034 {
1035 //More should be reset here... @JEB
1036 GetPhenotype().NewTrial();
1037 m_input_pointer = 0;
1038 m_input_buf.Clear();
1039 m_output_buf.Clear();
1040 }
1041
1042
1043 /*! Called as the bottom-half of a successfully sent message.
1044 */
MessageSent(cAvidaContext & ctx,cOrgMessage & msg)1045 void cOrganism::MessageSent(cAvidaContext& ctx, cOrgMessage& msg) {
1046 // check to see if we should store it:
1047 const int bsize = m_world->GetConfig().MESSAGE_SEND_BUFFER_SIZE.Get();
1048
1049 if((bsize > 0) || (bsize == -1)) {
1050 // yep; store it:
1051 m_msg->sent.push_back(msg);
1052 // and set the receiver-pointer of this message to NULL. We don't want to
1053 // walk this list later thinking that the receivers are still around.
1054 m_msg->sent.back().SetReceiver(0);
1055 // if our buffer is too large, chop off old messages:
1056 while((bsize != -1) && (static_cast<int>(m_msg->sent.size()) > bsize)) {
1057 m_msg->sent.pop_front();
1058 }
1059 }
1060 }
1061
1062
1063 /*! Send a message to the currently faced organism. Stat-tracking is done over
1064 in cPopulationInterface. Remember that this code WILL be called from within the
1065 test CPU! (Also, BroadcastMessage funnels down to code in the population interface
1066 too, so this way all the message sending code is in the same place.)
1067 */
SendMessage(cAvidaContext & ctx,cOrgMessage & msg)1068 bool cOrganism::SendMessage(cAvidaContext& ctx, cOrgMessage& msg)
1069 {
1070 assert(m_interface);
1071 InitMessaging();
1072
1073 // check to see if we've performed any tasks:
1074 if (m_world->GetConfig().CHECK_TASK_ON_SEND.Get()) {
1075 DoOutput(ctx, static_cast<int>(msg.GetData()));
1076 }
1077 // if we sent the message:
1078 if(m_interface->SendMessage(msg)) {
1079 MessageSent(ctx, msg);
1080 return true;
1081 }
1082 // importantly, m_interface->SendMessage() fails if we're running in the test CPU.
1083 return false;
1084 }
1085
1086
1087 /*! Broadcast a message to all organisms out to the given depth.
1088 */
BroadcastMessage(cAvidaContext & ctx,cOrgMessage & msg,int depth)1089 bool cOrganism::BroadcastMessage(cAvidaContext& ctx, cOrgMessage& msg, int depth) {
1090 assert(m_interface);
1091 InitMessaging();
1092
1093 // if we broadcasted the message:
1094 if(m_interface->BroadcastMessage(msg, depth)) {
1095 MessageSent(ctx, msg);
1096 return true;
1097 }
1098
1099 // Again, m_interface->BroadcastMessage() fails if we're running in the test CPU.
1100 return false;
1101 }
1102
1103
1104 /*! Called when this organism receives a message from another.
1105 */
ReceiveMessage(cOrgMessage & msg)1106 void cOrganism::ReceiveMessage(cOrgMessage& msg)
1107 {
1108 InitMessaging();
1109
1110 // don't store more messages than we're configured to.
1111 const int bsize = m_world->GetConfig().MESSAGE_RECV_BUFFER_SIZE.Get();
1112 if((bsize != -1) && (bsize <= static_cast<int>(m_msg->received.size()))) {
1113 switch(m_world->GetConfig().MESSAGE_RECV_BUFFER_BEHAVIOR.Get()) {
1114 case 0: // drop oldest message
1115 m_msg->received.pop_front();
1116 break;
1117 case 1: // drop this message
1118 return;
1119 default: // error
1120 m_world->GetDriver().RaiseFatalException(-1, "MESSAGE_RECV_BUFFER_BEHAVIOR is set to an invalid value.");
1121 assert(false);
1122 }
1123 }
1124
1125 msg.SetReceiver(this);
1126 m_msg->received.push_back(msg);
1127
1128 if (m_world->GetConfig().ACTIVE_MESSAGES_ENABLED.Get() > 0) {
1129 // then create new thread and load its registers
1130 m_hardware->InterruptThread(cHardwareBase::MSG_INTERRUPT);
1131 }
1132 }
1133
1134
1135 /*! Called to when this organism tries to load its CPU with the contents of a
1136 previously-received message. In a change from previous versions, pop the message
1137 off the front.
1138
1139 \return A pair (b, msg): if b is true, then msg was received; if b is false, then msg was not received.
1140 */
RetrieveMessage()1141 std::pair<bool, cOrgMessage> cOrganism::RetrieveMessage() {
1142 InitMessaging();
1143 std::pair<bool, cOrgMessage> ret = std::make_pair(false, cOrgMessage());
1144
1145 if(m_msg->received.size() > 0) {
1146 ret.second = m_msg->received.front();
1147 ret.first = true;
1148 m_msg->received.pop_front();
1149 }
1150
1151 return ret;
1152 }
1153
Move(cAvidaContext & ctx)1154 bool cOrganism::Move(cAvidaContext& ctx)
1155 {
1156 assert(m_interface);
1157 if (m_is_dead) return false;
1158 /*********************/
1159 // TEMP. Remove once movement tasks are implemented.
1160 if (GetCellData() < GetFacedCellData()) { // move up gradient
1161 SetGradientMovement(1.0);
1162 } else if(GetCellData() == GetFacedCellData()) {
1163 SetGradientMovement(0.0);
1164 } else { // move down gradient
1165 SetGradientMovement(-1.0);
1166 }
1167 /*********************/
1168
1169 int fromcellID = GetCellID();
1170 int destcellID = GetFacedCellID();
1171
1172 int facing = GetFacedDir();
1173
1174 // Actually perform the move
1175 if (m_interface->Move(ctx, fromcellID, destcellID)) {
1176 //Keep track of successful movement E/W and N/S in support of get-easterly and get-northerly for navigation
1177 //Skip counting if random < chance of miscounting a step.
1178 if (m_world->GetConfig().STEP_COUNTING_ERROR.Get()==0 || m_world->GetRandom().GetInt(0,101) > m_world->GetConfig().STEP_COUNTING_ERROR.Get()) {
1179 if (facing == 0) m_northerly = m_northerly - 1; // N
1180 else if (facing == 1) { // NE
1181 m_northerly = m_northerly - 1;
1182 m_easterly = m_easterly + 1;
1183 }
1184 else if (facing == 2) m_easterly = m_easterly + 1; // E
1185 else if (facing == 3) { // SE
1186 m_northerly = m_northerly + 1;
1187 m_easterly = m_easterly + 1;
1188 }
1189 else if (facing == 4) m_northerly = m_northerly + 1; // S
1190 else if (facing == 5) { // SW
1191 m_northerly = m_northerly + 1;
1192 m_easterly = m_easterly - 1;
1193 }
1194 else if (facing == 6) m_easterly = m_easterly - 1; // W
1195 else if (facing == 7) { // NW
1196 m_northerly = m_northerly - 1;
1197 m_easterly = m_easterly - 1;
1198 }
1199 }
1200 }
1201 else return false;
1202
1203 // Check to make sure the organism is alive after the move
1204 if (m_phenotype.GetToDelete()) return false;
1205
1206 // updates movement predicates
1207 m_world->GetStats().Move(*this);
1208
1209 // Pheromone drop stuff
1210 double pher_amount = 0; // this is used in the logging
1211 int drop_mode = -1;
1212
1213 // If organism is dropping pheromones, mark the appropriate cell(s)
1214 if (m_world->GetConfig().PHEROMONE_ENABLED.Get() == 1 && GetPheromoneStatus() == true) {
1215 pher_amount = m_world->GetConfig().PHEROMONE_AMOUNT.Get();
1216 drop_mode = m_world->GetConfig().PHEROMONE_DROP_MODE.Get();
1217
1218 cDeme* deme = GetDeme();
1219
1220 if (drop_mode == 0) {
1221 deme->AddPheromone(fromcellID, pher_amount / 2, ctx);
1222 deme->AddPheromone(destcellID, pher_amount / 2, ctx);
1223 } else if(drop_mode == 1) {
1224 deme->AddPheromone(fromcellID, pher_amount, ctx);
1225 } else if(drop_mode == 2) {
1226 deme->AddPheromone(destcellID, pher_amount, ctx);
1227 }
1228 } // End laying pheromone
1229
1230 // Write some logging information if LOG_PHEROMONE is set. This is done
1231 // out here so that non-pheromone moves are recorded.
1232 if (m_world->GetConfig().LOG_PHEROMONE.Get() == 1 &&
1233 m_world->GetStats().GetUpdate() >= m_world->GetConfig().MOVETARGET_LOG_START.Get()) {
1234 cDataFile& df = m_world->GetDataFile("movelog.dat");
1235
1236 int rel_srcid = GetDeme()->GetRelativeCellID(fromcellID);
1237 int rel_destid = GetDeme()->GetRelativeCellID(destcellID);
1238
1239 cString UpdateStr = cStringUtil::Stringf("%d,%d,%d,%d,%d,%f,%d,5", m_world->GetStats().GetUpdate(), GetID(), GetDeme()->GetDemeID(), rel_srcid, rel_destid, pher_amount, drop_mode);
1240 df.WriteRaw(UpdateStr);
1241 }
1242
1243 // don't trigger reactions on move if you're not supposed to!
1244 const cEnvironment& env = m_world->GetEnvironment();
1245 const int num_tasks = env.GetNumTasks();
1246 for (int i = 0; i < num_tasks; i++) {
1247 if (env.GetTask(i).GetDesc() == "move_up_gradient" || \
1248 env.GetTask(i).GetDesc() == "move_neutral_gradient" || \
1249 env.GetTask(i).GetDesc() == "move_down_gradient" || \
1250 env.GetTask(i).GetDesc() == "move_not_up_gradient" || \
1251 env.GetTask(i).GetDesc() == "move_to_right_side" || \
1252 env.GetTask(i).GetDesc() == "move_to_left_side" || \
1253 env.GetTask(i).GetDesc() == "move" || \
1254 env.GetTask(i).GetDesc() == "movetotarget" || \
1255 env.GetTask(i).GetDesc() == "movetoevent" || \
1256 env.GetTask(i).GetDesc() == "movebetweenevent" || \
1257 env.GetTask(i).GetDesc() == "move_to_event") {
1258 DoOutput(ctx);
1259 break;
1260 }
1261 }
1262
1263 if (m_world->GetConfig().ACTIVE_MESSAGES_ENABLED.Get() > 0) {
1264 // then create new thread and load its registers
1265 m_hardware->InterruptThread(cHardwareBase::MOVE_INTERRUPT);
1266 }
1267 return true;
1268 } //End cOrganism::Move()
1269
BcastAlarmMSG(cAvidaContext & ctx,int jump_label,int bcast_range)1270 bool cOrganism::BcastAlarmMSG(cAvidaContext& ctx, int jump_label, int bcast_range) {
1271 assert(m_interface);
1272
1273 // If we're able to succesfully send an alarm...
1274 if(m_interface->BcastAlarm(jump_label, bcast_range)) {
1275 // check to see if we've performed any tasks...
1276 DoOutput(ctx);
1277 return true;
1278 }
1279 return false;
1280 }
1281
moveIPtoAlarmLabel(int jump_label)1282 void cOrganism::moveIPtoAlarmLabel(int jump_label) {
1283 // move IP to alarm_label
1284 m_hardware->Jump_To_Alarm_Label(jump_label);
1285 }
1286
1287
1288 /*! Called to set this organism's opinion, which remains valid until a new opinion
1289 is expressed.
1290 */
SetOpinion(const Opinion & opinion)1291 void cOrganism::SetOpinion(const Opinion& opinion) {
1292 InitOpinions();
1293 const int bsize = m_world->GetConfig().OPINION_BUFFER_SIZE.Get();
1294
1295 if(bsize == 0) {
1296 m_world->GetDriver().RaiseFatalException(-1, "OPINION_BUFFER_SIZE is set to an invalid value.");
1297 }
1298
1299 if((bsize > 0) || (bsize == -1)) {
1300 m_opinion->opinion_list.push_back(std::make_pair(opinion, m_world->GetStats().GetUpdate()));
1301 // if our buffer is too large, chop off old messages:
1302 while((bsize != -1) && (static_cast<int>(m_opinion->opinion_list.size()) > bsize)) {
1303 m_opinion->opinion_list.pop_front();
1304 }
1305 }
1306 // if using avatars, make sure you swap avatar lists if the org's catorization changes!
1307 }
1308
1309 // Checks if the organism has an opinion.
HasOpinion()1310 bool cOrganism::HasOpinion() {
1311 InitOpinions();
1312 if (m_opinion->opinion_list.empty()) return false;
1313 else return true;
1314 }
1315
SetForageTarget(int forage_target)1316 void cOrganism::SetForageTarget(int forage_target) {
1317 // if using avatars, make sure you swap avatar lists if the org type changes!
1318 if (m_world->GetConfig().PRED_PREY_SWITCH.Get() == -2 || m_world->GetConfig().PRED_PREY_SWITCH.Get() > -1) {
1319 if (forage_target <= -2 && m_forage_target > -2) {
1320 m_interface->DecNumPreyOrganisms();
1321 m_interface->IncNumPredOrganisms();
1322 }
1323 else if (forage_target > -2 && m_forage_target <= -2) {
1324 m_interface->IncNumPreyOrganisms();
1325 m_interface->DecNumPredOrganisms();
1326 }
1327 }
1328 m_forage_target = forage_target;
1329 }
1330
CopyParentFT()1331 void cOrganism::CopyParentFT() {
1332 bool copy_ft = true;
1333 // close potential loop-hole allowing orgs to switch ft to prey at birth, collect res,
1334 // switch ft to pred, and then copy parent to become prey again.
1335 if (m_world->GetConfig().PRED_PREY_SWITCH.Get() <= 0 || m_world->GetConfig().PRED_PREY_SWITCH.Get() == 2) {
1336 if (m_parent_ft != -2 && m_forage_target < -1) {
1337 copy_ft = false;
1338 }
1339 }
1340 if (copy_ft) SetForageTarget(m_parent_ft);
1341 }
1342
1343 /*! Called when an organism receives a flash from a neighbor. */
ReceiveFlash()1344 void cOrganism::ReceiveFlash() {
1345 m_hardware->ReceiveFlash();
1346 }
1347
1348
1349 /*! Called by the "flash" instruction. */
SendFlash(cAvidaContext & ctx)1350 void cOrganism::SendFlash(cAvidaContext& ctx) {
1351 assert(m_interface);
1352
1353 // Check to see if we should lose the flash:
1354 if((m_world->GetConfig().SYNC_FLASH_LOSSRATE.Get() > 0.0) &&
1355 (m_world->GetRandom().P(m_world->GetConfig().SYNC_FLASH_LOSSRATE.Get()))) {
1356 return;
1357 }
1358
1359 // Flash not lost; continue.
1360 m_interface->SendFlash();
1361 m_world->GetStats().SentFlash(*this);
1362 DoOutput(ctx);
1363 }
1364
1365
GetNeighborhood()1366 cOrganism::Neighborhood cOrganism::GetNeighborhood() {
1367 Neighborhood neighbors;
1368 for(int i=0; i<GetNeighborhoodSize(); ++i, Rotate(1)) {
1369 if(IsNeighborCellOccupied()) {
1370 neighbors.insert(GetNeighbor()->GetID());
1371 }
1372 }
1373 return neighbors;
1374 }
1375
1376
LoadNeighborhood()1377 void cOrganism::LoadNeighborhood() {
1378 InitNeighborhood();
1379 m_neighborhood->neighbors = GetNeighborhood();
1380 m_neighborhood->loaded = true;
1381 }
1382
1383
HasNeighborhoodChanged()1384 bool cOrganism::HasNeighborhoodChanged() {
1385 InitNeighborhood();
1386 // Must have loaded the neighborhood first:
1387 if(!m_neighborhood->loaded) return false;
1388
1389 // Ok, get the symmetric difference between the old neighborhood and the current neighborhood:
1390 Neighborhood symdiff;
1391 Neighborhood current = GetNeighborhood();
1392 std::set_symmetric_difference(m_neighborhood->neighbors.begin(),
1393 m_neighborhood->neighbors.end(),
1394 current.begin(),
1395 current.end(),
1396 std::insert_iterator<Neighborhood>(symdiff, symdiff.begin()));
1397
1398 // If the symmetric difference is empty, then nothing has changed -- return
1399 return !symdiff.empty();
1400 }
1401
1402
1403 /* Called when raw materials are donated to others or when the
1404 raw materials are consumed. Amount is the number of resources
1405 donated. The boolean flag is used to indicate if the donation
1406 was successful... It would fail if the organism did not have
1407 that many resources. */
SubtractSelfRawMaterials(int amount)1408 bool cOrganism::SubtractSelfRawMaterials (int amount)
1409 {
1410 bool isSuccessful = false;
1411 if (amount <= m_self_raw_materials) {
1412 isSuccessful = true;
1413 m_self_raw_materials -= amount;
1414 }
1415 return isSuccessful;
1416 }
1417
1418
1419 /* Called when other raw materials are consumed. Amount is the
1420 number of resources consumed. The boolean flag is used to
1421 indicate if the donation was successful... It would fail if
1422 the organism did not have that many resources. */
SubtractOtherRawMaterials(int amount)1423 bool cOrganism::SubtractOtherRawMaterials (int amount)
1424 {
1425 bool isSuccessful = false;
1426 if (amount <= m_other_raw_materials) {
1427 isSuccessful = true;
1428 m_other_raw_materials -= amount;
1429 }
1430 return isSuccessful;
1431 }
1432
1433 /* Called when raw materials are received from others. Amount
1434 is the number of resources received. The boolean flag is used
1435 to indicate if the reception was successful, which should always
1436 be the case... */
1437
AddOtherRawMaterials(int amount,int donor_id)1438 bool cOrganism::AddOtherRawMaterials (int amount, int donor_id) {
1439 bool isSuccessful = true;
1440 m_other_raw_materials += amount;
1441 donor_list.insert(donor_id);
1442 m_num_donate_received += amount;
1443 m_amount_donate_received++;
1444 return isSuccessful;
1445 }
1446
1447 /* Called when raw materials are received from others. Amount
1448 is the number of resources received. The boolean flag is used
1449 to indicate if the reception was successful, which should always
1450 be the case...
1451
1452 This version is used if there is only one resource that is both
1453 donated and recieved.
1454 */
1455
AddRawMaterials(int amount,int donor_id)1456 bool cOrganism::AddRawMaterials (int amount, int donor_id) {
1457 bool isSuccessful = true;
1458 m_self_raw_materials += amount;
1459 donor_list.insert(donor_id);
1460 m_num_donate_received += amount;
1461 m_amount_donate_received++;
1462 return isSuccessful;
1463 }
1464
1465
1466 /* Get an organism's reputation, which is expressed as an
1467 opinion. 0 is the default reputation (this should be refactored
1468 to be cleaner). */
GetReputation()1469 int cOrganism::GetReputation() {
1470 int rep =0;
1471 if (HasOpinion()) {
1472 rep = GetOpinion().first;
1473 }
1474 return rep;
1475 }
1476
1477 /* Set an organism's reputation */
SetReputation(int rep)1478 void cOrganism::SetReputation(int rep) {
1479 SetOpinion(rep);
1480 return;
1481 }
1482
1483 /* An organism's reputation is based on a running average*/
SetAverageReputation(int rep)1484 void cOrganism::SetAverageReputation(int rep){
1485 int current_total = GetReputation() * m_opinion->opinion_list.size();
1486 int new_rep = (current_total + rep)/(m_opinion->opinion_list.size()+1);
1487 SetReputation(new_rep);
1488 }
1489
1490
1491 /* Check if an organism has previously donated to this organism */
IsDonor(int neighbor_id)1492 bool cOrganism::IsDonor(int neighbor_id)
1493 {
1494 bool found = false;
1495 if (donor_list.find(neighbor_id) != donor_list.end()) {
1496 found = true;
1497 }
1498 return found;
1499 }
1500
1501
1502
1503 /* Update the tag. If the organism was not already tagged,
1504 or the new tag is the same as the old tag, or the number
1505 of bits is > than the old tag, update.*/
UpdateTag(int new_tag,int bits)1506 void cOrganism::UpdateTag(int new_tag, int bits)
1507 {
1508 unsigned int rand_int = m_world->GetRandom().GetUInt(0, 2);
1509 if ((m_tag.first == -1) ||
1510 (m_tag.first == new_tag) ||
1511 (m_tag.second < bits)) {
1512 m_tag = make_pair(new_tag, bits);
1513 } else if ((m_tag.second == bits) && rand_int){
1514 m_tag = make_pair(new_tag, bits);
1515 }
1516 }
1517
1518
1519 /* See if the output buffer matches the string */
MatchOutputBuffer(cString string_to_match)1520 int cOrganism::MatchOutputBuffer(cString string_to_match)
1521 {
1522 tBuffer<int> org_str (GetOutputBuf());
1523 int num_matched =0;
1524 for (int j = 0; j < string_to_match.GetSize(); j++)
1525 {
1526 if (string_to_match[j]=='0' && org_str[j]==0 ||
1527 string_to_match[j]=='1' && org_str[j]==1)
1528 num_matched++;
1529 }
1530 return num_matched;
1531 }
1532
1533
SetOutputNegative1()1534 void cOrganism::SetOutputNegative1()
1535 {
1536 for (int i=0; i<GetOutputBuf().GetCapacity(); i++) {
1537 AddOutput(-1);
1538 }
1539 m_output_buf.Clear();
1540 }
1541
1542 /* Initialize the string tracking map */
InitStringMap()1543 void cOrganism::InitStringMap()
1544 {
1545 if (!m_string_map.size()) {
1546 // Get the strings from the task lib.
1547 std::vector < cString > temp_strings = m_world->GetEnvironment().GetMatchStringsFromTask();
1548 // Create structure for each of them.
1549 for (unsigned int i=0; i < temp_strings.size(); i++){
1550 m_string_map[i].m_string = temp_strings[i];
1551 }
1552 }
1553 }
1554
1555
ProduceString(int i)1556 bool cOrganism::ProduceString(int i)
1557 {
1558 bool val = false;
1559 int cap = m_world->GetConfig().STRING_AMOUNT_CAP.Get();
1560 if ((cap == -1) || (m_string_map[i].on_hand < cap))
1561 {
1562 m_string_map[i].prod_string++;
1563 m_string_map[i].on_hand++;
1564 val = true;
1565 }
1566 return val;
1567 }
1568
1569 /* Donate a string*/
DonateString(int string_tag,int amount)1570 bool cOrganism::DonateString(int string_tag, int amount)
1571 {
1572 bool val = false;
1573 if (m_string_map[string_tag].on_hand >= amount) {
1574 val = true;
1575 m_string_map[string_tag].on_hand -= amount;
1576 }
1577 return val;
1578
1579 }
1580
1581 /* Receive a string*/
ReceiveString(int string_tag,int amount,int donor_id)1582 bool cOrganism::ReceiveString(int string_tag, int amount, int donor_id)
1583 {
1584 bool val = false;
1585 int cap = m_world->GetConfig().STRING_AMOUNT_CAP.Get();
1586 if ((cap == -1) || (m_string_map[string_tag].on_hand < cap))
1587 {
1588 m_string_map[string_tag].received_string++;
1589 m_string_map[string_tag].on_hand++;
1590 donor_list.insert(donor_id);
1591 m_num_donate_received += amount;
1592 m_amount_donate_received++;
1593 val = true;
1594 }
1595 return val;
1596 }
1597
1598 /* Check to see if this amount is below the organism's cap*/
CanReceiveString(int string_tag,int amount)1599 bool cOrganism::CanReceiveString(int string_tag, int amount)
1600 {
1601 bool val = false;
1602 int cap = m_world->GetConfig().STRING_AMOUNT_CAP.Get();
1603 if ((cap == -1) || (m_string_map[string_tag].on_hand < cap))
1604 {
1605 val = true;
1606 }
1607 return val;
1608
1609 }
1610
IsInterrupted()1611 bool cOrganism::IsInterrupted()
1612 {
1613 for (int k = 0; k< GetHardware().GetNumThreads(); ++k) if (GetHardware().GetThreadMessageTriggerType(k) != -1) return true;
1614 return false;
1615 }
1616
DonateResConsumedToDeme()1617 void cOrganism::DonateResConsumedToDeme()
1618 {
1619 cDeme* deme = m_interface->GetDeme();
1620
1621 if(deme) {
1622 deme->AddResourcesConsumed(m_phenotype.GetResourcesConsumed());
1623 }
1624 return;
1625 }
1626
MoveAV(cAvidaContext & ctx)1627 bool cOrganism::MoveAV(cAvidaContext& ctx)
1628 {
1629 assert(m_interface);
1630 if (m_is_dead) return false;
1631
1632 // Actually perform the move
1633 if (m_interface->MoveAV(ctx)) {
1634 //Keep track of successful movement E/W and N/S in support of get-easterly and get-northerly for navigation
1635 //Skip counting if random < chance of miscounting a step.
1636 if (m_world->GetConfig().STEP_COUNTING_ERROR.Get() == 0 || m_world->GetRandom().GetInt(0,101) > m_world->GetConfig().STEP_COUNTING_ERROR.Get()) {
1637 int facing = m_interface->GetAVFacing();
1638
1639 if (facing == 0)
1640 m_northerly = m_northerly - 1; // N
1641 else if (facing == 1) {
1642 m_northerly = m_northerly - 1; // NE
1643 m_easterly = m_easterly + 1;
1644 }
1645 else if (facing == 2)
1646 m_easterly = m_easterly + 1; // E
1647 else if (facing == 3) {
1648 m_northerly = m_northerly + 1; // SE
1649 m_easterly = m_easterly + 1;
1650 }
1651 else if (facing == 4)
1652 m_northerly = m_northerly + 1; // S
1653 else if (facing == 5) {
1654 m_northerly = m_northerly + 1; // SW
1655 m_easterly = m_easterly - 1;
1656 }
1657 else if (facing == 6)
1658 m_easterly = m_easterly - 1; // W
1659 else if (facing == 7) {
1660 m_northerly = m_northerly - 1; // NW
1661 m_easterly = m_easterly - 1;
1662 }
1663 }
1664 else return false;
1665 }
1666
1667 // Check to make sure the organism is alive after the move
1668 if (m_phenotype.GetToDelete()) return false;
1669
1670 // updates movement predicates
1671 // m_world->GetStats().Move(*this);
1672
1673 return true;
1674 }
1675