Added body cell functionality
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
const Hyperparams = require("../Hyperparameters");
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
|
||||
class ControlPanel {
|
||||
constructor(engine) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const CanvasController = require("./CanvasController");
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
const CellStates = require("../Organism/Cell/CellStates");
|
||||
const Directions = require("../Organism/Directions");
|
||||
|
||||
class EditorController extends CanvasController{
|
||||
@@ -25,7 +25,6 @@ class EditorController extends CanvasController{
|
||||
mouseUp(){}
|
||||
|
||||
getCurLocalCell(){
|
||||
console.log(this.env.organism.getLocalCell(this.mouse_c-this.env.organism.c, this.mouse_r-this.env.organism.r))
|
||||
return this.env.organism.getLocalCell(this.mouse_c-this.env.organism.c, this.mouse_r-this.env.organism.r);
|
||||
}
|
||||
|
||||
@@ -37,25 +36,13 @@ class EditorController extends CanvasController{
|
||||
if (this.edit_cell_type == null || this.mode != Modes.Edit)
|
||||
return;
|
||||
if (this.left_click){
|
||||
if(this.edit_cell_type == CellTypes.eye) {
|
||||
if (this.cur_cell.type == CellTypes.eye){
|
||||
var loc_cell = this.getCurLocalCell();
|
||||
var dir = loc_cell.eye.direction;
|
||||
dir = Directions.rotateRight(dir);
|
||||
loc_cell.eye.direction = dir;
|
||||
this.cur_cell.direction = dir;
|
||||
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
|
||||
}
|
||||
else {
|
||||
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
|
||||
var loc_cell = this.getCurLocalCell();
|
||||
loc_cell.eye.direction = Directions.up;
|
||||
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
|
||||
}
|
||||
if(this.edit_cell_type == CellStates.eye && this.cur_cell.state == CellStates.eye) {
|
||||
var loc_cell = this.getCurLocalCell();
|
||||
loc_cell.direction = Directions.rotateRight(loc_cell.direction);
|
||||
this.env.renderFull();
|
||||
}
|
||||
else{
|
||||
else
|
||||
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
|
||||
}
|
||||
}
|
||||
if (this.right_click)
|
||||
this.env.removeCellFromOrg(this.mouse_c, this.mouse_r);
|
||||
@@ -70,22 +57,22 @@ class EditorController extends CanvasController{
|
||||
$('.cell-type').click( function() {
|
||||
switch(this.id){
|
||||
case "mouth":
|
||||
self.edit_cell_type = CellTypes.mouth;
|
||||
self.edit_cell_type = CellStates.mouth;
|
||||
break;
|
||||
case "producer":
|
||||
self.edit_cell_type = CellTypes.producer;
|
||||
self.edit_cell_type = CellStates.producer;
|
||||
break;
|
||||
case "mover":
|
||||
self.edit_cell_type = CellTypes.mover;
|
||||
self.edit_cell_type = CellStates.mover;
|
||||
break;
|
||||
case "killer":
|
||||
self.edit_cell_type = CellTypes.killer;
|
||||
self.edit_cell_type = CellStates.killer;
|
||||
break;
|
||||
case "armor":
|
||||
self.edit_cell_type = CellTypes.armor;
|
||||
self.edit_cell_type = CellStates.armor;
|
||||
break;
|
||||
case "eye":
|
||||
self.edit_cell_type = CellTypes.eye;
|
||||
self.edit_cell_type = CellStates.eye;
|
||||
break;
|
||||
}
|
||||
$(".cell-type" ).css( "border-color", "black" );
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const CanvasController = require("./CanvasController");
|
||||
const Organism = require('../Organism/Organism');
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
const CellStates = require("../Organism/Cell/CellStates");
|
||||
const Neighbors = require("../Grid/Neighbors");
|
||||
const Cell = require("../Organism/Cell/Cell");
|
||||
const Cell = require("../Organism/Cell/GridCell");
|
||||
|
||||
class EnvironmentController extends CanvasController{
|
||||
constructor(env, canvas) {
|
||||
@@ -69,19 +69,19 @@ class EnvironmentController extends CanvasController{
|
||||
switch(mode) {
|
||||
case Modes.FoodDrop:
|
||||
if (left_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.food, false);
|
||||
this.dropCellType(cell.col, cell.row, CellStates.food, false);
|
||||
}
|
||||
else if (right_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.empty, false);
|
||||
this.dropCellType(cell.col, cell.row, CellStates.empty, false);
|
||||
}
|
||||
break;
|
||||
case Modes.WallDrop:
|
||||
if (left_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.wall, true);
|
||||
this.dropCellType(cell.col, cell.row, CellStates.wall, true);
|
||||
|
||||
}
|
||||
else if (right_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.empty, false);
|
||||
this.dropCellType(cell.col, cell.row, CellStates.empty, false);
|
||||
}
|
||||
break;
|
||||
case Modes.ClickKill:
|
||||
@@ -118,7 +118,7 @@ class EnvironmentController extends CanvasController{
|
||||
}
|
||||
}
|
||||
|
||||
dropCellType(col, row, type, killBlocking=false) {
|
||||
dropCellType(col, row, state, killBlocking=false) {
|
||||
for (var loc of Neighbors.allSelf){
|
||||
var c=col + loc[0];
|
||||
var r=row + loc[1];
|
||||
@@ -131,7 +131,7 @@ class EnvironmentController extends CanvasController{
|
||||
else if (cell.owner != null) {
|
||||
continue;
|
||||
}
|
||||
this.env.changeCell(c, r, type, null);
|
||||
this.env.changeCell(c, r, state, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ class Environment{
|
||||
alert("Environment.update() must be overriden");
|
||||
}
|
||||
|
||||
changeCell(c, r, type, owner) {
|
||||
this.grid_map.setCellType(c, r, type);
|
||||
changeCell(c, r, state, owner) {
|
||||
this.grid_map.setCellType(c, r, state);
|
||||
this.grid_map.setCellOwner(c, r, owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ const Environment = require('./Environment');
|
||||
const Organism = require('../Organism/Organism');
|
||||
const GridMap = require('../Grid/GridMap');
|
||||
const Renderer = require('../Rendering/Renderer');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
const CellStates = require('../Organism/Cell/CellStates');
|
||||
const EditorController = require("../Controllers/EditorController");
|
||||
const Cell = require("../Organism/Cell/Cell");
|
||||
const Cell = require("../Organism/Cell/GridCell");
|
||||
const Eye = require('../Organism/Perception/Eye');
|
||||
const Directions = require('../Organism/Directions');
|
||||
|
||||
@@ -27,28 +27,27 @@ class OrganismEditor extends Environment{
|
||||
}
|
||||
}
|
||||
|
||||
changeCell(c, r, type, owner) {
|
||||
super.changeCell(c, r, type, owner);
|
||||
changeCell(c, r, state, owner) {
|
||||
super.changeCell(c, r, state, owner);
|
||||
this.renderFull();
|
||||
}
|
||||
|
||||
renderFull() {
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
}
|
||||
|
||||
// absolute c r, not local
|
||||
addCellToOrg(c, r, type) {
|
||||
addCellToOrg(c, r, state) {
|
||||
var center = this.grid_map.getCenter();
|
||||
var loc_c = c - center[0];
|
||||
var loc_r = r - center[1];
|
||||
var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
|
||||
if (prev_cell != null) {
|
||||
console.log(prev_cell.type)
|
||||
if (type == CellTypes.eye && prev_cell.type != CellTypes.eye){
|
||||
prev_cell.eye = new Eye(Directions.up);
|
||||
|
||||
}
|
||||
prev_cell.type = type;
|
||||
this.changeCell(c, r, type, this.organism);
|
||||
var new_cell = this.organism.replaceCell(state, prev_cell.loc_col, prev_cell.loc_row, false);
|
||||
this.changeCell(c, r, state, new_cell);
|
||||
}
|
||||
else if (this.organism.addCell(type, loc_c, loc_r)){
|
||||
this.changeCell(c, r, type, this.organism);
|
||||
else if (this.organism.canAddCellAt(loc_c, loc_r)){
|
||||
this.changeCell(c, r, state, this.organism.addDefaultCell(state, loc_c, loc_r));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +62,13 @@ class OrganismEditor extends Environment{
|
||||
var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
|
||||
if (prev_cell != null) {
|
||||
if (this.organism.removeCell(loc_c, loc_r)) {
|
||||
this.changeCell(c, r, CellTypes.empty, null);
|
||||
this.changeCell(c, r, CellStates.empty, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOrganismToCopyOf(orig_org){
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
this.grid_map.fillGrid(CellStates.empty);
|
||||
var center = this.grid_map.getCenter();
|
||||
this.organism = new Organism(center[0], center[1], this, orig_org);
|
||||
this.organism.updateGrid();
|
||||
@@ -82,10 +81,10 @@ class OrganismEditor extends Environment{
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
this.grid_map.fillGrid(CellStates.empty);
|
||||
var center = this.grid_map.getCenter();
|
||||
this.organism = new Organism(center[0], center[1], this, null);
|
||||
this.organism.addCell(CellTypes.mouth, 0, 0);
|
||||
this.organism.addDefaultCell(CellStates.mouth, 0, 0);
|
||||
this.organism.updateGrid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ const Grid = require('../Grid/GridMap');
|
||||
const Renderer = require('../Rendering/Renderer');
|
||||
const GridMap = require('../Grid/GridMap');
|
||||
const Organism = require('../Organism/Organism');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
const Cell = require('../Organism/Cell/Cell');
|
||||
const CellStates = require('../Organism/Cell/CellStates');
|
||||
const Cell = require('../Organism/Cell/GridCell');
|
||||
const EnvironmentController = require('../Controllers/EnvironmentController');
|
||||
|
||||
class WorldEnvironment extends Environment{
|
||||
@@ -54,12 +54,12 @@ class WorldEnvironment extends Environment{
|
||||
OriginOfLife() {
|
||||
var center = this.grid_map.getCenter();
|
||||
var org = new Organism(center[0], center[1], this);
|
||||
// org.addCell(CellTypes.eye, 0, 0);
|
||||
// org.addCell(CellTypes.mouth, 1, 1);
|
||||
// org.addCell(CellTypes.mover, -1, -1);
|
||||
org.addCell(CellTypes.mouth, 0, 0);
|
||||
org.addCell(CellTypes.producer, 1, 1);
|
||||
org.addCell(CellTypes.producer, -1, -1);
|
||||
org.addDefaultCell(CellStates.eye, 0, 0);
|
||||
org.addDefaultCell(CellStates.mouth, 1, 1);
|
||||
org.addDefaultCell(CellStates.mover, 1, -1);
|
||||
// org.addDefaultCell(CellStates.mouth, 0, 0);
|
||||
// org.addDefaultCell(CellStates.producer, 1, 1);
|
||||
// org.addDefaultCell(CellStates.producer, -1, -1);
|
||||
this.addOrganism(org);
|
||||
}
|
||||
|
||||
@@ -77,17 +77,17 @@ class WorldEnvironment extends Environment{
|
||||
return this.total_mutability / this.organisms.length;
|
||||
}
|
||||
|
||||
changeCell(c, r, type, owner) {
|
||||
super.changeCell(c, r, type, owner);
|
||||
changeCell(c, r, state, owner) {
|
||||
super.changeCell(c, r, state, owner);
|
||||
this.renderer.addToRender(this.grid_map.cellAt(c, r));
|
||||
if(type == CellTypes.wall)
|
||||
if(state == CellStates.wall)
|
||||
this.walls.push(this.grid_map.cellAt(c, r));
|
||||
}
|
||||
|
||||
clearWalls() {
|
||||
for(var wall of this.walls){
|
||||
if (this.grid_map.cellAt(wall.col, wall.row).type == CellTypes.wall)
|
||||
this.changeCell(wall.col, wall.row, CellTypes.empty, null);
|
||||
if (this.grid_map.cellAt(wall.col, wall.row).state == CellStates.wall)
|
||||
this.changeCell(wall.col, wall.row, CellStates.empty, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class WorldEnvironment extends Environment{
|
||||
|
||||
reset(clear_walls=true) {
|
||||
this.organisms = [];
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
this.grid_map.fillGrid(CellStates.empty);
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
this.total_mutability = 0;
|
||||
this.OriginOfLife();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const Cell = require('../Organism/Cell/Cell');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
const Cell = require('../Organism/Cell/GridCell');
|
||||
const CellStates = require('../Organism/Cell/CellStates');
|
||||
|
||||
class GridMap {
|
||||
constructor(cols, rows, cell_size) {
|
||||
@@ -14,18 +14,19 @@ class GridMap {
|
||||
for(var c=0; c<cols; c++) {
|
||||
var row = [];
|
||||
for(var r=0; r<rows; r++) {
|
||||
var cell = new Cell(CellTypes.empty, c, r, c*cell_size, r*cell_size);
|
||||
var cell = new Cell(CellStates.empty, c, r, c*cell_size, r*cell_size);
|
||||
row.push(cell);
|
||||
}
|
||||
this.grid.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
fillGrid(type) {
|
||||
fillGrid(state) {
|
||||
for (var col of this.grid) {
|
||||
for (var cell of col) {
|
||||
cell.setType(type);
|
||||
cell.setType(state);
|
||||
cell.owner = null;
|
||||
cell.cell_owner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,18 +38,22 @@ class GridMap {
|
||||
return this.grid[col][row];
|
||||
}
|
||||
|
||||
setCellType(col, row, type) {
|
||||
setCellType(col, row, state) {
|
||||
if (!this.isValidLoc(col, row)) {
|
||||
return;
|
||||
}
|
||||
this.grid[col][row].setType(type);
|
||||
this.grid[col][row].setType(state);
|
||||
}
|
||||
|
||||
setCellOwner(col, row, owner) {
|
||||
setCellOwner(col, row, cell_owner) {
|
||||
if (!this.isValidLoc(col, row)) {
|
||||
return;
|
||||
}
|
||||
this.grid[col][row].owner = owner;
|
||||
this.grid[col][row].cell_owner = cell_owner;
|
||||
if (cell_owner != null)
|
||||
this.grid[col][row].owner = cell_owner.org;
|
||||
else
|
||||
this.grid[col][row].owner = null;
|
||||
}
|
||||
|
||||
isValidLoc(col, row){
|
||||
|
||||
10
src/Organism/Cell/BodyCells/ArmorCell.js
Normal file
10
src/Organism/Cell/BodyCells/ArmorCell.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
|
||||
class ArmorCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.armor, org, loc_col, loc_row);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ArmorCell;
|
||||
73
src/Organism/Cell/BodyCells/BodyCell.js
Normal file
73
src/Organism/Cell/BodyCells/BodyCell.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const Directions = require("../../Directions");
|
||||
|
||||
// A body cell defines the relative location of the cell in it's parent organism. It also defines their functional behavior.
|
||||
class BodyCell{
|
||||
constructor(state, org, loc_col, loc_row){
|
||||
this.state = state;
|
||||
this.org = org;
|
||||
this.loc_col = loc_col;
|
||||
this.loc_row = loc_row;
|
||||
}
|
||||
|
||||
initInherit(parent) {
|
||||
// deep copy parent values
|
||||
this.loc_col = parent.loc_col;
|
||||
this.loc_row = parent.loc_row;
|
||||
}
|
||||
|
||||
initRandom() {
|
||||
// initialize values randomly
|
||||
}
|
||||
|
||||
initDefault() {
|
||||
// initialize to default values
|
||||
}
|
||||
|
||||
performFunction(env) {
|
||||
// default behavior: none
|
||||
}
|
||||
|
||||
|
||||
getRealCol() {
|
||||
return this.org.c + this.rotatedCol(this.org.rotation);
|
||||
}
|
||||
|
||||
getRealRow() {
|
||||
return this.org.r + this.rotatedRow(this.org.rotation);
|
||||
}
|
||||
|
||||
getRealCell() {
|
||||
var real_c = this.getRealCol();
|
||||
var real_r = this.getRealRow();
|
||||
return this.org.env.grid_map.cellAt(real_c, real_r);
|
||||
}
|
||||
|
||||
rotatedCol(dir){
|
||||
switch(dir){
|
||||
case Directions.up:
|
||||
return this.loc_col;
|
||||
case Directions.down:
|
||||
return this.loc_col * -1;
|
||||
case Directions.left:
|
||||
return this.loc_row;
|
||||
case Directions.right:
|
||||
return this.loc_row * -1;
|
||||
}
|
||||
}
|
||||
|
||||
rotatedRow(dir){
|
||||
switch(dir){
|
||||
case Directions.up:
|
||||
return this.loc_row;
|
||||
case Directions.down:
|
||||
return this.loc_row * -1;
|
||||
case Directions.left:
|
||||
return this.loc_col * -1;
|
||||
case Directions.right:
|
||||
return this.loc_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BodyCell;
|
||||
42
src/Organism/Cell/BodyCells/BodyCellFactory.js
Normal file
42
src/Organism/Cell/BodyCells/BodyCellFactory.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const MouthCell = require("./MouthCell");
|
||||
const ProducerCell = require("./ProducerCell");
|
||||
const MoverCell = require("./MoverCell");
|
||||
const KillerCell = require("./KillerCell");
|
||||
const ArmorCell = require("./ArmorCell");
|
||||
const EyeCell = require("./EyeCell");
|
||||
const CellStates = require("../CellStates");
|
||||
|
||||
|
||||
const BodyCellFactory = {
|
||||
init: function() {
|
||||
var type_map = {};
|
||||
type_map[CellStates.mouth.name] = MouthCell;
|
||||
type_map[CellStates.producer.name] = ProducerCell;
|
||||
type_map[CellStates.mover.name] = MoverCell;
|
||||
type_map[CellStates.killer.name] = KillerCell;
|
||||
type_map[CellStates.armor.name] = ArmorCell;
|
||||
type_map[CellStates.eye.name] = EyeCell;
|
||||
this.type_map = type_map;
|
||||
},
|
||||
|
||||
createInherited: function(org, to_copy) {
|
||||
var cell = new this.type_map[to_copy.state.name](org, to_copy.loc_col, to_copy.loc_row);
|
||||
cell.initInherit(to_copy);
|
||||
return cell;
|
||||
},
|
||||
|
||||
createRandom: function(org, state, loc_col, loc_row) {
|
||||
var cell = new this.type_map[state.name](org, loc_col, loc_row);
|
||||
cell.initRandom();
|
||||
return cell;
|
||||
},
|
||||
|
||||
createDefault: function(org, state, loc_col, loc_row) {
|
||||
var cell = new this.type_map[state.name](org, loc_col, loc_row);
|
||||
cell.initDefault();
|
||||
return cell;
|
||||
},
|
||||
}
|
||||
BodyCellFactory.init();
|
||||
|
||||
module.exports = BodyCellFactory;
|
||||
81
src/Organism/Cell/BodyCells/EyeCell.js
Normal file
81
src/Organism/Cell/BodyCells/EyeCell.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
const Hyperparams = require("../../../Hyperparameters");
|
||||
const Directions = require("../../Directions");
|
||||
const Observation = require("../../Perception/Observation")
|
||||
|
||||
class EyeCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.eye, org, loc_col, loc_row);
|
||||
this.org.has_eyes = true;
|
||||
}
|
||||
|
||||
initInherit(parent) {
|
||||
// deep copy parent values
|
||||
super.initInherit(parent);
|
||||
this.direction = parent.direction;
|
||||
}
|
||||
|
||||
initRandom() {
|
||||
// initialize values randomly
|
||||
this.direction = Directions.getRandomDirection();
|
||||
}
|
||||
|
||||
initDefault() {
|
||||
// initialize to default values
|
||||
this.direction = Directions.up;
|
||||
}
|
||||
|
||||
getAbsoluteDirection() {
|
||||
var dir = this.org.rotation + this.direction;
|
||||
if (dir > 3)
|
||||
dir -= 4;
|
||||
return dir;
|
||||
}
|
||||
|
||||
performFunction() {
|
||||
var obs = this.look();
|
||||
this.org.brain.observe(obs);
|
||||
}
|
||||
|
||||
look() {
|
||||
var env = this.org.env;
|
||||
var direction = this.getAbsoluteDirection();
|
||||
var addCol = 0;
|
||||
var addRow = 0;
|
||||
switch(direction) {
|
||||
case Directions.up:
|
||||
addRow = -1;
|
||||
break;
|
||||
case Directions.down:
|
||||
addRow = 1;
|
||||
break;
|
||||
case Directions.right:
|
||||
addCol = 1;
|
||||
break;
|
||||
case Directions.left:
|
||||
addCol = -1;
|
||||
break;
|
||||
}
|
||||
var start_col = this.getRealCol();
|
||||
var start_row = this.getRealRow();
|
||||
var col = start_col;
|
||||
var row = start_row;
|
||||
var cell = null;
|
||||
for (var i=0; i<Hyperparams.lookRange; i++){
|
||||
col+=addCol;
|
||||
row+=addRow;
|
||||
cell = env.grid_map.cellAt(col, row);
|
||||
if (cell == null) {
|
||||
break;
|
||||
}
|
||||
if (cell.state != CellStates.empty){
|
||||
var distance = Math.abs(start_col-col) + Math.abs(start_row-row);
|
||||
return new Observation(cell, distance, direction);
|
||||
}
|
||||
}
|
||||
return new Observation(cell, Hyperparams.lookRange, direction);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EyeCell;
|
||||
32
src/Organism/Cell/BodyCells/KillerCell.js
Normal file
32
src/Organism/Cell/BodyCells/KillerCell.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
const Hyperparams = require("../../../Hyperparameters");
|
||||
|
||||
class KillerCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.killer, org, loc_col, loc_row);
|
||||
}
|
||||
|
||||
performFunction() {
|
||||
var env = this.org.env;
|
||||
var c = this.getRealCol();
|
||||
var r = this.getRealRow();
|
||||
for (var loc of Hyperparams.killableNeighbors) {
|
||||
var cell = env.grid_map.cellAt(c+loc[0], r+loc[1]);
|
||||
this.killNeighbor(cell);
|
||||
}
|
||||
}
|
||||
|
||||
killNeighbor(n_cell) {
|
||||
// console.log(n_cell)
|
||||
if(n_cell == null || n_cell.owner == null || n_cell.owner == this.org || !n_cell.owner.living || n_cell.state == CellStates.armor)
|
||||
return;
|
||||
var is_hit = n_cell.state == CellStates.killer; // has to be calculated before death
|
||||
n_cell.owner.harm();
|
||||
if (is_hit) {
|
||||
this.org.harm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = KillerCell;
|
||||
30
src/Organism/Cell/BodyCells/MouthCell.js
Normal file
30
src/Organism/Cell/BodyCells/MouthCell.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
const Hyperparams = require("../../../Hyperparameters");
|
||||
|
||||
class MouthCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.mouth, org, loc_col, loc_row);
|
||||
}
|
||||
|
||||
performFunction() {
|
||||
var env = this.org.env;
|
||||
var real_c = this.getRealCol();
|
||||
var real_r = this.getRealRow();
|
||||
for (var loc of Hyperparams.edibleNeighbors){
|
||||
var cell = env.grid_map.cellAt(real_c+loc[0], real_r+loc[1]);
|
||||
this.eatNeighbor(cell, env);
|
||||
}
|
||||
}
|
||||
|
||||
eatNeighbor(n_cell, env) {
|
||||
if (n_cell == null)
|
||||
return;
|
||||
if (n_cell.state == CellStates.food){
|
||||
env.changeCell(n_cell.col, n_cell.row, CellStates.empty, null);
|
||||
this.org.food_collected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MouthCell;
|
||||
11
src/Organism/Cell/BodyCells/MoverCell.js
Normal file
11
src/Organism/Cell/BodyCells/MoverCell.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
|
||||
class MoverCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.mover, org, loc_col, loc_row);
|
||||
this.org.is_mover = true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MoverCell;
|
||||
31
src/Organism/Cell/BodyCells/ProducerCell.js
Normal file
31
src/Organism/Cell/BodyCells/ProducerCell.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const CellStates = require("../CellStates");
|
||||
const BodyCell = require("./BodyCell");
|
||||
const Hyperparams = require("../../../Hyperparameters");
|
||||
|
||||
class ProducerCell extends BodyCell{
|
||||
constructor(org, loc_col, loc_row){
|
||||
super(CellStates.producer, org, loc_col, loc_row);
|
||||
this.org.is_producer = true;
|
||||
}
|
||||
|
||||
performFunction() {
|
||||
if (this.org.is_mover && !Hyperparams.moversCanProduce)
|
||||
return;
|
||||
var env = this.org.env;
|
||||
var prob = Hyperparams.foodProdProb;
|
||||
var real_c = this.getRealCol();
|
||||
var real_r = this.getRealRow();
|
||||
if (Math.random() * 100 <= prob) {
|
||||
var loc = Hyperparams.growableNeighbors[Math.floor(Math.random() * Hyperparams.growableNeighbors.length)]
|
||||
var loc_c=loc[0];
|
||||
var loc_r=loc[1];
|
||||
var cell = env.grid_map.cellAt(real_c+loc_c, real_r+loc_r);
|
||||
if (cell != null && cell.state == CellStates.empty){
|
||||
env.changeCell(real_c+loc_c, real_r+loc_r, CellStates.food, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProducerCell;
|
||||
@@ -1,98 +0,0 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
|
||||
// A cell exists in a grid map.
|
||||
class Cell{
|
||||
constructor(type, col, row, x, y){
|
||||
this.owner = null;
|
||||
this.setType(type);
|
||||
this.col = col;
|
||||
this.row = row;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.func = null;
|
||||
}
|
||||
|
||||
setType(type) {
|
||||
this.type = type;
|
||||
switch(this.type){
|
||||
case CellTypes.mouth:
|
||||
this.func = eatFood;
|
||||
break;
|
||||
case CellTypes.producer:
|
||||
this.func = growFood;
|
||||
break;
|
||||
case CellTypes.killer:
|
||||
this.func = killNeighbors;
|
||||
break;
|
||||
default:
|
||||
this.func = null;
|
||||
}
|
||||
}
|
||||
|
||||
performFunction(env) {
|
||||
if (this.func == null) return;
|
||||
this.func(this, env);
|
||||
}
|
||||
|
||||
getColor() {
|
||||
return CellTypes.colors[this.type];
|
||||
}
|
||||
|
||||
isLiving() {
|
||||
return this.type != CellTypes.empty &&
|
||||
this.type != CellTypes.food &&
|
||||
this.type != CellTypes.wall;
|
||||
}
|
||||
}
|
||||
|
||||
function eatFood(self, env){
|
||||
for (var loc of Hyperparams.edibleNeighbors){
|
||||
var cell = env.grid_map.cellAt(self.col+loc[0], self.row+loc[1]);
|
||||
eatNeighborFood(self, cell, env);
|
||||
}
|
||||
}
|
||||
|
||||
function eatNeighborFood(self, n_cell, env){
|
||||
if (n_cell == null)
|
||||
return;
|
||||
if (n_cell.type == CellTypes.food){
|
||||
env.changeCell(n_cell.col, n_cell.row, CellTypes.empty, null);
|
||||
self.owner.food_collected++;
|
||||
}
|
||||
}
|
||||
|
||||
function growFood(self, env){
|
||||
if (self.owner.is_mover && !Hyperparams.moversCanProduce)
|
||||
return;
|
||||
var prob = Hyperparams.foodProdProb;
|
||||
if (Math.random() * 100 <= prob){
|
||||
var loc = Hyperparams.growableNeighbors[Math.floor(Math.random() * Hyperparams.growableNeighbors.length)]
|
||||
var c=loc[0];
|
||||
var r=loc[1];
|
||||
var cell = env.grid_map.cellAt(self.col+c, self.row+r);
|
||||
if (cell != null && cell.type == CellTypes.empty){
|
||||
env.changeCell(self.col+c, self.row+r, CellTypes.food, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function killNeighbors(self, env) {
|
||||
for (var loc of Hyperparams.killableNeighbors){
|
||||
var cell = env.grid_map.cellAt(self.col+loc[0], self.row+loc[1]);
|
||||
killNeighbor(self, cell);
|
||||
}
|
||||
}
|
||||
|
||||
function killNeighbor(self, n_cell) {
|
||||
if(n_cell == null || n_cell.owner == null || self.owner == null || n_cell.owner == self.owner || !n_cell.owner.living || n_cell.type == CellTypes.armor)
|
||||
return;
|
||||
var is_hit = n_cell.type == CellTypes.killer; // has to be calculated before death
|
||||
n_cell.owner.harm();
|
||||
if (is_hit){
|
||||
self.owner.harm();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Cell;
|
||||
100
src/Organism/Cell/CellStates.js
Normal file
100
src/Organism/Cell/CellStates.js
Normal file
@@ -0,0 +1,100 @@
|
||||
// A cell state is used to differentiate type and render the cell
|
||||
class CellState{
|
||||
constructor(name, color) {
|
||||
this.name = name;
|
||||
this.color = color
|
||||
}
|
||||
|
||||
render(ctx, cell, size) {
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fillRect(cell.x, cell.y, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
class Empty extends CellState {
|
||||
constructor() {
|
||||
super('empty', '#121D29');
|
||||
}
|
||||
}
|
||||
class Food extends CellState {
|
||||
constructor() {
|
||||
super('food', 'green');
|
||||
}
|
||||
}
|
||||
class Wall extends CellState {
|
||||
constructor() {
|
||||
super('wall', 'gray');
|
||||
}
|
||||
}
|
||||
class Mouth extends CellState {
|
||||
constructor() {
|
||||
super('mouth', 'orange');
|
||||
}
|
||||
}
|
||||
class Producer extends CellState {
|
||||
constructor() {
|
||||
super('producer', 'white');
|
||||
}
|
||||
}
|
||||
class Mover extends CellState {
|
||||
constructor() {
|
||||
super('mover', '#3493EB');
|
||||
}
|
||||
}
|
||||
class Killer extends CellState {
|
||||
constructor() {
|
||||
super('killer', 'red');
|
||||
}
|
||||
}
|
||||
class Armor extends CellState {
|
||||
constructor() {
|
||||
super('armor', 'purple');
|
||||
}
|
||||
}
|
||||
class Eye extends CellState {
|
||||
constructor() {
|
||||
super('eye', '#d4bb3f');
|
||||
this.slit_color = '#121D29';
|
||||
}
|
||||
render(ctx, cell, size) {
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fillRect(cell.x, cell.y, size, size);
|
||||
if(size == 1)
|
||||
return;
|
||||
var half = size/2;
|
||||
var x = -(size)/8
|
||||
var y = -half
|
||||
var h = size/2 + size/4;
|
||||
var w = size/4;
|
||||
ctx.translate(cell.x+half, cell.y+half);
|
||||
ctx.rotate((cell.cell_owner.getAbsoluteDirection() * 90) * Math.PI / 180);
|
||||
ctx.fillStyle = this.slit_color
|
||||
ctx.fillRect(x, y, w, h);
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const CellStates = {
|
||||
empty: new Empty(),
|
||||
food: new Food(),
|
||||
wall: new Wall(),
|
||||
mouth: new Mouth(),
|
||||
producer: new Producer(),
|
||||
mover: new Mover(),
|
||||
killer: new Killer(),
|
||||
armor: new Armor(),
|
||||
eye: new Eye(),
|
||||
defineLists() {
|
||||
this.all = [this.empty, this.food, this.wall, this.mouth, this.producer, this.mover, this.killer, this.armor, this.eye]
|
||||
this.living = [this.mouth, this.producer, this.mover, this.killer, this.armor, this.eye];
|
||||
},
|
||||
getRandomName: function() {
|
||||
return this.all[Math.floor(Math.random() * this.all.length)].name;
|
||||
},
|
||||
getRandomLivingType: function() {
|
||||
return this.living[Math.floor(Math.random() * this.living.length)];
|
||||
}
|
||||
}
|
||||
CellStates.defineLists();
|
||||
|
||||
module.exports = CellStates;
|
||||
21
src/Organism/Cell/GridCell.js
Normal file
21
src/Organism/Cell/GridCell.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const CellStates = require("./CellStates");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
|
||||
// A cell exists in a grid map.
|
||||
class Cell{
|
||||
constructor(state, col, row, x, y){
|
||||
this.owner = null; // owner organism
|
||||
this.cell_owner = null; // owner cell of ^that organism
|
||||
this.setType(state);
|
||||
this.col = col;
|
||||
this.row = row;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
setType(state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Cell;
|
||||
@@ -1,15 +1,14 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Directions = require("../Directions");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
const CellStates = require("./CellStates");
|
||||
const Directions = require("../Directions");;
|
||||
const Eye = require("../Perception/Eye.js");
|
||||
|
||||
// A local cell is a lightweight container for a cell in an organism. It does not directly exist in the grid
|
||||
// A body cell defines the relative location of the cell in it's parent organism. It also defines their functional behavior.
|
||||
class LocalCell{
|
||||
constructor(type, loc_col, loc_row, eye=null){
|
||||
this.type = type;
|
||||
constructor(state, loc_col, loc_row, eye=null){
|
||||
this.state = state;
|
||||
this.loc_col = loc_col;
|
||||
this.loc_row = loc_row;
|
||||
if (this.type == CellTypes.eye){
|
||||
if (this.state == CellStates.eye){
|
||||
this.eye = new Eye();
|
||||
if (eye != null) {
|
||||
this.eye.direction = eye.direction;
|
||||
@@ -17,8 +16,6 @@ class LocalCell{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
rotatedCol(dir){
|
||||
switch(dir){
|
||||
case Directions.up:
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
const CellTypes = require("./Cell/CellTypes");
|
||||
const Cell = require("./Cell/Cell");
|
||||
// const CellTypes = require("./Cell/CellTypes");
|
||||
const CellStates = require("../Organism/Cell/CellStates");
|
||||
const Cell = require("./Cell/GridCell");
|
||||
const GridMap = require("../Grid/GridMap");
|
||||
const LocalCell = require("./Cell/LocalCell");
|
||||
const BodyCellFactory = require("./Cell/BodyCells/BodyCellFactory");
|
||||
const Neighbors = require("../Grid/Neighbors");
|
||||
const Hyperparams = require("../Hyperparameters");
|
||||
const Directions = require("./Directions");
|
||||
@@ -36,39 +38,54 @@ class Organism {
|
||||
}
|
||||
}
|
||||
|
||||
addCell(type, c, r, eye=null) {
|
||||
canAddCellAt(c, r) {
|
||||
for (var cell of this.cells) {
|
||||
if (cell.loc_col == c && cell.loc_row == r){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkTypeChange(type);
|
||||
this.cells.push(new LocalCell(type, c, r, eye));
|
||||
return true;
|
||||
}
|
||||
|
||||
removeCell(c, r) {
|
||||
if (c == 0 && r == 0)
|
||||
addDefaultCell(state, c, r) {
|
||||
var new_cell = BodyCellFactory.createDefault(this, state, c, r);
|
||||
this.cells.push(new_cell);
|
||||
return new_cell;
|
||||
}
|
||||
|
||||
addRandomizedCell(state, c, r) {
|
||||
var new_cell = BodyCellFactory.createRandom(this, state, c, r);
|
||||
this.cells.push(new_cell);
|
||||
return new_cell;
|
||||
}
|
||||
|
||||
addInheritCell(parent_cell) {
|
||||
var new_cell = BodyCellFactory.createInherited(this, parent_cell);
|
||||
this.cells.push(new_cell);
|
||||
return new_cell;
|
||||
}
|
||||
|
||||
replaceCell(state, c, r, randomize=true) {
|
||||
this.removeCell(c, r, true);
|
||||
if (randomize) {
|
||||
return this.addRandomizedCell(state, c, r);
|
||||
}
|
||||
else {
|
||||
return this.addDefaultCell(state, c, r);
|
||||
}
|
||||
}
|
||||
|
||||
removeCell(c, r, override_defense=false) {
|
||||
if (c == 0 && r == 0 && !override_defense)
|
||||
return false;
|
||||
var check_change = false;
|
||||
for (var i=0; i<this.cells.length; i++) {
|
||||
var cell = this.cells[i];
|
||||
if (cell.loc_col == c && cell.loc_row == r){
|
||||
if (cell.type == CellTypes.producer || cell.type == CellTypes.mover) {
|
||||
check_change = true;
|
||||
}
|
||||
this.cells.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (check_change) {
|
||||
this.is_producer = false;
|
||||
this.is_producer = false;
|
||||
for (var cell of this.cells) {
|
||||
this.checkTypeChange(cell.type);
|
||||
}
|
||||
}
|
||||
this.checkTypeChange(cell.state);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -81,13 +98,18 @@ class Organism {
|
||||
return null;
|
||||
}
|
||||
|
||||
checkTypeChange(type) {
|
||||
if (type == CellTypes.producer)
|
||||
this.is_producer = true;
|
||||
if (type == CellTypes.mover)
|
||||
this.is_mover = true;
|
||||
if (type == CellTypes.eye)
|
||||
this.has_eyes = true;
|
||||
checkTypeChange() {
|
||||
this.is_producer = false;
|
||||
this.is_mover = false;
|
||||
this.has_eyes = false;
|
||||
for (var cell of this.cells) {
|
||||
if (cell.state == CellStates.producer)
|
||||
this.is_producer = true;
|
||||
if (cell.state == CellStates.mover)
|
||||
this.is_mover = true;
|
||||
if (cell.state == CellStates.eye)
|
||||
this.has_eyes = true;
|
||||
}
|
||||
}
|
||||
|
||||
inherit(parent) {
|
||||
@@ -96,11 +118,7 @@ class Organism {
|
||||
this.birth_distance = parent.birth_distance;
|
||||
for (var c of parent.cells){
|
||||
//deep copy parent cells
|
||||
if (c.type == CellTypes.eye){
|
||||
this.addCell(c.type, c.loc_col, c.loc_row, c.eye);
|
||||
}
|
||||
else
|
||||
this.addCell(c.type, c.loc_col, c.loc_row);
|
||||
this.addInheritCell(c);
|
||||
}
|
||||
if(parent.is_mover) {
|
||||
for (var i in parent.brain.decisions) {
|
||||
@@ -172,30 +190,32 @@ class Organism {
|
||||
var mutated = false;
|
||||
if (choice <= Hyperparams.addProb) {
|
||||
// add cell
|
||||
var type = CellTypes.getRandomLivingType();
|
||||
var num_to_add = Math.floor(Math.random() * 3) + 1;
|
||||
// console.log("add cell")
|
||||
|
||||
var state = CellStates.getRandomLivingType();
|
||||
var branch = this.cells[Math.floor(Math.random() * this.cells.length)];
|
||||
var growth_direction = Neighbors.all[Math.floor(Math.random() * Neighbors.all.length)]
|
||||
var c = branch.loc_col+growth_direction[0];
|
||||
var r = branch.loc_row+growth_direction[1];
|
||||
mutated = this.addCell(type, c, r);
|
||||
// mutated = this.addCell(state, c, r);
|
||||
if (this.canAddCellAt(c, r)){
|
||||
mutated = true;
|
||||
this.addRandomizedCell(state, c, r);
|
||||
}
|
||||
this.birth_distance++;
|
||||
}
|
||||
else if (choice <= Hyperparams.addProb + Hyperparams.changeProb){
|
||||
// change cell
|
||||
var cell = this.cells[Math.floor(Math.random() * this.cells.length)];
|
||||
if (cell.type == CellTypes.eye) {
|
||||
delete cell.eye;
|
||||
}
|
||||
cell.type = CellTypes.getRandomLivingType();
|
||||
if (cell.type == CellTypes.eye) {
|
||||
cell.eye = new Eye();
|
||||
}
|
||||
this.checkTypeChange(cell.type);
|
||||
var state = CellStates.getRandomLivingType();
|
||||
// console.log("change cell", state)
|
||||
this.replaceCell(state, cell.loc_col, cell.loc_row);
|
||||
mutated = true;
|
||||
}
|
||||
else if (choice <= Hyperparams.addProb + Hyperparams.changeProb + Hyperparams.removeProb){
|
||||
// remove cell
|
||||
// console.log("remove cell")
|
||||
|
||||
if(this.cells.length > 1) {
|
||||
var cell = this.cells[Math.floor(Math.random() * this.cells.length)];
|
||||
mutated = this.removeCell(cell.loc_col, cell.loc_row);
|
||||
@@ -229,7 +249,7 @@ class Organism {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.rotatedCol(this.rotation);
|
||||
var real_r = this.r + cell.rotatedRow(this.rotation);
|
||||
this.env.changeCell(real_c, real_r, CellTypes.empty, null);
|
||||
this.env.changeCell(real_c, real_r, CellStates.empty, null);
|
||||
}
|
||||
this.c = new_c;
|
||||
this.r = new_r;
|
||||
@@ -250,7 +270,7 @@ class Organism {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.rotatedCol(this.rotation);
|
||||
var real_r = this.r + cell.rotatedRow(this.rotation);
|
||||
this.env.changeCell(real_c, real_r, CellTypes.empty, null);
|
||||
this.env.changeCell(real_c, real_r, CellStates.empty, null);
|
||||
}
|
||||
this.rotation = new_rotation;
|
||||
this.direction = Directions.getRandomDirection();
|
||||
@@ -299,7 +319,7 @@ class Organism {
|
||||
}
|
||||
|
||||
isPassableCell(cell, parent){
|
||||
return cell != null && (cell.type == CellTypes.empty || cell.owner == this || cell.owner == parent || cell.type == CellTypes.food);
|
||||
return cell != null && (cell.state == CellStates.empty || cell.owner == this || cell.owner == parent || cell.state == CellStates.food);
|
||||
}
|
||||
|
||||
isClear(col, row, rotation=this.rotation) {
|
||||
@@ -308,7 +328,7 @@ class Organism {
|
||||
if(cell==null) {
|
||||
return false;
|
||||
}
|
||||
if (cell.owner==this || cell.type==CellTypes.empty || (!Hyperparams.foodBlocksReproduction && cell.type==CellTypes.food)){
|
||||
if (cell.owner==this || cell.state==CellStates.empty || (!Hyperparams.foodBlocksReproduction && cell.state==CellStates.food)){
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
@@ -327,7 +347,7 @@ class Organism {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.rotatedCol(this.rotation);
|
||||
var real_r = this.r + cell.rotatedRow(this.rotation);
|
||||
this.env.changeCell(real_c, real_r, CellTypes.food, null);
|
||||
this.env.changeCell(real_c, real_r, CellStates.food, null);
|
||||
}
|
||||
this.living = false;
|
||||
}
|
||||
@@ -336,10 +356,7 @@ class Organism {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.rotatedCol(this.rotation);
|
||||
var real_r = this.r + cell.rotatedRow(this.rotation);
|
||||
this.env.changeCell(real_c, real_r, cell.type, this);
|
||||
if (cell.type == CellTypes.eye) {
|
||||
this.getRealCell(cell).direction = cell.eye.getAbsoluteDirection(this.rotation);
|
||||
}
|
||||
this.env.changeCell(real_c, real_r, cell.state, cell);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,16 +370,9 @@ class Organism {
|
||||
this.reproduce();
|
||||
}
|
||||
for (var cell of this.cells) {
|
||||
if (cell.type == CellTypes.eye){
|
||||
var obs = cell.eye.look(this.getRealCol(cell), this.getRealRow(cell), this.rotation, this.env);
|
||||
this.brain.observe(obs);
|
||||
}
|
||||
else {
|
||||
this.getRealCell(cell).performFunction(this.env);
|
||||
if (!this.living){
|
||||
return this.living
|
||||
}
|
||||
}
|
||||
cell.performFunction();
|
||||
if (!this.living)
|
||||
return this.living
|
||||
}
|
||||
|
||||
if (this.is_mover) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const CellTypes = require("../Cell/CellTypes");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
const Directions = require("../Directions");
|
||||
const CellStates = require("../Cell/CellStates");
|
||||
|
||||
const Decision = {
|
||||
neutral: 0,
|
||||
@@ -17,17 +17,17 @@ class Brain {
|
||||
this.observations = [];
|
||||
|
||||
// corresponds to CellTypes
|
||||
this.decisions = [
|
||||
Decision.neutral, // empty
|
||||
Decision.chase, // food
|
||||
Decision.neutral, // wall
|
||||
Decision.neutral, // mouth
|
||||
Decision.neutral, // producer
|
||||
Decision.neutral, // mover
|
||||
Decision.retreat, // killer
|
||||
Decision.neutral, // armor
|
||||
Decision.neutral, // eye
|
||||
];
|
||||
this.decisions = [];
|
||||
this.decisions[CellStates.empty.name] = Decision.neutral;
|
||||
this.decisions[CellStates.food.name] = Decision.chase;
|
||||
this.decisions[CellStates.wall.name] = Decision.neutral;
|
||||
this.decisions[CellStates.mouth.name] = Decision.neutral;
|
||||
this.decisions[CellStates.producer.name] = Decision.neutral;
|
||||
this.decisions[CellStates.mover.name] = Decision.neutral;
|
||||
this.decisions[CellStates.killer.name] = Decision.retreat;
|
||||
this.decisions[CellStates.armor.name] = Decision.neutral;
|
||||
this.decisions[CellStates.eye.name] = Decision.neutral;
|
||||
|
||||
}
|
||||
|
||||
observe(observation) {
|
||||
@@ -43,7 +43,9 @@ class Brain {
|
||||
continue;
|
||||
}
|
||||
if (obs.distance < closest) {
|
||||
decision = this.decisions[obs.cell.type];
|
||||
// console.log(obs.cell.state)
|
||||
decision = this.decisions[obs.cell.state.name];
|
||||
// console.log(decision)
|
||||
move_direction = obs.direction;
|
||||
closest = obs.distance;
|
||||
}
|
||||
@@ -61,8 +63,8 @@ class Brain {
|
||||
}
|
||||
|
||||
mutate() {
|
||||
var selection = Math.floor(Math.random() * (this.decisions.length-1))+1;
|
||||
this.decisions[selection] = Decision.getRandom();
|
||||
this.decisions[CellStates.getRandomName()] = Decision.getRandom();
|
||||
this.decisions[CellStates.empty.name] = Decision.neutral; // if the empty cell has a decision it gets weird
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const Directions = require("../Directions");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
const CellTypes = require("../Cell/CellTypes");
|
||||
const CellStates = require("../Cell/CellStates");
|
||||
const Observation = require("./Observation")
|
||||
|
||||
class Eye {
|
||||
@@ -46,7 +46,7 @@ class Eye {
|
||||
if (cell == null) {
|
||||
break;
|
||||
}
|
||||
if (cell.type != CellTypes.empty){
|
||||
if (cell.state != CellStates.empty){
|
||||
var distance = Math.abs(start_col-col) + Math.abs(start_row-row);
|
||||
return new Observation(cell, distance, direction);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
// const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
const CellStates = require("../Organism/Cell/CellStates");
|
||||
const Directions = require("../Organism/Directions");
|
||||
|
||||
// Renderer controls access to a canvas. There is one renderer for each canvas
|
||||
@@ -47,36 +48,7 @@ class Renderer {
|
||||
}
|
||||
|
||||
renderCell(cell) {
|
||||
this.ctx.fillStyle = cell.getColor();
|
||||
this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);
|
||||
if (cell.type == CellTypes.eye) {
|
||||
this.renderEyeCell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
renderEyeCell(cell) {
|
||||
if(this.cell_size == 1)
|
||||
return;
|
||||
if (this.cell_size % 2 == 0){
|
||||
//even
|
||||
var w = 2;
|
||||
}
|
||||
else{
|
||||
//odd
|
||||
var w = 1;
|
||||
}
|
||||
var halfInt = Math.ceil(this.cell_size/2);
|
||||
var halfFloat = this.cell_size/2;
|
||||
var h = this.cell_size/2 + this.cell_size/4;
|
||||
var x = cell.x + h - Math.floor(w/2);
|
||||
var y = cell.y;
|
||||
|
||||
|
||||
this.ctx.translate(cell.x+halfFloat, cell.y+halfFloat);
|
||||
this.ctx.rotate((cell.direction * 90) * Math.PI / 180);
|
||||
this.ctx.fillStyle = '#121D29';
|
||||
this.ctx.fillRect(-(this.cell_size)/8, -halfFloat, this.cell_size/4, h);
|
||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
cell.state.render(this.ctx, cell, this.cell_size);
|
||||
}
|
||||
|
||||
renderOrganism(org) {
|
||||
|
||||
Reference in New Issue
Block a user