Skip to content

Instantly share code, notes, and snippets.

@rozag
Last active August 29, 2015 14:15
Show Gist options
  • Save rozag/2ca1ab6cf4a76b5d8bba to your computer and use it in GitHub Desktop.
Save rozag/2ca1ab6cf4a76b5d8bba to your computer and use it in GitHub Desktop.
My Electronic Life implementation for Eloquent JavaScript book
clc;
close all;
figure;
grid;
title ('Plants (green), critters (blue) and predators (red)', 'FontSize', 15, 'FontWeight', 'bold');
xlabel('Time', 'FontSize', 15, 'FontWeight', 'bold');
ylabel('Population size', 'FontSize', 15, 'FontWeight', 'bold');
hold on;
plants = [28 56 112 222 398 622 783 859 884 876 859 827 798 769 737 704 677 657 641 609 591 581 574 560 553 538 524 510 499 485 474 455 440 415 397 385 374 357 353 334 316 305 300 293 286 286 286 283 281 282 278 280 276 275 275 276 278 283 287 286 288 292 295 302 308 313 317 326 329 338 341 347 353 356 359 362 365 368 378 384 389 398 405 412 415 417 426 430 437 445 449 457 463 470 475 481 485 493 503 506 511 521 529 534 539 544 548 554 559 571 585 588 598 605 614 622 626 631 637 639 648 653 662 674 684 693 698 702 710 720 728 734 742 750 754 763 771 781 796 810 816 824 832 842 850 864 874 879 891 898 907 916 927 935 943 952 961 971 979 990 1001 1014 1026 1034 1045 1055 1065 1078 1094 1100 1110 1126 1139 1151 1168 1177 1187 1197 1208 1215 1225 1235 1242 1251 1260 1267 1278 1286 1297 1304 1314 1321 1330 1336 1340 1347 1355 1358 1362 1366 1369 1373 1380 1387 1392 1395 1396 1401 1407 1409 1410 1411 1413 1416 1417 1418 1422 1424 1425 1425 1425 1425 1425 1425 1427 1428 1428 1428 1428 1429 1431 1431 1431 1431 1431 1431 1431 1431 1433 1434 1435 1435 1435 1436 1437 1437 1437 1437 1438 1438 1438 1438 1439 1439 1440 1440 1440 1440 1440 1441 1442 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1443 1445 1445 1445 1445 1445 1446 1446 1446 1447 1448 1448 1448 1448 1448 1448 1448 1449 1449 1449 1449 1449 1450 1450 1450 ];
critters = [9 18 36 63 105 153 200 218 230 257 269 294 309 327 347 358 381 385 401 406 421 417 399 388 379 379 370 363 362 351 349 347 344 349 341 317 299 286 275 252 225 210 185 166 156 136 119 95 84 68 63 59 56 53 45 42 36 28 24 23 19 11 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ];
predators = [11 22 44 77 129 179 223 258 281 286 298 310 326 340 350 366 374 389 394 411 423 438 462 483 503 519 541 559 579 598 612 632 645 667 696 724 757 785 814 852 892 923 951 973 994 1016 1039 1064 1080 1097 1109 1110 1113 1121 1128 1128 1135 1142 1140 1141 1146 1151 1154 1149 1148 1141 1137 1129 1126 1116 1113 1109 1102 1100 1097 1093 1091 1085 1076 1071 1067 1056 1050 1041 1041 1038 1030 1025 1019 1011 1007 999 993 986 980 975 971 963 953 950 945 935 926 922 917 912 908 902 897 885 870 867 857 850 842 834 830 825 819 817 808 803 794 782 772 763 758 754 746 736 728 722 714 705 701 693 685 675 660 646 640 630 624 613 605 592 582 577 565 558 549 540 529 521 513 504 495 485 477 466 454 441 430 421 411 401 391 377 362 356 346 329 316 305 288 279 269 258 248 240 231 221 214 205 196 189 178 170 159 152 141 135 126 120 116 109 101 98 94 90 87 83 76 69 64 61 58 55 49 47 46 45 43 40 38 38 34 32 31 31 31 30 30 31 29 28 28 28 28 27 25 25 25 25 25 25 25 24 22 22 21 21 21 20 19 19 19 19 18 18 18 18 17 16 16 16 16 16 15 15 14 13 13 13 13 13 13 13 13 12 13 13 13 13 13 13 13 11 11 11 11 11 10 10 10 8 8 8 8 8 8 8 8 7 7 7 7 7 6 6 6 ];
t = 0 : length(plants) - 1;
plot(t, plants, 'Color', 'green');
plot(t, critters, 'Color', 'blue');
plot(t, predators, 'Color', 'red');
hold off;
"use strict";
var MAX_CYCLES = 5;
var ACTING_ENERGY_LOSSES = 2;
var START_PLANT_ENERGY = 30;
var PLANT_REPRODUCTION_ENERGY = 10;
var PLANT_INCOMING_ENERGY = 2;
var START_CRITTER_ENERGY = 30;
var CRITTER_REPRODUCTION_ENERGY = 10;
var START_PREDATOR_ENERGY = 30;
var PREDATOR_REPRODUCTION_ENERGY = 10;
var terrain = [
"############################################################",
"# # # #",
"# @ # @ # #",
"# # * * # * #",
"# # o # #",
"# * # # o @ #",
"# # ########## # #",
"# o # @ * #",
"# # #",
"# # ##################",
"# # * o * #",
"# * @ #",
"# * * #",
"######################## @ * o #",
"# # * #",
"# o * * # ##############################",
"# # #",
"# # * #",
"# # * #",
"# * # o #",
"# # * * #",
"# o # #",
"# * # * # #",
"# * * # * #",
"# # @ #",
"# o * # * #",
"# @ * * @ # @ #",
"# # @ #",
"############################################################"];
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.plus = function (point) {
return new Point(this.x + point.x, this.y + point.y);
};
var directions = {
"n": new Point(0, -1),
"ne": new Point(1, -1),
"e": new Point(1, 0),
"se": new Point(1, 1),
"s": new Point(0, 1),
"sw": new Point(-1, 1),
"w": new Point(-1, 0),
"nw": new Point(-1, -1)
};
function World(terrain) {
this.space = this.parseTerrain(terrain);
this.liveCreatures = this.findLiveCreatures();
}
World.prototype.parseTerrain = function (terrain) {
var space = [];
terrain.forEach(function (line) {
var row = [];
line.split("").forEach(function (symbol) {
switch (symbol) {
case " ":
row.push(null);
break;
case "#":
row.push(new Wall());
break;
case "*":
row.push(new Plant());
break;
case "o":
row.push(new Critter());
break;
case "@":
row.push(new Predator());
break;
}
});
space.push(row);
});
return space;
};
World.prototype.findLiveCreatures = function () {
var liveCreatures = [];
this.space.forEach(function (row) {
row.forEach(function (entity) {
if (entity instanceof Plant ||
entity instanceof Critter ||
entity instanceof Predator) {
liveCreatures.push(entity);
}
});
});
return liveCreatures;
};
World.prototype.letThemAct = function () {
this.liveCreatures.forEach(function (currentCreature) {
currentCreature.act();
});
};
World.prototype.getCoordinatesOf = function (creature) {
var result = null;
this.space.forEach(function (row, i) {
row.forEach(function (something, j) {
if (something === creature) {
result = new Point(j, i);
}
});
});
return result;
};
World.prototype.findFood = function (creature) {
var point = this.getCoordinatesOf(creature);
var food = [];
for (var direction in directions) {
var newPoint = point.plus(directions[direction]);
if (this.space[newPoint.y][newPoint.x] instanceof (creature instanceof Critter ? Plant : Critter)) {
food.push(this.space[newPoint.y][newPoint.x]);
}
}
return food.length == 0 ? null : food;
};
World.prototype.findEmptySpaces = function (creature) {
var point = this.getCoordinatesOf(creature);
var emptyPoints = [];
for (var direction in directions) {
var newPoint = point.plus(directions[direction]);
if (this.space[newPoint.y][newPoint.x] == null) {
emptyPoints.push(newPoint);
}
}
return emptyPoints.length == 0 ? null : emptyPoints;
};
World.prototype.printSpace = function () {
this.space.forEach(function (row) {
var line = "";
row.forEach(function (element) {
if (element == null) {
line += " ";
} else if (element instanceof Wall) {
line += "#";
} else if (element instanceof Plant) {
line += "*";
} else if (element instanceof Critter) {
line += "o";
} else if (element instanceof Predator) {
line += "@";
}
});
console.log(line);
});
};
function Entity() {
}
Entity.prototype.act = function () {
var reproductionEnergy;
var child;
if (this instanceof Critter) {
reproductionEnergy = CRITTER_REPRODUCTION_ENERGY;
child = new Critter();
} else if (this instanceof Predator) {
reproductionEnergy = PREDATOR_REPRODUCTION_ENERGY;
child = new Predator();
}
this.energy -= ACTING_ENERGY_LOSSES;
if (this.energy <= 0) {
var currentPlace = world.getCoordinatesOf(this);
world.space[currentPlace.y][currentPlace.x] = null;
var position = world.liveCreatures.indexOf(this);
if (position > -1) {
world.liveCreatures.splice(position, 1);
}
return;
}
var emptySpaces = world.findEmptySpaces(this);
var creaturesForFood = world.findFood(this);
if (this.energy > reproductionEnergy && emptySpaces != null) {
this.energy -= reproductionEnergy;
var pointForChild = emptySpaces[Math.floor(Math.random() * emptySpaces.length)];
world.space[pointForChild.y][pointForChild.x] = child;
world.liveCreatures.push(child);
} else if (creaturesForFood != null) {
var food = creaturesForFood[Math.floor(Math.random() * creaturesForFood.length)];
this.energy += food.energy;
var foodPoint = world.getCoordinatesOf(food);
world.space[foodPoint.y][foodPoint.x] = null;
var index = world.liveCreatures.indexOf(food);
if (index > -1) {
world.liveCreatures.splice(index, 1);
}
} else if (emptySpaces != null) {
var currentPoint = world.getCoordinatesOf(this);
world.space[currentPoint.y][currentPoint.x] = null;
var newPoint = emptySpaces[Math.floor(Math.random() * emptySpaces.length)];
world.space[newPoint.y][newPoint.x] = this;
}
};
function Wall() {
}
function Plant() {
this.energy = START_PLANT_ENERGY;
}
Plant.prototype.act = function () {
this.energy += PLANT_INCOMING_ENERGY;
var emptySpaces = world.findEmptySpaces(this);
if (this.energy > PLANT_REPRODUCTION_ENERGY && emptySpaces != null) {
this.energy -= PLANT_REPRODUCTION_ENERGY;
var pointForChild = emptySpaces[Math.floor(Math.random() * emptySpaces.length)];
var child = new Plant();
world.space[pointForChild.y][pointForChild.x] = child;
world.liveCreatures.push(child);
}
};
function Critter() {
this.energy = START_CRITTER_ENERGY;
}
Critter.prototype = Object.create(Entity.prototype);
function Predator() {
this.energy = START_PREDATOR_ENERGY;
}
Predator.prototype = Object.create(Entity.prototype);
var plantsCount = "plants = [";
var crittersCount = "critters = [";
var predatorsCount = "predators = [";
function countCreatures() {
var plants = 0, critters = 0, predators = 0;
world.liveCreatures.forEach(function (current) {
if (current instanceof Plant) {
plants++;
} else if (current instanceof Critter) {
critters++;
} else if (current instanceof Predator) {
predators++;
}
});
plantsCount += plants + " ";
crittersCount += critters + " ";
predatorsCount += predators + " ";
}
// Main loop
var world = new World(terrain);
for (var t = 0; t <= MAX_CYCLES; t++) {
countCreatures();
world.letThemAct();
}
world.printSpace();
plantsCount += "];";
crittersCount += "];";
predatorsCount += "];";
console.log(plantsCount);
console.log(crittersCount);
console.log(predatorsCount);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment