00001
00002
#include "world.h"
00003
#include "render.h"
00004
00005
00006
00007 #define process2entity(PROC) *static_cast<entity*>(&(PROC.getProgram()))
00008 #define vm2world(VM) *static_cast<world*>(&VM)
00009
00010
00011 entity::entity( uInt seed,
00012
const energy& e,
00013
const memory& m,
00014
const position& p,
00015
const direction& d )
00016 : m_energy(e)
00017 , m_position(p)
00018 , m_direction(d)
00019 {
00020 resize(m);
00021 generate(seed);
00022 }
00023
00024
00025
00026 void entity::draw()
00027 {
00028 }
00029
00030
00031
00032 tile::tile(
float cost, energy e) : m_cost(cost)
00033 , m_energy(e)
00034 , m_pEntity(NULL)
00035 {
00036 }
00037
00038
00039
00040
00041 world::world() : m_size(100,100)
00042 , m_absorbAmount(4)
00043 , m_energyPerUnitMemory(1)
00044 , m_maxEnergyPerTile(g_max_int)
00045 , m_maxCostPerTile(1.0f)
00046 , m_maxEnergyPerEntity(g_max_int)
00047 , m_maxMemoryPerEntity(10000)
00048 {
00049 }
00050
00051
00052 world::~world()
00053 {
00054
00055 vv_tiles::iterator it =
m_tiles.begin();
00056
for( ; it!=
m_tiles.end(); ++it)
00057 {
00058 v_tiles::iterator iit = it->begin();
00059
for( ; iit!=it->end();++iit)
00060 {
00061
if(iit->m_pEntity)
delete iit->m_pEntity;
00062 }
00063 }
00064 }
00065
00066
00067 void world::init()
00068 {
00069
00070
m_tiles.resize(
m_size.x);
00071
00072 vv_tiles::iterator it =
m_tiles.begin();
00073 v_tiles::iterator tit;
00074
for( ;it!=
m_tiles.end(); ++it)
00075 {
00076 it->resize(
m_size.y);
00077
00078 tit = it->begin();
00079
for( ; tit!=it->end();++tit)
00080 {
00081 tit->m_cost = (
float)rand()/RAND_MAX*
m_maxCostPerTile;
00082 tit->m_energy = (
float)rand()/RAND_MAX*
m_maxEnergyPerTile;
00083 }
00084 }
00085 }
00086
00087
00088 instruction
world::addInstruction(instructionPtr instrPtr)
00089 {
00090
return virtualMachine::addInstruction(instrPtr);
00091 }
00092
00093
00094 bool world::replaceInstruction(instruction instr, instructionPtr instrPtr)
00095 {
00096
return virtualMachine::replaceInstruction(instr, instrPtr);
00097 }
00098
00099
00100 uInt
world::getNumInstructions()
00101 {
00102
return static_cast<uInt>(size());
00103 }
00104
00105
00106 void world::step()
00107 {
00108 virtualMachine::step();
00109 }
00110
00111
00112 void world::kill(
entityId entId)
00113 {
00114 virtualMachine::kill(entId);
00115 }
00116
00117
00118 entity*
world::spawnEntity( energy e,
00119
memory m,
00120
const position& p,
00121
const direction& d )
00122 {
00123
00124
if(e>
m_maxEnergyPerEntity) e =
m_maxEnergyPerEntity;
00125
if(m>
m_maxMemoryPerEntity) m =
m_maxMemoryPerEntity;
00126
00127
static uInt seed = 0;
00128
00129
00130
if(p.x>=0 && p.x<
m_size.x && p.y>=0 && p.y<
m_size.y && !
getEntityAtPos(p))
00131 {
00132
00133
entity* pEntity =
new entity(seed++, e, m, p, d);
00134
if(pEntity)
00135 {
00136
00137 pEntity->
m_pid = run(*pEntity);
00138
00139
00140
if(!pEntity->
m_pid)
00141 {
00142
delete pEntity;
00143 pEntity = NULL;
00144 }
00145
00146
00147
m_tiles[p.x][p.y].m_pEntity = pEntity;
00148
00149
return(pEntity);
00150 }
00151 }
00152
00153
return NULL;
00154 }
00155
00156
00157
00158 entity*
world::getEntity(entityId entId)
00159 {
00160 process* proc = getProcess(entId);
00161
if(proc)
00162 {
00163
return static_cast<entity*>(&(proc->getProgram()));
00164 }
00165
return NULL;
00166 }
00167
00168
00169 entity*
world::getEntityAtPos(
const position& p)
00170 {
00171
00172
if(p.x>=0 && p.x<
m_size.x && p.y>=0 && p.y<
m_size.y)
00173 {
00174
return m_tiles[p.x][p.y].m_pEntity;
00175 }
00176
00177
return NULL;
00178 }
00179
00180
00181 void world::moveEntity(
entity& ent)
00182 {
00183
00184
position newPos =
getPosInfrontOfEntity(ent, 1);
00185
00186
tile* currentTile =
getTileAtPos(ent.
m_position);
00187
00188
tile* newTile = getTileAtPos(newPos);
00189
00190 ASSERT(currentTile,
"entity must inhabit tile");
00191
00192
00193
if(newTile && !
getEntityAtPos(newPos))
00194 {
00195
00196 currentTile->
m_pEntity = NULL;
00197
00198 newTile->
m_pEntity = &ent;
00199
00200 ent.
m_position = newPos;
00201
00202
00203
00204
energy cost = (
energy)(
00205 ent.size()*(
00206 currentTile->
m_cost-newTile->
m_cost
00207 )
00208 );
00209
00210
00211
00212
transferEnergy(cost, *currentTile, ent);
00213 }
00214
00215 ASSERT(ent.
m_position.x>=0,
"invalid coordinate");
00216 ASSERT(ent.
m_position.x<
m_size.x,
"invalid coordinate");
00217 ASSERT(ent.
m_position.y>=0,
"invalid coordinate");
00218 ASSERT(ent.
m_position.y<
m_size.y,
"invalid coordinate");
00219 }
00220
00221
00222 void world::rotateEntityLeft(
entity& ent)
00223 {
00224
int tmp = ent.
m_direction.x;
00225 ent.
m_direction.x = -ent.
m_direction.y;
00226 ent.
m_direction.y = tmp;
00227 }
00228
00229 void world::rotateEntityRight(
entity& ent)
00230 {
00231
int tmp = ent.
m_direction.x;
00232 ent.
m_direction.x = ent.
m_direction.y;
00233 ent.
m_direction.y = -tmp;
00234 }
00235
00236
00237 energy world::transferEnergy( energy amount,
00238 energy& a,
00239 energy& b )
00240 {
00241
00242
if(amount==0)
return 0;
00243
00244
00245
00246
if(amount>a)
00247 {
00248 amount = a;
00249
00250 }
else if(-amount>b)
00251 {
00252 amount = -b;
00253 }
00254
00255
00256 a -= amount;
00257 b += amount;
00258
00259
00260
return amount;
00261 }
00262
00263 energy world::transferEnergy( energy amount,
00264
tile& t,
00265
entity& ent )
00266 {
00267
00268
if(amount==0)
return 0;
00269
00270
00271
00272
if(amount>0 && (amount+ent.
m_energy)>
m_maxEnergyPerEntity)
00273 {
00274 amount =
m_maxEnergyPerEntity-ent.
m_energy;
00275
00276 }
else if((amount-t.
m_energy)<-
m_maxEnergyPerTile)
00277 {
00278 amount = -(
m_maxEnergyPerTile-t.
m_energy);
00279 }
00280
00281
00282
00283
return transferEnergy(amount, t.
m_energy, ent.
m_energy);
00284 }
00285
00286
00287 energy world::transferEnergy( energy amount,
00288
entity& entA,
00289
entity& entB )
00290 {
00291
00292
if(amount==0)
return 0;
00293
00294
00295
00296
if(amount>0 && (amount+entB.
m_energy)>
m_maxEnergyPerEntity)
00297 {
00298 amount =
m_maxEnergyPerEntity-entB.
m_energy;
00299
00300 }
else if((amount-entA.
m_energy)<-
m_maxEnergyPerEntity)
00301 {
00302 amount = -(
m_maxEnergyPerEntity-entA.
m_energy);
00303 }
00304
00305
00306
00307
return transferEnergy(amount, entA.
m_energy, entB.
m_energy);
00308 }
00309
00310
00311 energy world::transferEnergy(energy amount,
entity& ent)
00312 {
00313
00314
position infront =
getPosInfrontOfEntity(ent, 1);
00315
tile* tileInfront =
getTileAtPos(infront);
00316
00317
00318
if(tileInfront && tileInfront->
m_pEntity)
00319 {
00320
00321
00322
return transferEnergy(amount, ent, *(tileInfront->
m_pEntity));
00323 }
00324
00325
return 0;
00326 }
00327
00328
00329 void world::absorbEnergy(
entity& ent)
00330 {
00331
tile* currentTile =
getTileAtPos(ent.
m_position);
00332 ASSERT(currentTile,
"entity must inhabit tile");
00333
00334
00335
energy halfMax =
m_maxEnergyPerTile/2;
00336
float tileEnergyRatio = (
float)(currentTile->
m_energy-halfMax)/halfMax;
00337
00338
00339
energy amount =
m_absorbAmount*tileEnergyRatio;
00340
00341
00342
transferEnergy(amount, *currentTile, ent);
00343 }
00344
00345
00346 energy world::releaseEnergy(energy amount,
entity& ent)
00347 {
00348
tile* currentTile =
getTileAtPos(ent.
m_position);
00349 ASSERT(currentTile,
"entity must inhabit tile");
00350
00351
00352
if(amount<=0)
return 0;
00353
00354
00355
00356
return -
transferEnergy(-amount, *currentTile, ent);
00357 }
00358
00359
00360 void world::transferMemory(address addr, program& a, program& b)
00361 {
00362 uInt sizeA = static_cast<uInt>(a.size());
00363 uInt sizeB = static_cast<uInt>(b.size());
00364
00365
00366 addr%=sizeA;
00367
00368
00369 b.resize(sizeB+sizeA-addr);
00370
00371
00372
for(address from=addr, to=sizeB; from<sizeA; ++from, ++to)
00373 {
00374 b[to] = a[from];
00375 }
00376
00377
00378 a.resize(addr);
00379 }
00380
00381
00382 void world::transferMemory(address addr,
entity& entA,
entity& entB)
00383 {
00384
int sizeA = static_cast<int>(entA.size());
00385
int sizeB = static_cast<int>(entB.size());
00386
00387
00388
if(sizeA<=0)
return;
00389
00390
00391
00392 addr%=sizeA;
00393
00394
memory amountToTransfer = sizeA-addr;
00395
00396
00397
if(amountToTransfer+sizeB>
m_maxMemoryPerEntity)
00398 {
00399 amountToTransfer =
m_maxMemoryPerEntity-sizeB;
00400 }
00401
00402
00403
00404
tile* tileA =
getTileAtPos(entA.
m_position);
00405
tile* tileB = getTileAtPos(entB.
m_position);
00406
00407 ASSERT(tileA,
"entity must inhabit tile");
00408 ASSERT(tileB,
"entity must inhabit tile");
00409
00410
float deltaCost = tileB->
m_cost-tileA->
m_cost;
00411
00412
00413
energy costToTransfer = (
energy)(amountToTransfer*deltaCost);
00414
00415
if(costToTransfer>0)
00416 {
00417
00418
00419 costToTransfer =
releaseEnergy(costToTransfer, entA);
00420
00421 }
else if(costToTransfer<0)
00422 {
00423
00424
00425 costToTransfer =
transferEnergy(costToTransfer, entB, entA);
00426 }
else
00427 {
00428
00429 deltaCost = 1.0f;
00430 }
00431
00432
00433
00434 amountToTransfer = (
memory)(costToTransfer/deltaCost);
00435
00436
00437 entB.resize(sizeB+amountToTransfer);
00438
00439
for(
int from=sizeA-amountToTransfer, to=sizeB; from<sizeA; ++from, ++to)
00440 {
00441 entB[to] = entA[from];
00442 }
00443
00444 entA.resize(sizeA-amountToTransfer);
00445 }
00446
00447
00448 void world::giveMemory(
entity& ent, address addr)
00449 {
00450
position infront =
getPosInfrontOfEntity(ent, 1);
00451
tile* tileInfront =
getTileAtPos(infront);
00452
00453
if(tileInfront && tileInfront->
m_pEntity)
00454 {
00455
00456
00457
transferMemory(addr, ent, *(tileInfront->
m_pEntity));
00458
00459 }
else
00460 {
00461
00462
entity* newEnt =
spawnEntity(0, 0, infront, ent.
m_direction);
00463
if(newEnt)
00464 {
00465
00466
transferMemory(addr, ent, *newEnt);
00467 }
00468 }
00469 }
00470
00471
00472 void world::takeMemory(
entity& ent, address addr)
00473 {
00474
position infront =
getPosInfrontOfEntity(ent, 1);
00475
tile* tileInfront =
getTileAtPos(infront);
00476
00477
if(tileInfront && tileInfront->
m_pEntity)
00478 {
00479
00480
transferMemory(addr, *(tileInfront->
m_pEntity), ent);
00481 }
00482 }
00483
00484
00485 void world::convertEnergyToMemory(
entity& ent, energy amount)
00486 {
00487
00488
if(ent.
m_energy<=0)
return;
00489
00490
00491
if(amount<0) amount = -amount;
00492
00493
memory current = static_cast<uInt>(ent.size());
00494
00495
00496 amount%=ent.
m_energy;
00497
00498
00499
memory toAdd = amount/
m_energyPerUnitMemory;
00500
00501
00502
if(toAdd==0)
return;
00503
00504
00505
if(current + toAdd >
m_maxMemoryPerEntity)
00506 {
00507 toAdd =
m_maxMemoryPerEntity-current;
00508 }
00509
00510
00511
00512 amount = toAdd*
m_energyPerUnitMemory;
00513
00514
00515 ent.
m_energy-=amount;
00516
00517
00518
00519 ent.resize(current+toAdd, 0);
00520 }
00521
00522
00523 void world::convertMemoryToEnergy(
entity& ent, address addr)
00524 {
00525
00526
if(ent.size()==0)
return;
00527
00528
00529
memory current = static_cast<uInt>(ent.size());
00530 addr%=current;
00531
00532
00533
00534
memory toConvert = current - addr;
00535
energy toAdd = toConvert*
m_energyPerUnitMemory;
00536
00537
00538
if(toAdd+ent.
m_energy+m_energyPerUnitMemory>
m_maxEnergyPerEntity)
00539 {
00540 toAdd =
m_maxEnergyPerEntity-ent.
m_energy-m_energyPerUnitMemory;
00541 }
00542
00543
00544 ent.
m_energy += toAdd;
00545
00546
00547 toConvert = toAdd/m_energyPerUnitMemory;
00548
00549
00550 ent.resize(current-toConvert);
00551
00552
00553
00554 ent.
m_energy+=toAdd%m_energyPerUnitMemory;
00555 }
00556
00557
00558 tile*
world::getTileAtPos(
const position& p)
00559 {
00560
if(p.x>=0 && p.x<
m_size.x && p.y>=0 && p.y<
m_size.y)
00561 {
00562
return &(
m_tiles[p.x][p.y]);
00563 }
00564
return NULL;
00565 }
00566
00567
00568 position world::getPosInfrontOfEntity(
entity& ent, uInt d)
00569 {
00570
position pos;
00571 pos.x = ent.
m_position.x+d*ent.
m_direction.x;
00572 pos.y = ent.
m_position.y+d*ent.
m_direction.y;
00573
return pos;
00574 }
00575
00576
00577
00578
00579
00580 void world::draw()
00581 {
00582
float tileSize = 1.0f/
m_size.x;
00583
00584 vector2f pos, dim;
00585
00586 dim.x = dim.y = tileSize;
00587
float lineWidth = 1.0f;
00588
00589
colour4f lineColour(1.0f,1.0f,1.0f,1.0f);
00590
colour4f tileColour(0.0f,1.0f,0.0f,1.0f);
00591
colour4f entityColour(1.0f,0.0f,0.0f,1.0f);
00592
00593 vv_tiles::iterator xIt =
m_tiles.begin();
00594 v_tiles::iterator yIt;
00595
for( uInt x=0; xIt!=
m_tiles.end(); ++xIt, ++x)
00596 {
00597 yIt = xIt->begin();
00598
for( uInt y=0; yIt!=xIt->end(); ++yIt, ++y)
00599 {
00600 pos.x = x*tileSize;
00601 pos.y = y*tileSize;
00602
00603
if(yIt->m_pEntity==NULL)
00604 {
00605 tileColour.
m_g = yIt->m_cost/
m_maxCostPerTile;
00606
drawRectangle(&pos, &dim, NULL, NULL, &tileColour);
00607 }
else
00608 {
00609 entityColour.
m_b = (
float)yIt->m_pEntity->m_energy/1000.0f;
00610
drawRectangle(&pos, &dim, NULL, NULL, &entityColour);
00611 }
00612 }
00613 }
00614
00615
drawGrid(
m_size, NULL, NULL, &lineWidth, &lineColour, NULL);
00616 }
00617
00618
00619
00620 bool world::canBeExecuted(process& proc)
00621 {
00622
if(proc.isTerminated())
return false;
00623
00624
entity& ent =
process2entity(proc);
00625
return ent.
m_energy > 0;
00626 }
00627
00628
00629
00630
00631 void world::kill(process& proc)
00632 {
00633
entity* pEnt = &
process2entity(proc);
00634
00635
00636
00637
tile* t =
getTileAtPos(pEnt->
m_position);
00638 ASSERT(t->
m_pEntity==pEnt,
"entity not in specified tile");
00639 t->
m_pEntity = NULL;
00640 t->
m_energy += pEnt->
m_energy;
00641
00642
#ifdef VERBOSE
00643
std::cout <<
"pid: " << proc.getId() <<
"\tkill\tE:" << pEnt->
m_energy <<
"\tM:" << pEnt->size() << std::endl;
00644
#endif
00645
00646
delete pEnt;
00647
00648
00649 virtualMachine::kill(proc);
00650
00651 }
00652