From 1e4733f7963001bc0050034d90d691315452ced2 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 6 Dec 2017 18:10:15 +0200 Subject: [PATCH 01/21] updated README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00aae1e..216ae21 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # construct [![Build Status](https://travis-ci.org/tmptrash/construct.svg?branch=master)](https://travis-ci.org/tmptrash/construct) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/da2d5c5f53d04df79c9aae3599555b4e)](https://www.codacy.com/app/flatline/construct?utm_source=github.com&utm_medium=referral&utm_content=tmptrash/construct&utm_campaign=Badge_Grade) -

construct is a native JavaScript/ES6 based, digital organisms evolution simulator. It's used for study the evolutionary biology of self-replicating and evolving computer programs (digital organisms). This project similar to Avida, but works with more abstract language (Digital Organism Script - DOS) instead of assembler. It uses special DOSVM for running DOS byte code and distributed computing to speed up the calculations. Generally, it consists of servers, which just a proxies between clients. All calculations are made on a client side only. It's possible to run the system in a "serverless" mode. For this, you have to run index.html (just drop it into the browser) in Chrome without server. More details for russian speaking people on blog and youtube channel. See video presentation here. +

construct is a native JavaScript/ES6 based, digital organisms evolution simulator. It's used for study the evolutionary biology of self-replicating and evolving computer programs (digital organisms). This project similar to Avida, but works with more abstract language (Digital Organism Script - DOS) instead of assembler. It uses special DOSVM for running DOS byte code and distributed computing to speed up the calculations. Generally, it consists of servers, which just a proxies between clients. All calculations are made on a client side only. It's possible to run the system in a "serverless" mode. For this, you have to run index.html (just drop it into the browser) in Chrome without server. More details for russian speaking people on blog and youtube channel. See video presentation here.

# Requirements @@ -29,4 +29,4 @@ Note: to improve speed, type `man.api.visualize(false)` in Chrome's devtool console during application run ___ -P.S. If you `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! \ No newline at end of file +P.S. If you `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! \ No newline at end of file From 08113d64807ec6aed5114813626bf5fefc7c7639 Mon Sep 17 00:00:00 2001 From: Taras Date: Thu, 14 Dec 2017 01:12:00 +0200 Subject: [PATCH 02/21] Update README.md A minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 216ae21..a8fa05f 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ Note: to improve speed, type `man.api.visualize(false)` in Chrome's devtool console during application run ___ -P.S. If you `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! \ No newline at end of file +P.S. If you are a `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! From 33bd8ad00527d3486927448fdeebf783d4a545c2 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 12 Mar 2018 16:43:45 +0200 Subject: [PATCH 03/21] fixed #128 --- client/src/manager/ManagerSpec.js | 4 -- .../src/manager/plugins/organisms/Config.js | 14 ++--- .../src/manager/plugins/organisms/Organism.js | 6 ++- .../plugins/organisms/dos/Code2String.js | 51 +++++++------------ client/src/vm/VM.js | 2 +- 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index acb5714..1104b1a 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -554,12 +554,10 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { - log('loop'); expect(man2.organisms.size).toBe(1); org1 = man1.organisms.first.val; org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() } else if (man2.organisms.size === 2) { - log('destroy'); destroy(); } if (iterated1 > 10000) {throw 'Error sending organism between Servers'} @@ -568,9 +566,7 @@ describe("client/src/manager/Manager", () => { man2.on(EVENTS.LOOP, () => iterated2++); waitEvent(server1, server1.EVENTS.RUN, () => server1.run(), () => { - log('server1 run'); waitEvent(server2, server2.EVENTS.RUN, () => server2.run(), () => { - log('server2 run'); man1.run(() => man2.run()); }); }); diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 4f28b4d..1adf25c 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,12 +15,12 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .000001, .000001, .00000001, .00000000001, .0000001, // var, const, if, loop, operator, - .0000001, .0002, .0002, .0002, .0002, // lookAt, eatLeft, eatRight, eatUp, eatDown, - .002, .002, .002, .002, // stepLeft, stepRight, stepUp, stepDown, - .000001, .000001, // fromMem, toMem, - .0000001, .0000001, // myX, myY, - .000001, .000001, .000001, .000001 // checkLeft, checkRight, checkUp, checkDown + .0001, .0001, .000001, .000000001, .00001, // var, const, if, loop, operator, + .00001, .02, .02, .02, .02, // lookAt, eatLeft, eatRight, eatUp, eatDown, + .2, .2, .2, .2, // stepLeft, stepRight, stepUp, stepDown, + .0001, .0001, // fromMem, toMem, + .00001, .00001, // myX, myY, + .0001, .0001, .0001, .0001 // checkLeft, checkRight, checkUp, checkDown ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -146,7 +146,7 @@ const Config = { * {Number} Amount of bits per one variable. It affects maximum value, * which this variable may contain. This value shouldn't be less then 2. */ - codeBitsPerVar: 4, + codeBitsPerVar: 2, /** * {Number} Amount of bits for storing operator. This is first XX bits * in a number. diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 9c96fdb..8d828b0 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -127,8 +127,10 @@ class Organism extends Observer { this._updateEnergy(); if (this._energy > 0) { this._updateClone(); - this._energy > 0 && this.fire(ITERATION, lines, this); - this._energy > 0 && this._updateAge(); + if (this._energy > 0) { + this.fire(ITERATION, lines, this); + this._energy > 0 && this._updateAge(); + } } return true; diff --git a/client/src/manager/plugins/organisms/dos/Code2String.js b/client/src/manager/plugins/organisms/dos/Code2String.js index 013efb2..7cc2bce 100644 --- a/client/src/manager/plugins/organisms/dos/Code2String.js +++ b/client/src/manager/plugins/organisms/dos/Code2String.js @@ -59,7 +59,7 @@ class Code2String { /** * {Array} Contains closing bracket offset for "if", "loop",... operators */ - this._offsets = []; + this._offsets = [0]; Num.init(this._OPERATORS_CB_LEN); @@ -86,35 +86,28 @@ class Code2String { const operators = this._OPERATORS_CB; const offs = this._offsets; let lines = new Array(len); - let needClose = 0; - + // + // First number always amount of code lines + // + offs.splice(0, offs.length, len); for (let line = 0; line < len; line++) { + lines[line] = operators[Num.getOperator(code[line])](code[line], line); // // We found closing bracket '}' of some loop and have to add // it to output code array // - if (line === offs[offs.length - 1]) { - while (offs.length > 0 && offs[offs.length - 1] === line) { - offs.pop(); - needClose++; - } - } - lines[line] = operators[Num.getOperator(code[line])](code[line], line, len); - if (needClose > 0) { - for (let i = 0; i < needClose; i++) { - lines[line] = '}' + lines[line]; - } - needClose = 0; + while (offs.length > 1 && line === offs[offs.length - 1]) { + line = offs.pop(); + lines[line] += '}'; } } // // All closing brackets st the end of JS script // const length = lines.length - 1; - for (let i = 0; i < offs.length; i++) { + for (let i = 1; i < offs.length; i++) { lines[length] += '}'; } - offs.length = 0; return js_beautify(lines.join(separator), {indent_size: 4}); } @@ -134,22 +127,22 @@ class Code2String { } _onConst(num) { - return `v${Num.getVar0(num)}=${Num.getBits(num, this._BITS_AFTER_THREE_VARS, OConfig.codeConstBits)}`; + return `v${Num.getVar0(num)}=${Num.getBits(num, this._BITS_AFTER_ONE_VAR, OConfig.codeConstBits)}`; } - _onCondition(num, line, lines) { + _onCondition(num, line) { const cond = Num.getBits(num, this._BITS_AFTER_TWO_VARS, CONDITION_BITS); const blockOffs = Num.getBits(num, this._BITS_AFTER_TWO_VARS + CONDITION_BITS, OConfig.codeBitsPerBlock); - this._offsets.push(this._getOffs(line, lines, blockOffs)); + this._offsets.push(this._getOffs(line, blockOffs)); return `if(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){`; } - _onLoop(num, line, lines) { + _onLoop(num, line) { const cond = Num.getBits(num, this._BITS_AFTER_TWO_VARS, CONDITION_BITS); const blockOffs = Num.getBits(num, this._BITS_AFTER_TWO_VARS + CONDITION_BITS, OConfig.codeBitsPerBlock); - this._offsets.push(this._getOffs(line, lines, blockOffs)); + this._offsets.push(this._getOffs(line, blockOffs)); return `while(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){`; } @@ -248,20 +241,12 @@ class Code2String { * So it's possible to set it to one of 1...3. So we change it in * real time to fix the overlap problem. * @param {Number} line Current line index - * @param {Number} lines Amount of lines * @param {Number} offs Local offset of closing bracket we want to set * @returns {Number} */ - _getOffs(line, lines, offs) { - let offset = line + offs < lines ? line + offs + 1 : lines; - const offsets = this._offsets; - const length = offsets.length; - - if (length > 0 && offset >= offsets[length - 1]) { - return offsets[length - 1]; - } - - return offset; + _getOffs(line, offs) { + const offsets = this._offsets || [0]; + return line + offs > offsets[offsets.length - 1] ? offsets[offsets.length - 1] : line + offs; } } diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index 22138f7..df075bd 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -107,7 +107,7 @@ class VM extends Observer { // This is very important peace of logic. As big the organism is // as more energy he spends // - org.energy -= (WEIGHTS[operator] * org.energy + (org.vm ? org.vm.size : 0)); + org.energy -= WEIGHTS[operator]; // // We found closing bracket '}' of some loop and have to return // to the beginning of operator (e.g.: for) From 296ff85ff333e545fadc062d9a05bfe6761642a6 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 13 Mar 2018 08:43:35 +0200 Subject: [PATCH 04/21] fixed tests #83 --- .../src/manager/plugins/organisms/Config.js | 2 +- .../plugins/organisms/dos/OrganismSpec.js | 5 ++-- client/src/vm/VMSpec.js | 2 +- server/src/server/ServerSpec.js | 29 ++++++++++++------- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 1adf25c..ecba4b1 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -146,7 +146,7 @@ const Config = { * {Number} Amount of bits per one variable. It affects maximum value, * which this variable may contain. This value shouldn't be less then 2. */ - codeBitsPerVar: 2, + codeBitsPerVar: 4, /** * {Number} Amount of bits for storing operator. This is first XX bits * in a number. diff --git a/client/src/manager/plugins/organisms/dos/OrganismSpec.js b/client/src/manager/plugins/organisms/dos/OrganismSpec.js index 27281c9..636e920 100644 --- a/client/src/manager/plugins/organisms/dos/OrganismSpec.js +++ b/client/src/manager/plugins/organisms/dos/OrganismSpec.js @@ -82,7 +82,6 @@ describe("client/src/organism/OrganismDos", () => { OConfig.orgStartEnergy = energy; }); - it("Organism should not be dead after loosing some energy", () => { const period = OConfig.orgAlivePeriod; const energy = OConfig.orgStartEnergy; @@ -99,9 +98,9 @@ describe("client/src/organism/OrganismDos", () => { expect(org1.energy).toBe(100); org1.run(); - expect(org1.energy).toBe(89); // 100 - (100 * .1 + 1) = 89 + expect(org1.energy).toBe(99.9); // 100 - .1 = 99.9 org1.run(); - expect(org1.energy).toBe(79.1); // 90 - (90 * .1 + 1) = 79.1 + expect(org1.energy).toBe(99.80000000000001); // 99.9 - .1 = 99.8 org1.destroy(); expect(org1.energy < 1).toBe(true); diff --git a/client/src/vm/VMSpec.js b/client/src/vm/VMSpec.js index ba7e2b1..08fe69d 100644 --- a/client/src/vm/VMSpec.js +++ b/client/src/vm/VMSpec.js @@ -238,7 +238,7 @@ describe("client/src/organism/VM", () => { vm.updateLine(0, 0x00000000); expect(org.energy).toEqual(100); vm.run(org); - expect(org.energy).toEqual(90); // 100 - (100 * .1 + 0) = 90 + expect(org.energy).toEqual(99.9); // 100 - .1 = 99.9 org.destroy(); vm.destroy(); diff --git a/server/src/server/ServerSpec.js b/server/src/server/ServerSpec.js index 161f0c3..d4f7b1f 100644 --- a/server/src/server/ServerSpec.js +++ b/server/src/server/ServerSpec.js @@ -209,13 +209,17 @@ describe("server/src/server/Server", () => { const ws1 = new WebSocket(CLIENT_URL); const ws2 = new WebSocket(CLIENT_URL); Helper.wait(waitObj, () => { - server.on(SEVENTS.STOP, () => waitObj.done = true); - server.stop(); + cons = 0; + server.on(SEVENTS.CLOSE, () => ++cons === 2 && (waitObj.done = true)); ws1.close(); ws2.close(); Helper.wait(waitObj, () => { - server.destroy(); - done(); + server.on(SEVENTS.STOP, () => waitObj.done = true); + server.stop(); + Helper.wait(waitObj, () => { + server.destroy(); + done(); + }); }); }); }); @@ -232,12 +236,12 @@ describe("server/src/server/Server", () => { server.on(SEVENTS.CLOSE, () => waitObj.done = true); ws2.close(); Helper.wait(waitObj, () => { - server.on(SEVENTS.STOP, () => waitObj.done = true); - server.stop(); + server.on(SEVENTS.CLOSE, () => waitObj.done = true); ws1.close(); Helper.wait(waitObj, () => { + server.on(SEVENTS.DESTROY, () => waitObj.done = true); server.destroy(); - done(); + Helper.wait(waitObj, done); }); }) }); @@ -265,12 +269,15 @@ describe("server/src/server/Server", () => { const ws = new WebSocket(CLIENT_URL); Helper.wait(waitObj, () => { expect(server.active).toEqual(true); - server.on(SEVENTS.STOP, () => waitObj.done = true); - server.destroy(); + server.on(SEVENTS.CLOSE, () => waitObj.done = true); ws.close(); Helper.wait(waitObj, () => { - expect(server.active).toEqual(false); - done(); + server.on(SEVENTS.DESTROY, () => waitObj.done = true); + server.destroy(); + Helper.wait(waitObj, () => { + expect(server.active).toEqual(false); + done(); + }); }); }); }); From 290015655ad4aee40fd9e95ac9cb82b90d3c32e0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 22 Mar 2018 13:30:40 +0200 Subject: [PATCH 05/21] added console API commends to the README #118 fixed small issue with extra mutations on start added min energy for ability to clone added description to API methods changed version to 0.2.1.1 --- README.md | 13 ++++++ client/src/manager/Manager.js | 6 ++- client/src/manager/plugins/Config.js | 7 ++-- .../src/manager/plugins/organisms/Config.js | 22 ++++++---- .../src/manager/plugins/organisms/Mutator.js | 2 +- .../src/manager/plugins/organisms/Organism.js | 2 +- .../manager/plugins/organisms/Organisms.js | 41 ++++++++++++++++--- .../plugins/organisms/dos/Code2String.js | 3 +- .../plugins/organisms/dos/Operators.js | 4 +- .../plugins/organisms/dos/OrganismSpec.js | 5 ++- .../manager/plugins/status/charts/Charts.js | 2 +- common/src/Configurable.js | 3 +- common/src/Helper.js | 12 ++++++ 13 files changed, 93 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 8ef7c8b..73e33a6 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,19 @@ - Run server `npm run server` on chosen host - Copy `./client/dist/index.html` and `./client/dist/app.js` on all your remote machines and run it there under Chrome +# Main commands +As an administrator, you may affect the system by command line API. For instance, you may obtain amount of organisms in current population or set new configuration in real time. For this, you have to open Chrome console (press `F12`) and type `man.api[.namespace].xxx()`. Where `namespace` is an optional unit or module and `xxx()` is supported command of this module. It's possible to use `desc` property to get command description. Example: `man.api.getConfig.desc`. Here are all available commands separated by namespace: +- global namespace - `man.api`: + - `man.api.visualize(show:Boolean = true)` - Turns on/off visualization in browser for current instance (world). Turning visualization off, increases application speed. + - `man.api.formatCode(code:Array)` - Converts byte code array into human readable JavaScript based code. This function is low level. For using it you have to get organism's virtual machine reference and then use it's `code` property. For example: `man.api.formatCode(man.api.organisms.getOrganism('128').vm.code)`. This example will find organism with id `128` and shows his byte code. + - `man.api.version` - Returns current app version + - `man.api.getConfig(path:String)` - Returns specified config value. First parameter is a namespace (optional) and config name. For example, to get maximum amount of organisms in current instance/world type: `man.api.getConfig('organisms.orgMaxOrgs')`. Example of organism related configs you may find [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/organisms/Config.js). Other configuration parameters are located in files with name `Config.js`. + - `man.api.setConfig(path:String, value:Any)` - Sets configuration value in real time. Opposite to `getConfig()`. +- charts namespace - `man.api.charts`. This namespace is related to statistics in charts. There are many parameters like average code size, organisms amount, amount of picked energy and so on. See details [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js) in charts property. You may show and hide different charts on a canvas, locate them and reset any time you need: + - `man.api.charts.on([[name:String = undefined[, show:Boolean = true]])` - shows chart(s) by name. List of all available names you may find [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). Example: `man.api.charts.on('energy')` - will show chart of average organism energy at the moment. Calling this method without parameters shows all available charts. Calling this method with only one string parameter shows specified chart. Calling this method with two parameters shows/hides specified chart depending on second Boolean parameter. Example: `man.api.charts.on()` - shows all charts. `man.api.charts.on('energy')` - shows energy chart only. `man.api.charts.on('energy', false)` - hides energy chart only. + - `man.api.charts.off(name:String = undefined)` - opposite to `on()`. Hides specified or all charts (without parameters) from the canvas. + - `man.api.charts.pos(String, String)` - Locates chart according to specified position. Available positions are: `full`, `top`, `down`, `left`, `right`, `topleft`, `downleft`, `topright`, `downright`. Example: `man.api.charts.pos('code', 'full')` - shows `code` trend chart on full screen. All available chart names are [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). + Note: to improve speed, type `man.api.visualize(false)` in Chrome's devtool console during application run ___ P.S. If you are a `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index c39461a..e18ef7b 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -20,6 +20,7 @@ const Plugins = require('./Plugins'); const EVENTS = require('./../share/Events').EVENTS; const EVENT_AMOUNT = require('./../share/Events').EVENT_AMOUNT; const Console = require('./../share/Console'); +const Helper = require('./../../../common/src/Helper'); const World = require('./../view/World').World; const WEVENTS = require('./../view/World').EVENTS; const Canvas = require('./../view/Canvas'); @@ -52,8 +53,9 @@ class Manager extends Observer { * It may be used in a user console by the Operator of construct. Plugins * may add their methods to this map also. */ - this.api = {version: () => '0.2.1'}; - hasView && (this.api.visualize = this._visualize.bind(this)); + this.api = {}; + Helper.setApi(this.api, 'version', '0.2.1.1', 'Shows construct version'); + hasView && Helper.setApi(this.api, 'visualize', this._visualize.bind(this), 'Turns on/off visualization in browser for current instance (world). Turning visualization off, increases application speed.'); /** * {Boolean} Means that this manager instance doesn't contain view(canvas). diff --git a/client/src/manager/plugins/Config.js b/client/src/manager/plugins/Config.js index de63ebb..9dafbe4 100644 --- a/client/src/manager/plugins/Config.js +++ b/client/src/manager/plugins/Config.js @@ -3,12 +3,13 @@ * * @author flatline */ -const Api = require('./../../share/Config').api; +const Api = require('./../../share/Config').api; +const Helper = require('./../../../../common/src/Helper'); class Config { constructor(manager) { - manager.api.setConfig = Api.set.bind(Api); - manager.api.getConfig = Api.get.bind(Api); + Helper.setApi(manager.api, 'setConfig', Api.set.bind(Api), 'Sets configuration value by name. Namespaces are also supported. Example: \'setConfig(\'organisms.orgMaxOrgs\', 500)\'. Opposite to getConfig()'); + Helper.setApi(manager.api, 'getConfig', Api.get.bind(Api), 'Returns specified config value. First parameter is a namespace (optional) and config name. For example, to get maximum amount of organisms in current instance/world type: man.api.getConfig(\'organisms.orgMaxOrgs\'). Example of organism related configs you may find here (https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). Other configuration parameters are located in files with name Config.js'); } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ecba4b1..3858d8d 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -52,7 +52,11 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 5000, + orgCloneMinAge: 8000, + /** + * {Number} Minimum energy for cloning + */ + orgCloneMinEnergy: 100000, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -63,12 +67,12 @@ const Config = { * do mutations according to orgRainMutationPercent config. If 0, then * mutations will be disabled. Should be less then ORGANISM_MAX_MUTATION_PERIOD */ - orgRainMutationPeriod: 10000, + orgRainMutationPeriod: 20000, /** * {Number} Percent of mutations from code size. 0 is a possible value if * we want to disable mutations. Should be less then 1.0 (1.0 === 100%) */ - orgRainMutationPercent: 0.01, + orgRainMutationPercent: 0.001, /** * {Boolean} Turn this flag on to give organism a possibility to choose his * own mutations period and percent. false - mean, that these values will be @@ -79,17 +83,17 @@ const Config = { * {Number} Amount of iterations, after which crossover will be applied * to random organisms. May be set to 0 to turn crossover off */ - orgCrossoverPeriod: 1000, + orgCrossoverPeriod: 20000, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 8000, + orgRandomOrgPeriod: 30000, /** * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 30000, + orgAlivePeriod: 25000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -141,7 +145,7 @@ const Config = { * organism without interruption by one VM. Set this value to value bigger * then codeMaxSize, then entire code of organism will be run */ - codeYieldPeriod: 4, + codeYieldPeriod: 10, /** * {Number} Amount of bits per one variable. It affects maximum value, * which this variable may contain. This value shouldn't be less then 2. @@ -156,7 +160,7 @@ const Config = { * {Number} Amount of bits, which stores maximum block length. Under block * length we mean maximum amount of lines in one block like if, for,... */ - codeBitsPerBlock: 8, + codeBitsPerBlock: 10, /** * {Number} Amount of iterations between calls to V8 event loop. See * Manager._initLoop(), Manager.run() methods for details. @@ -169,7 +173,7 @@ const Config = { * it's possible for organisms to go outside the limit by inventing new * effective mechanisms of energy obtaining. */ - codeMaxSize: 1000 + codeMaxSize: 300 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Mutator.js b/client/src/manager/plugins/organisms/Mutator.js index b7f7abe..f668c7e 100644 --- a/client/src/manager/plugins/organisms/Mutator.js +++ b/client/src/manager/plugins/organisms/Mutator.js @@ -107,7 +107,7 @@ class Mutator { } _onOrganism(org) { - if (org.iterations % org.mutationPeriod !== 0 || OConfig.orgRainMutationPeriod === 0 || OConfig.orgRainMutationPercent === 0.0 || org.mutationPeriod === 0 || org.energy < 1) {return} + if (org.iterations % org.mutationPeriod !== 0 || org.iterations < 1 || OConfig.orgRainMutationPeriod === 0 || OConfig.orgRainMutationPercent === 0.0 || org.mutationPeriod === 0 || org.energy < 1) {return} this._mutate(org); } diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 8d828b0..8ef9bda 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -241,7 +241,7 @@ class Organism extends Observer { } _updateClone() { - if (this._iterations > OConfig.orgCloneMinAge && this._energy > 0) {this.fire(CLONE, this)} + if (this._iterations > OConfig.orgCloneMinAge && this._energy > OConfig.orgCloneMinEnergy) {this.fire(CLONE, this)} } /** diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index ccbf40a..aba3608 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -17,7 +17,7 @@ const ORG_EVENTS = require('./../../../../src/manager/plugins/organisms/Organi const Mutator = require('./Mutator'); const Num = require('./../../../vm/Num'); -const RAND_OFFS = 3; +//const RAND_OFFS = 3; const POSID = Helper.posId; // TODO: inherit this class from Configurable @@ -56,7 +56,10 @@ class Organisms extends Configurable { createEmptyOrg(...args) {} constructor(manager) { - super(manager, {Config, cfg: OConfig}, {getAmount: ['_apiGetAmount', 'Shows amount of organisms within current Client(Manager)']}); + super(manager, {Config, cfg: OConfig}, { + getAmount : ['_apiGetAmount', 'Shows amount of organisms within current Client(Manager)'], + getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in a Queue'] + }); this.organisms = manager.organisms; this.randOrgItem = this.organisms.first; this.positions = manager.positions; @@ -150,7 +153,8 @@ class Organisms extends Configurable { * @return {Organism|null} */ randOrg() { - const offs = Helper.rand(RAND_OFFS) + 1; + //const offs = Helper.rand(RAND_OFFS) + 1; + const offs = Helper.rand(this.organisms.size) + 1; let item = this.randOrgItem; for (let i = 0; i < offs; i++) { @@ -215,13 +219,15 @@ class Organisms extends Configurable { } _crossover(org1, org2) { - this._clone(org1, true); - const orgs = this.organisms; - let child = orgs.last.val; + if (!this._clone(org1, true)) {return false} + let child = this.organisms.last.val; if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); + return true; } + + return false; } _createPopulation() { @@ -236,12 +242,35 @@ class Organisms extends Configurable { /** * API method, which will be added to Manager.api interface + * @api * @return {Number} Amount of organisms within current Manager */ _apiGetAmount() { return this.parent.organisms.size; } + /** + * Return organism instance by id or it's index in a Queue + * @param {Number|String} index Index or id + * @return {Organism} Organism instance or null + * @api + */ + _apiGetOrganism(index) { + if (Helper.isNumeric(index)) { + return this.organisms.get(index); + } + + let item = this.organisms.first; + let org; + + while (org = item && item.val) { + if (org.id === index) {return org} + item = item.next; + } + + return null; + } + _onDestroyOrg(org) { if (this.randOrgItem === org.item) { if ((this.randOrgItem = org.item.next) === null) { diff --git a/client/src/manager/plugins/organisms/dos/Code2String.js b/client/src/manager/plugins/organisms/dos/Code2String.js index 7cc2bce..139b0f4 100644 --- a/client/src/manager/plugins/organisms/dos/Code2String.js +++ b/client/src/manager/plugins/organisms/dos/Code2String.js @@ -7,6 +7,7 @@ */ const Num = require('./../../../../vm/Num'); const OConfig = require('./../Config'); +const Helper = require('./../../../../../../common/src/Helper'); /** * {Function} Just a shortcuts */ @@ -69,7 +70,7 @@ class Code2String { // // API of the Manager for accessing outside. (e.g. from Console) // - manager.api.formatCode = (code) => this.format(code); + Helper.setApi(manager.api, 'formatCode', (code) => this.format(code), 'Converts byte code array into human readable JavaScript based code. This function is low level. For using it you have to get organism\'s virtual machine reference and then use it\'s code property. For example: man.api.formatCode(man.api.organisms.getOrganism(\'128\').vm.code). This example will find organism with id \'128\' and shows his byte code.'); } destroy() { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index f7f36b6..3e1c007 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -56,8 +56,8 @@ class OperatorsDos extends Operators { constructor(offs, vars, obs) { super(offs, vars, obs); /** - * {Object} These operator handlers should return string, which - * will be added to the final string script for evaluation. + * {Object} These operator handlers should return next script line + * number VM should step to */ this._OPERATORS_CB = [ this.onVar.bind(this), diff --git a/client/src/manager/plugins/organisms/dos/OrganismSpec.js b/client/src/manager/plugins/organisms/dos/OrganismSpec.js index 636e920..c116ac0 100644 --- a/client/src/manager/plugins/organisms/dos/OrganismSpec.js +++ b/client/src/manager/plugins/organisms/dos/OrganismSpec.js @@ -226,10 +226,12 @@ describe("client/src/organism/OrganismDos", () => { it('Organism should fire CLONE event if enough age', () => { let flag = false; const minAge = OConfig.orgCloneMinAge; + const minEnergy = OConfig.orgCloneMinEnergy; const yieldPeriod = OConfig.codeYieldPeriod; const weights = OConfig.orgOperatorWeights.slice(); const newWeights = [.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1]; OConfig.orgCloneMinAge = 1; + OConfig.orgCloneMinEnergy = 1; OConfig.codeYieldPeriod = 1; OConfig.orgOperatorWeights.splice(0, OConfig.orgOperatorWeights.length, ...newWeights); const org1 = new OrganismDos('0', 1, 2, null); @@ -246,7 +248,8 @@ describe("client/src/organism/OrganismDos", () => { expect(flag).toBe(true); org1.destroy(); - OConfig.orgCloneMinAge = minAge; + OConfig.orgCloneMinAge = minAge; + OConfig.orgCloneMinEnergy = minEnergy; OConfig.codeYieldPeriod = yieldPeriod; OConfig.orgOperatorWeights.splice(0, OConfig.orgOperatorWeights.length, ...weights); }) diff --git a/client/src/manager/plugins/status/charts/Charts.js b/client/src/manager/plugins/status/charts/Charts.js index b02b51d..73bcab6 100644 --- a/client/src/manager/plugins/status/charts/Charts.js +++ b/client/src/manager/plugins/status/charts/Charts.js @@ -18,7 +18,7 @@ const API = { pos9 : ['_pos9', 'Sets chart position in 3x3 grid' ], pos16 : ['_pos16', 'Sets chart position in 4x4 grid' ], active : ['_active', 'Activates/Deactivates chart' ], - on : ['_on', 'Activates/Deactivates chart' ], + on : ['_on', 'Activates/Deactivates chart by name' ], off : ['_off', 'Deactivates chart' ], reset : ['_reset', 'Resets chart data' ], preset : ['_preset', 'Positioning charts according to preset'] diff --git a/common/src/Configurable.js b/common/src/Configurable.js index dd7665c..dd516c9 100644 --- a/common/src/Configurable.js +++ b/common/src/Configurable.js @@ -97,8 +97,7 @@ class Configurable { const isStr = typeof key === 'string'; let desc = isStr && 'No description' || key[1]; - cfg[c] = (isStr && this[key] || this[key[0]]).bind(this); - cfg[c].desc = desc; + Helper.setApi(cfg, c, (isStr && this[key] || this[key[0]]).bind(this), desc); } } diff --git a/common/src/Helper.js b/common/src/Helper.js index 71eeef8..21e8d2d 100644 --- a/common/src/Helper.js +++ b/common/src/Helper.js @@ -63,6 +63,18 @@ class Helper { return el; } + /** + * Sets API function, which may be used by users in Chrome console (in DevTools) + * @param {Object} obj Destination object + * @param {String} name Name of function/property + * @param {Function|*} fn Function or value (if property) + * @param {String} desc Description + */ + static setApi(obj, name, fn, desc = '') { + obj[name] = fn; + Helper.isFunc(fn) && (obj[name].desc = desc); + } + /** * Sets first letter to lower case * @param {String} s From 71ee0a0b531c739a37733ba63a880f402bfb3fa6 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 22 Mar 2018 21:34:14 +0200 Subject: [PATCH 06/21] added console API commends to the README #118 fixed small issue with extra mutations on start added min energy for ability to clone added description to API methods changed version to 0.2.1.1 --- client/src/manager/Manager.js | 5 ++ client/src/manager/plugins/Energy.js | 4 +- client/src/manager/plugins/Stones.js | 62 +++++++++++++++++++ .../manager/plugins/organisms/Organisms.js | 2 - .../plugins/organisms/dos/Organisms.js | 15 ++++- client/src/share/Config.js | 17 ++++- client/src/view/World.js | 3 +- 7 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 client/src/manager/plugins/Stones.js diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index e18ef7b..67acfb0 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -48,6 +48,10 @@ class Manager extends Observer { * and track all world objects */ this.positions = {}; + /** + * {Object} Map of world objects like stones, water,... + */ + this.objects = {}; /** * {Object} This field is used as a container for public API of the Manager. * It may be used in a user console by the Operator of construct. Plugins @@ -193,6 +197,7 @@ class Manager extends Observer { this._world = null; this.api = null; this._codeRuns = 0; + this.objects = null; this.positions = null; this.organisms.destroy(); this.organisms = null; diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index 30c7f81..c4dc222 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -39,7 +39,7 @@ class Energy { _addEnergyBlock() { const width = Config.worldWidth; const height = Config.worldHeight; - const color = Helper.rand(Organism.getMaxColors()); + const color = Organism.getColor(Config.worldEnergyColorIndex); let block = Config.worldEnergyBlockSize; const world = this._manager.world; let x = Helper.rand(width); @@ -49,7 +49,7 @@ class Energy { x = x + Helper.rand(3) - 1; y = y + Helper.rand(3) - 1; if (x < 0 || x >= width || y < 0 || y >= height) {return} - if (world.isFree(x, y)) {world.setDot(x, y, Organism.getColor(color))} + if (world.isFree(x, y)) {world.setDot(x, y, color)} } } diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js new file mode 100644 index 0000000..f2dfae4 --- /dev/null +++ b/client/src/manager/plugins/Stones.js @@ -0,0 +1,62 @@ +/** + * Manager's plugin, which add stones to the world + * + * @author flatline + */ +const Helper = require('./../../../../common/src/Helper'); +const Config = require('./../../share/Config').Config; +const Organism = require('./../../manager/plugins/organisms/Organism').Organism; +const OBJECT_TYPES = require('./../../view/World').OBJECT_TYPES; + +const STONE_BLOCK_SIZE = 300; +const POSID = Helper.posId; +// +// We have to add stone type to global types storage +// +OBJECT_TYPES.TYPE_STONE = Object.keys(OBJECT_TYPES).length; + +class Stones { + constructor(manager) { + this._manager = manager; + this._onLoopCb = this._onLoop.bind(this); + + Helper.override(manager, 'onLoop', this._onLoopCb); + } + + destroy() { + Helper.unoverride(this._manager, 'onLoop', this._onLoopCb); + this._manager = null; + this._onLoopCb = null; + } + + _onLoop(counter) { + if (counter > 1 || Config.worldStonesAmount === 0) {return} + + const stones = Config.worldStonesAmount; + for (let i = 0; i < stones; i++) { + this._addStoneBlock(); + } + } + + _addStoneBlock() { + const width = Config.worldWidth; + const height = Config.worldHeight; + const color = Organism.getColor(Config.worldStoneColorIndex); + const man = this._manager; + const world = man.world; + const stone = OBJECT_TYPES.TYPE_STONE; + let x = Helper.rand(width); + let y = Helper.rand(height); + + for (let i = 0; i < STONE_BLOCK_SIZE; i++) { + x = x + Helper.rand(3) - 1; + y = y + Helper.rand(3) - 1; + if (x < 0 || x >= width || y < 0 || y >= height) {return} + if (world.isFree(x, y)) { + world.setDot(x, y, color) && (man.objects[POSID(x, y)] = stone); + } + } + } +} + +module.exports = Stones; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index aba3608..597bc08 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -17,7 +17,6 @@ const ORG_EVENTS = require('./../../../../src/manager/plugins/organisms/Organi const Mutator = require('./Mutator'); const Num = require('./../../../vm/Num'); -//const RAND_OFFS = 3; const POSID = Helper.posId; // TODO: inherit this class from Configurable @@ -153,7 +152,6 @@ class Organisms extends Configurable { * @return {Organism|null} */ randOrg() { - //const offs = Helper.rand(RAND_OFFS) + 1; const offs = Helper.rand(this.organisms.size) + 1; let item = this.randOrgItem; diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 26c0df1..7e84c09 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -23,6 +23,7 @@ const DIR = require('./../../../../../../common/src/Directions').DI const EMPTY = 0; const ENERGY = 1; const ORGANISM = 2; +const OBJECT = 3; /** * {Function} Is created to speed up this function call. constants are run * much faster, then Helper.normalize() @@ -136,6 +137,13 @@ class Organisms extends BaseOrganisms { [x, y] = NORMALIZE_NO_DIR(x, y); const posId = POSID(x, y); // + // World object found. We can't eat objects + // + if (typeof(this.parent.objects[posId]) !== 'undefined') { + ret.ret = 0; + return; + } + // // Energy found // if (typeof(positions[posId]) === 'undefined') { @@ -211,9 +219,12 @@ class Organisms extends BaseOrganisms { } _onCheckAt(x, y, ret) { - [x, y] = NORMALIZE_NO_DIR(x, y); + const posId = POSID(x, y); + [x, y] = NORMALIZE_NO_DIR(x, y); - if (typeof(this.parent.positions[POSID(x, y)]) === 'undefined') { + if (typeof(this.parent.objects[posId]) !== 'undefined') { + ret.ret = OBJECT + this.parent.objects[posId]; + } else if (typeof(this.parent.positions[posId]) === 'undefined') { ret.ret = this.parent.world.getDot(x, y) > 0 ? ENERGY : EMPTY; } else { ret.ret = ORGANISM; diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 63f07c2..41e6fbd 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -39,6 +39,7 @@ ClientConfig.init({ 'Config', 'client/Client', 'Energy', + 'Stones', 'status/console/Console', IS_NODE_JS ? '' : 'status/charts/Charts', 'ips/Ips', @@ -72,9 +73,14 @@ ClientConfig.init({ */ worldEnergyCheckPeriod: 5000, /** - * {Number} size of one clever energy block in dots. + * {Number} size of one clever energy block in dots */ worldEnergyBlockSize: 200, + /** + * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS + * constant for details + */ + worldEnergyColorIndex: 0, /** * {Number} Percent from all energy in a world until clever energy will be added. * After this value clever energy will be stopped to add until it's amount will @@ -88,6 +94,15 @@ ClientConfig.init({ * world again). */ worldEnergyMinPercent: .0001, + /** + * {Number} Amount of random stones in a world + */ + worldStonesAmount: 600, + /** + * {Number} Color index for stones in a world. See Organism.MAX_COLORS + * constant for details + */ + worldStoneColorIndex: 1800, /** * {Number} Zoom speed 0..1 */ diff --git a/client/src/view/World.js b/client/src/view/World.js index 0c7e880..6b8d43a 100644 --- a/client/src/view/World.js +++ b/client/src/view/World.js @@ -30,6 +30,7 @@ const WEVENTS = { * The same like this.getDot(x, y) === 0 */ const FREE_DOT_ATTEMPTS = 100; +const OBJECT_TYPES = {}; class World extends Observer { constructor (width, height) { @@ -118,4 +119,4 @@ class World extends Observer { } } -module.exports = {World, EVENTS: WEVENTS}; \ No newline at end of file +module.exports = {World, EVENTS: WEVENTS, OBJECT_TYPES}; \ No newline at end of file From b766b0b583b1f9e52868fab7f838b59df3cdc2d6 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 23 Mar 2018 22:23:24 +0200 Subject: [PATCH 07/21] added oenergy chart removed unused console statistics parameters --- .../src/manager/plugins/organisms/Config.js | 24 +++++++++---------- .../manager/plugins/organisms/Organisms.js | 5 ++-- .../plugins/organisms/dos/Organisms.js | 12 +++++----- client/src/manager/plugins/status/Status.js | 19 ++++++++++----- .../manager/plugins/status/charts/Charts.js | 9 +++---- .../manager/plugins/status/charts/Config.js | 2 +- .../manager/plugins/status/console/Console.js | 5 ++-- client/src/share/Config.js | 10 ++++---- 8 files changed, 47 insertions(+), 39 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 3858d8d..1347f22 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,12 +15,12 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .0001, .0001, .000001, .000000001, .00001, // var, const, if, loop, operator, - .00001, .02, .02, .02, .02, // lookAt, eatLeft, eatRight, eatUp, eatDown, - .2, .2, .2, .2, // stepLeft, stepRight, stepUp, stepDown, - .0001, .0001, // fromMem, toMem, - .00001, .00001, // myX, myY, - .0001, .0001, .0001, .0001 // checkLeft, checkRight, checkUp, checkDown + .001, .001, .00001, .00000001, .0001, // var, const, if, loop, operator, + .0001, .2, .2, .2, .2, // lookAt, eatLeft, eatRight, eatUp, eatDown, + 2, 2, 2, 2, // stepLeft, stepRight, stepUp, stepDown, + .001, .001, // fromMem, toMem, + .0001, .0001, // myX, myY, + .001, .001, .001, .001 // checkLeft, checkRight, checkUp, checkDown ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -67,7 +67,7 @@ const Config = { * do mutations according to orgRainMutationPercent config. If 0, then * mutations will be disabled. Should be less then ORGANISM_MAX_MUTATION_PERIOD */ - orgRainMutationPeriod: 20000, + orgRainMutationPeriod: 9500, /** * {Number} Percent of mutations from code size. 0 is a possible value if * we want to disable mutations. Should be less then 1.0 (1.0 === 100%) @@ -83,17 +83,17 @@ const Config = { * {Number} Amount of iterations, after which crossover will be applied * to random organisms. May be set to 0 to turn crossover off */ - orgCrossoverPeriod: 20000, + orgCrossoverPeriod: 10000, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 30000, + orgRandomOrgPeriod: 20000, /** * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 25000, + orgAlivePeriod: 10000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -119,11 +119,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 500, + orgMaxOrgs: 400, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 500, + orgStartAmount: 400, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 597bc08..047a1bf 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -60,6 +60,7 @@ class Organisms extends Configurable { getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in a Queue'] }); this.organisms = manager.organisms; + this.objects = manager.objects; this.randOrgItem = this.organisms.first; this.positions = manager.positions; this.world = manager.world; @@ -171,8 +172,8 @@ class Organisms extends Configurable { * @param {Number} stamp Time stamp of current iteration */ _onIteration(counter, stamp) { - let item = this.organisms.first; - let org; + let item = this.organisms.first; + let org; while (org = item && item.val) { org.run(); diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 7e84c09..bf7a71b 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -128,7 +128,6 @@ class Organisms extends BaseOrganisms { } _onEat(org, x, y, ret) { - const positions = this.positions; // // Amount of eat energy depends on organism size. Small organisms // eat less, big - more @@ -139,14 +138,14 @@ class Organisms extends BaseOrganisms { // // World object found. We can't eat objects // - if (typeof(this.parent.objects[posId]) !== 'undefined') { + if (typeof(this.objects[posId]) !== 'undefined') { ret.ret = 0; return; } // // Energy found // - if (typeof(positions[posId]) === 'undefined') { + if (typeof(this.positions[posId]) === 'undefined') { if (eat >= 0) { ret.ret = this.world.grabDot(x, y, eat); this.parent.fire(EVENTS.EAT_ENERGY, ret.ret); @@ -159,7 +158,7 @@ class Organisms extends BaseOrganisms { // Organism found // } else { - const victimOrg = positions[posId]; + const victimOrg = this.positions[posId]; ret.ret = eat < 0 ? 0 : (eat > victimOrg.energy ? victimOrg.energy : eat); if (victimOrg.energy <= ret.ret) { this.parent.fire(EVENTS.KILL_EAT, victimOrg); @@ -171,6 +170,7 @@ class Organisms extends BaseOrganisms { // victimOrg.destroy(); } else { + this.parent.fire(EVENTS.EAT_ORG, victimOrg, ret.ret); victimOrg.energy -= ret.ret; } } @@ -222,8 +222,8 @@ class Organisms extends BaseOrganisms { const posId = POSID(x, y); [x, y] = NORMALIZE_NO_DIR(x, y); - if (typeof(this.parent.objects[posId]) !== 'undefined') { - ret.ret = OBJECT + this.parent.objects[posId]; + if (typeof(this.objects[posId]) !== 'undefined') { + ret.ret = OBJECT + this.objects[posId]; } else if (typeof(this.parent.positions[posId]) === 'undefined') { ret.ret = this.parent.world.getDot(x, y) > 0 ? ENERGY : EMPTY; } else { diff --git a/client/src/manager/plugins/status/Status.js b/client/src/manager/plugins/status/Status.js index fae69d8..bbb013c 100644 --- a/client/src/manager/plugins/status/Status.js +++ b/client/src/manager/plugins/status/Status.js @@ -19,7 +19,6 @@ const Helper = require('./../../../../../common/src/Helper'); const EVENTS = require('./../../../share/Events').EVENTS; const Configurable = require('./../../../../../common/src/Configurable'); const Config = require('./../../../share/Config').Config; -const OConfig = require('./../../../manager/plugins/organisms/Config'); class Status extends Configurable { static _toFixed(val, fixed) { @@ -38,7 +37,7 @@ class Status extends Configurable { super(manager, {Config, cfg: statCfg}, apiCfg); this._status = { - lps :0, ips :0, orgs :0, energy :0, penergy :0, eenergy:0, wenergy:0, wenergyup:true, changes:0, fit:0, age:0, code:0, + lps :0, ips :0, orgs :0, energy :0, oenergy :0, eenergy:0, wenergy:0, wenergyup:true, changes:0, fit:0, age:0, code:0, kill:0, killenergy:0, killage:0, killeat:0, killover:0, killout:0, killin :0, killclone:0 }; this._stamp = 0; @@ -64,6 +63,7 @@ class Status extends Configurable { this._onLoopCb = this._onLoop.bind(this); this._onIpsCb = this._onIps.bind(this); this._onEatEnergyCb = this._onEatEnergy.bind(this); + this._onEatOrgCb = this._onEatOrg.bind(this); this._onPutEnergyCb = this._onPutEnergy.bind(this); this._onKillOrgCb = this._onKillOrg.bind(this); this._onKillEnergyCb = this._onKillHandlerOrg.bind(this, 1); @@ -80,6 +80,7 @@ class Status extends Configurable { Helper.override(manager, 'onLoop', this._onLoopCb); manager.on(EVENTS.IPS, this._onIpsCb); manager.on(EVENTS.EAT_ENERGY, this._onEatEnergyCb); + manager.on(EVENTS.EAT_ORG, this._onEatOrgCb); manager.on(EVENTS.PUT_ENERGY, this._onPutEnergyCb); manager.on(EVENTS.KILL, this._onKillOrgCb); manager.on(EVENTS.KILL_TOUR, this._onKillTourCb); @@ -111,6 +112,7 @@ class Status extends Configurable { man.off(EVENTS.KILL_TOUR, this._onKillTourCb); man.off(EVENTS.KILL, this._onKillOrgCb); man.off(EVENTS.PUT_ENERGY, this._onPutEnergyCb); + man.off(EVENTS.EAT_ORG, this._onEatOrgCb); man.off(EVENTS.EAT_ENERGY, this._onEatEnergyCb); man.off(EVENTS.IPS, this._onIpsCb); Helper.unoverride(man, 'onLoop', this._onLoopCb); @@ -120,6 +122,7 @@ class Status extends Configurable { this._onKillOrgCb = null; this._onKillTourCb = null; this._onPutEnergyCb = null; + this._onEatOrgCb = null; this._onEatEnergyCb = null; this._onKillCloneCb = null; this._onKillInCb = null; @@ -155,7 +158,6 @@ class Status extends Configurable { item = item.next; } - this._pickEnergy = ((energy - startEnergy) / iterations) / size; this._energy = energy / size; this._changes = changes / size; this._fitness = fitness / size; @@ -174,11 +176,11 @@ class Status extends Configurable { this._onBeforeLoop(orgs); - status.ips = fix(this._ips / this._ipsTimes * OConfig.codeYieldPeriod, 2); + status.ips = fix(this._ips / this._ipsTimes, 2); status.lps = fix((this.parent.codeRuns - this._codeRuns) / ((stamp - this._stamp) / 1000), 0); status.orgs = orgAmount; status.energy = fix(this._energy, 2); - status.penergy = fix(this._pickEnergy * 1000, 2); + status.oenergy = fix(this._pickEnergy / orgAmount, 2); status.eenergy = fix(this._eatEnergy / orgAmount, 2); status.puenergy = fix(this._putEnergy / orgAmount, 2); status.changes = +(this._changes).toFixed(1); @@ -230,6 +232,10 @@ class Status extends Configurable { this._eatEnergy += eat; } + _onEatOrg(org, eat) { + this._pickEnergy += eat; + } + /** * Calculates putting of energy by organisms to the world * @param {Number} put Amount of put energy @@ -245,8 +251,9 @@ class Status extends Configurable { this._kill[0] ++; } - _onKillHandlerOrg(index) { + _onKillHandlerOrg(index, org) { this._kill[index]++; + index === 4 && (this._pickEnergy += org.energy); } _onWorldEnergy(percent) { diff --git a/client/src/manager/plugins/status/charts/Charts.js b/client/src/manager/plugins/status/charts/Charts.js index 73bcab6..ccccb0f 100644 --- a/client/src/manager/plugins/status/charts/Charts.js +++ b/client/src/manager/plugins/status/charts/Charts.js @@ -47,7 +47,7 @@ const PRESETS = { orgs : '0-1|16', energy : '0-2|16', eenergy : '0-3|16', - penergy : '1-0|16', + oenergy : '1-0|16', changes : '1-1|16', age : '1-2|16', code : '1-3|16', @@ -71,7 +71,7 @@ const PRESETS = { lps : 'topleft', energy : 'downleft', eenergy : 'topright', - penergy : 'downright' + oenergy : 'downright' } }; @@ -108,7 +108,7 @@ class Charts extends Status { ips : new Chart('IPS - Iterations Per Second', Config.charts.ips), orgs : new Chart('Amount of organisms', Config.charts.orgs), energy : new Chart('Average organism energy', Config.charts.energy), - penergy : new Chart('Average organism\'s picked energy (all)', Config.charts.penergy), + oenergy : new Chart('Average organism\'s eat energy from other organisms', Config.charts.oenergy), eenergy : new Chart('Average organism\'s picked energy (energy only)', Config.charts.eenergy), puenergy : new Chart('Average organism\'s put energy to the world', Config.charts.puenergy), changes : new Chart('Average organism\'s changes (Mutations)', Config.charts.changes), @@ -165,6 +165,7 @@ class Charts extends Status { const conns = `${active[0] ? '^' : ''}${active[1] ? '>' : ''}${active[2] ? 'v' : ''}${active[3] ? '<' : ''}`; const ips = `ips:${status.ips}`; const enrg = `enrg:${status.eenergy}`; + const onrg = `onrg:${status.oenergy}`; const wnrg = `wnrg:${status.wenergy}`; const wnrgup = status.wenergyup ? '\u2191' : '\u2193'; const code = `cod:${status.code}`; @@ -173,7 +174,7 @@ class Charts extends Status { const kilo = `kilo:${status.killeat}`; const orgs = `org:${status.orgs}`; - this._headerEl.textContent = `${man.clientId ? 'id:' + man.clientId : ''} ${conns === '' ? '' : 'con:' + conns} ${ips} ${wnrg} ${wnrgup} ${enrg} ${code} ${age} ${kill} ${kilo} ${orgs}`; + this._headerEl.textContent = `${man.clientId ? 'id:' + man.clientId : ''} ${conns === '' ? '' : 'con:' + conns} ${ips} ${wnrg} ${wnrgup} ${enrg} ${onrg} ${code} ${age} ${kill} ${kilo} ${orgs}`; } /** diff --git a/client/src/manager/plugins/status/charts/Config.js b/client/src/manager/plugins/status/charts/Config.js index 3facf59..00871a7 100644 --- a/client/src/manager/plugins/status/charts/Config.js +++ b/client/src/manager/plugins/status/charts/Config.js @@ -25,7 +25,7 @@ const Config = { killout : {pos: 'topright', active: false, transparent: 0.8}, energy : {pos: 'downright', active: false, transparent: 0.8}, orgs : {pos: '0-0|16', active: false, transparent: 0.8}, - penergy : {pos: '0-1|16', active: false, transparent: 0.8}, + oenergy : {pos: '0-1|16', active: false, transparent: 0.8}, eenergy : {pos: '0-2|16', active: false, transparent: 0.8}, puenergy : {pos: '0-3|16', active: false, transparent: 0.8}, fit : {pos: '1-0|16', active: false, transparent: 0.8}, diff --git a/client/src/manager/plugins/status/console/Console.js b/client/src/manager/plugins/status/console/Console.js index 37aef97..80865fc 100644 --- a/client/src/manager/plugins/status/console/Console.js +++ b/client/src/manager/plugins/status/console/Console.js @@ -48,17 +48,16 @@ class Console extends Status { const slps = format(status.lps, 'lps', 14); const sorgs = format(orgs, 'org', 10); const senergy = format(status.energy, 'nrg', 19); - const spenergy = format(status.penergy, 'pnrg', 15); + const spenergy = format(status.oenergy, 'onrg', 15); const seenergy = format(status.eenergy, 'enrg', 16); const wenergy = format(status.wenergy + (status.wenergyup ? '\u2191' : '\u2193'), 'wnrg', 14); const skill = format(status.kill, 'kil', 12); const schanges = format(status.changes, 'che', 12); - const sfit = format(status.fit, 'fit', 13); const sage = format(status.age, 'age', 11); const scode = format(status.code, 'cod', 12); // TODO: under Node.js should use Server/Console.xxx() - console.log(`%c${conns}${sips}${slps}${sorgs}%c${senergy}${spenergy}${seenergy}${wenergy}${skill}${schanges}${sfit}${sage}${scode}`, GREEN, RED); + console.log(`%c${conns}${sips}${slps}${sorgs}%c${senergy}${spenergy}${seenergy}${wenergy}${skill}${schanges}${sage}${scode}`, GREEN, RED); } } diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 41e6fbd..9434af8 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 2, + worldWidth: 1920, /** * {Number} World height */ - worldHeight: 1080 / 2, + worldHeight: 1080, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 @@ -66,7 +66,7 @@ ClientConfig.init({ * coordinate (height). It actual only for one instance mode (no distributed * calculations). */ - worldCyclical: false, + worldCyclical: true, /** * {Number} An amount of iteration, after which we have to check world energy * percent. May be 0 if you want to disable energy generation @@ -93,11 +93,11 @@ ClientConfig.init({ * all energy in a world after which clever energy will turn on (be added to the * world again). */ - worldEnergyMinPercent: .0001, + worldEnergyMinPercent: .0002, /** * {Number} Amount of random stones in a world */ - worldStonesAmount: 600, + worldStonesAmount: 4000, /** * {Number} Color index for stones in a world. See Organism.MAX_COLORS * constant for details From 31a844d0ef68e2f60512588ba1d905edc6983f19 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 23 Mar 2018 23:04:42 +0200 Subject: [PATCH 08/21] added commands #118 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73e33a6..8c5723b 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,10 @@ As an administrator, you may affect the system by command line API. For instance - charts namespace - `man.api.charts`. This namespace is related to statistics in charts. There are many parameters like average code size, organisms amount, amount of picked energy and so on. See details [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js) in charts property. You may show and hide different charts on a canvas, locate them and reset any time you need: - `man.api.charts.on([[name:String = undefined[, show:Boolean = true]])` - shows chart(s) by name. List of all available names you may find [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). Example: `man.api.charts.on('energy')` - will show chart of average organism energy at the moment. Calling this method without parameters shows all available charts. Calling this method with only one string parameter shows specified chart. Calling this method with two parameters shows/hides specified chart depending on second Boolean parameter. Example: `man.api.charts.on()` - shows all charts. `man.api.charts.on('energy')` - shows energy chart only. `man.api.charts.on('energy', false)` - hides energy chart only. - `man.api.charts.off(name:String = undefined)` - opposite to `on()`. Hides specified or all charts (without parameters) from the canvas. - - `man.api.charts.pos(String, String)` - Locates chart according to specified position. Available positions are: `full`, `top`, `down`, `left`, `right`, `topleft`, `downleft`, `topright`, `downright`. Example: `man.api.charts.pos('code', 'full')` - shows `code` trend chart on full screen. All available chart names are [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). - + - `man.api.charts.pos(name:String, pos:String)` - Locates chart according to specified position. Available positions are: `full`, `top`, `down`, `left`, `right`, `topleft`, `downleft`, `topright`, `downright`. Example: `man.api.charts.pos('code', 'full')` - shows `code` trend chart on full screen. All available chart names are [here](https://github.com/tmptrash/construct/blob/master/client/src/manager/plugins/status/charts/Config.js). + - `man.api.charts.pos9(name:String, x:Number, y:Number)` - The same like `pos()`, but with chart coordinates in 3x3 grid. For example: `man.api.charts.pos9('energy', 0, 2)` - will positioning energy chart at the location `x:0, y:2`. + - `man.api.charts.pos16(name:String, x:Number, y:Number)` - The same like `pos9()`, but for grid 4x4. + - `man.api.charts.transparent(name:String, val:Number)` - Sets chart transparency. `val` should be between `0..1`. `val` parameter is optional. In this case all charts will have same transparency. Note: to improve speed, type `man.api.visualize(false)` in Chrome's devtool console during application run ___ P.S. If you are a `ES6 js developer` | `Canvas 2D developer` | `Node.js developer` | you just a - join us! From 9dbc2e247e19e5e4483d59f1bd722ad58e6bca48 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 24 Mar 2018 14:24:27 +0200 Subject: [PATCH 09/21] small optimizations --- .../src/manager/plugins/organisms/Config.js | 4 ++-- .../src/manager/plugins/organisms/Organism.js | 22 ++++++++++--------- .../plugins/organisms/dos/Organisms.js | 4 ++-- client/src/share/Config.js | 6 ++--- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 1347f22..ad7543b 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -119,11 +119,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 400, + orgMaxOrgs: 20000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 400, + orgStartAmount: 10000, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 8ef9bda..3d86e85 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -25,7 +25,8 @@ const ORG_EVENTS = { ITERATION }; -const MAX_COLORS = 4000; +const MAX_COLORS = 4000; +const UPDATE_COLOR_PERIOD = 50; class Organism extends Observer { /** @@ -81,14 +82,15 @@ class Organism extends Observer { if (parent === null) {this._create()} else {this._clone(parent)} - this._id = id; - this._x = x; - this._y = y; - this._iterations = -1; - this._changes = 0; - this._item = item; - this._maxEnergy = 0; - this._fnId = 0; + this._id = id; + this._x = x; + this._y = y; + this._iterations = -1; + this._changes = 0; + this._item = item; + this._maxEnergy = 0; + this._energyChanges = 0; + this._fnId = 0; } get id() {return this._id} @@ -110,7 +112,7 @@ class Organism extends Observer { set y(newY) {this._y = newY} set mutationPeriod(m) {this._mutationPeriod = m} set mutationPercent(p) {this._mutationPercent = p} - set energy(e) {if (this.vm !== null) { this._energy = e; this._updateColor()}} + set energy(e) {if (this.vm !== null) { this._energy = e; ++this._energyChanges % UPDATE_COLOR_PERIOD === 0 && this._updateColor()}} set startEnergy(e) {this._startEnergy = e} set changes(c) {this._changes = c} set maxEnergy(e) {this._maxEnergy = e} diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index bf7a71b..f5842b3 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -224,8 +224,8 @@ class Organisms extends BaseOrganisms { if (typeof(this.objects[posId]) !== 'undefined') { ret.ret = OBJECT + this.objects[posId]; - } else if (typeof(this.parent.positions[posId]) === 'undefined') { - ret.ret = this.parent.world.getDot(x, y) > 0 ? ENERGY : EMPTY; + } else if (typeof(this.positions[posId]) === 'undefined') { + ret.ret = this.world.getDot(x, y) > 0 ? ENERGY : EMPTY; } else { ret.ret = ORGANISM; } diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 9434af8..5f8dbdf 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920, + worldWidth: 1920 / 2, /** * {Number} World height */ - worldHeight: 1080, + worldHeight: 1080 / 2, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 @@ -97,7 +97,7 @@ ClientConfig.init({ /** * {Number} Amount of random stones in a world */ - worldStonesAmount: 4000, + worldStonesAmount: 1500, /** * {Number} Color index for stones in a world. See Organism.MAX_COLORS * constant for details From 10eaf40e967b676cc137d278f3bfa159b29e9a46 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 27 Mar 2018 18:00:22 +0300 Subject: [PATCH 10/21] speed optimizations of DOS VM added orgKilOnClone config fixed an issue with stuck of evolution fixed an issue with incorrect energy calculation stones amount is now in percents (config) --- client/src/manager/plugins/Energy.js | 4 ++- client/src/manager/plugins/Stones.js | 20 +++++++---- .../src/manager/plugins/organisms/Config.js | 33 +++++++++++-------- .../src/manager/plugins/organisms/Mutator.js | 4 +-- .../manager/plugins/organisms/Organisms.js | 6 ++-- .../plugins/organisms/dos/Operators.js | 24 ++++++++++---- .../plugins/organisms/dos/Organisms.js | 32 +++++++++--------- client/src/share/Config.js | 11 ++++--- 8 files changed, 81 insertions(+), 53 deletions(-) diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index c4dc222..6ef17db 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -59,10 +59,12 @@ class Energy { const width = Config.worldWidth; const height = Config.worldHeight; const poses = this._manager.positions; + const objs = this._manager.objects; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { - if (typeof poses[POSID(x, y)] === 'undefined') {energy += world.getDot(x, y)} + const posId = POSID(x, y); + if (typeof poses[posId] === 'undefined' && typeof objs[posId] === 'undefined') {energy += world.getDot(x, y)} } } diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js index f2dfae4..7697fe4 100644 --- a/client/src/manager/plugins/Stones.js +++ b/client/src/manager/plugins/Stones.js @@ -30,15 +30,16 @@ class Stones { } _onLoop(counter) { - if (counter > 1 || Config.worldStonesAmount === 0) {return} + if (counter > 1 || Config.worldStonesPercent === .0) {return} - const stones = Config.worldStonesAmount; - for (let i = 0; i < stones; i++) { - this._addStoneBlock(); + const stones = Config.worldStonesPercent * Config.worldWidth * Config.worldHeight; + let amount = 0; + while (amount < stones) { + amount = this._addStoneBlock(amount, stones); } } - _addStoneBlock() { + _addStoneBlock(amount, stones) { const width = Config.worldWidth; const height = Config.worldHeight; const color = Organism.getColor(Config.worldStoneColorIndex); @@ -51,11 +52,16 @@ class Stones { for (let i = 0; i < STONE_BLOCK_SIZE; i++) { x = x + Helper.rand(3) - 1; y = y + Helper.rand(3) - 1; - if (x < 0 || x >= width || y < 0 || y >= height) {return} + if (x < 0 || x >= width || y < 0 || y >= height) {return amount} if (world.isFree(x, y)) { - world.setDot(x, y, color) && (man.objects[POSID(x, y)] = stone); + if (world.setDot(x, y, color)) { + man.objects[POSID(x, y)] = stone; + if (++amount >= stones) {return amount} + } } } + + return amount; } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ad7543b..148c4cc 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -47,12 +47,19 @@ const Config = { * {Boolean} If turned on, then organism will be responsible for changing * mutations probabilities. Otherwise these probabilities will be constant */ - orgMutationPerOrg: false, + orgMutationProbsPerOrg: true, /** * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 8000, + orgCloneMinAge: 200, + /** + * {Boolean} If true, then random organism will be killed after new one has + * cloned and amount of organisms is greater then orgMaxOrgs config. false + * mean, that new organism will not be cloned, if amount of organisms is >= + * orgMaxOrgs config. + */ + orgKillOnClone: false, /** * {Number} Minimum energy for cloning */ @@ -65,35 +72,35 @@ const Config = { /** * {Number} Amount of iterations within organism's life loop, after that we * do mutations according to orgRainMutationPercent config. If 0, then - * mutations will be disabled. Should be less then ORGANISM_MAX_MUTATION_PERIOD + * mutations wilsabled. Should be less then ORGANISM_MAX_MUTATION_PERIOD */ - orgRainMutationPeriod: 9500, + orgRainMutationPeriod: 100, /** * {Number} Percent of mutations from code size. 0 is a possible value if * we want to disable mutations. Should be less then 1.0 (1.0 === 100%) */ - orgRainMutationPercent: 0.001, + orgRainMutationPercent: 0.01, /** * {Boolean} Turn this flag on to give organism a possibility to choose his * own mutations period and percent. false - mean, that these values will be * constant for all organisms */ - orgRainPerOrg: false, + orgRainPerOrg: true, /** * {Number} Amount of iterations, after which crossover will be applied * to random organisms. May be set to 0 to turn crossover off */ - orgCrossoverPeriod: 10000, + orgCrossoverPeriod: 4000, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 20000, + orgRandomOrgPeriod: 5000, /** * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 10000, + orgAlivePeriod: 500, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -119,17 +126,17 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 20000, + orgMaxOrgs: 1000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 10000, + orgStartAmount: 1000, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created * by operator and not by evolution. */ - orgStartEnergy: 10000000, + orgStartEnergy: 1000000, /** * {Number} Amount of bits for storing a numeric constant inside byte code */ @@ -145,7 +152,7 @@ const Config = { * organism without interruption by one VM. Set this value to value bigger * then codeMaxSize, then entire code of organism will be run */ - codeYieldPeriod: 10, + codeYieldPeriod: 5, /** * {Number} Amount of bits per one variable. It affects maximum value, * which this variable may contain. This value shouldn't be less then 2. diff --git a/client/src/manager/plugins/organisms/Mutator.js b/client/src/manager/plugins/organisms/Mutator.js index f668c7e..65de19c 100644 --- a/client/src/manager/plugins/organisms/Mutator.js +++ b/client/src/manager/plugins/organisms/Mutator.js @@ -54,7 +54,7 @@ class Mutator { static _onMutationPeriod(org) { if (!OConfig.orgRainPerOrg) {return} - org.mutationPeriod = Helper.rand(OConfig.orgAlivePeriod); + org.mutationPeriod = Helper.rand(OConfig.orgAlivePeriod - 1) + 1; org.changes++; } @@ -65,7 +65,7 @@ class Mutator { } static _onProbs(org) { - if (!OConfig.orgMutationPerOrg) {return} + if (!OConfig.orgMutationProbsPerOrg) {return} org.mutationProbs[Helper.rand(org.mutationProbs.length)] = Helper.rand(OConfig.ORG_MUTATION_PROBS_MAX_VAL) || 1; org.changes++; } diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 047a1bf..7bb5954 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -92,7 +92,7 @@ class Organisms extends Configurable { } /** - * Is called at the end of run() method + * Is called at the end of run() method. Updates maxEnergy value for population * @param {Organism} org Current organism */ onOrganism(org) { @@ -309,7 +309,9 @@ class Organisms extends Configurable { // organisms before cloning. They should kill each other to have a possibility // to clone them. // - this.organisms.size < OConfig.orgMaxOrgs && this._clone(org); + if (org.energy < OConfig.orgCloneMinEnergy) {return} + if (OConfig.orgKillOnClone && this.organisms.size >= OConfig.orgMaxOrgs) {this.randOrg().destroy()} + if (this.organisms.size < OConfig.orgMaxOrgs) {this._clone(org)} } _killInTour() { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 3e1c007..527188b 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -251,13 +251,23 @@ class OperatorsDos extends Operators { onMyX(num, line, org) {this.vars[Num.getVar0(num)] = org.x; return ++line} onMyY(num, line, org) {this.vars[Num.getVar0(num)] = org.y; return ++line} - onCheckLeft(num, line, org) {return this._checkAt(num, line, org.x - 1, org.y)} - onCheckRight(num, line, org) {return this._checkAt(num, line, org.x + 1, org.y)} - onCheckUp(num, line, org) {return this._checkAt(num, line, org.x, org.y - 1)} - onCheckDown(num, line, org) {return this._checkAt(num, line, org.x, org.y + 1)} - - _checkAt(num, line, x, y) { - this.obs.fire(EVENTS.CHECK_AT, x, y, this._ret); + onCheckLeft(num, line, org) { + this.obs.fire(EVENTS.CHECK_AT, org.x - 1, org.y, this._ret); + this.vars[Num.getVar0(num)] = this._ret.ret; + return ++line; + } + onCheckRight(num, line, org) { + this.obs.fire(EVENTS.CHECK_AT, org.x + 1, org.y, this._ret); + this.vars[Num.getVar0(num)] = this._ret.ret; + return ++line; + } + onCheckUp(num, line, org) { + this.obs.fire(EVENTS.CHECK_AT, org.x, org.y - 1, this._ret); + this.vars[Num.getVar0(num)] = this._ret.ret; + return ++line; + } + onCheckDown(num, line, org) { + this.obs.fire(EVENTS.CHECK_AT, org.x, org.y + 1, this._ret); this.vars[Num.getVar0(num)] = this._ret.ret; return ++line; } diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index f5842b3..a3b71fb 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -145,7 +145,8 @@ class Organisms extends BaseOrganisms { // // Energy found // - if (typeof(this.positions[posId]) === 'undefined') { + const victimOrg = this.positions[posId]; + if (typeof victimOrg === 'undefined') { if (eat >= 0) { ret.ret = this.world.grabDot(x, y, eat); this.parent.fire(EVENTS.EAT_ENERGY, ret.ret); @@ -154,25 +155,24 @@ class Organisms extends BaseOrganisms { this.world.setDot(x, y, (((-eat + .5) << 0) >>> 0) + this.world.getDot(x, y)); this.parent.fire(EVENTS.PUT_ENERGY, -eat); } + return; + } // // Organism found // + ret.ret = eat < 0 ? 0 : (eat > victimOrg.energy ? victimOrg.energy : eat); + if (victimOrg.energy <= ret.ret) { + this.parent.fire(EVENTS.KILL_EAT, victimOrg); + // + // IMPORTANT: + // We have to do destroy here, to have a possibility for current + // (winner) organism to clone himself after eating other organism. + // This is how organisms compete for an ability to clone + // + victimOrg.destroy(); } else { - const victimOrg = this.positions[posId]; - ret.ret = eat < 0 ? 0 : (eat > victimOrg.energy ? victimOrg.energy : eat); - if (victimOrg.energy <= ret.ret) { - this.parent.fire(EVENTS.KILL_EAT, victimOrg); - // - // IMPORTANT: - // We have to do destroy here, to have a possibility for current - // (winner) organism to clone himself after eating other organism. - // This is how organisms compete for an ability to clone - // - victimOrg.destroy(); - } else { - this.parent.fire(EVENTS.EAT_ORG, victimOrg, ret.ret); - victimOrg.energy -= ret.ret; - } + this.parent.fire(EVENTS.EAT_ORG, victimOrg, ret.ret); + victimOrg.energy -= ret.ret; } } diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 5f8dbdf..97044b1 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 2, + worldWidth: 1920 / 4, /** * {Number} World height */ - worldHeight: 1080 / 2, + worldHeight: 1080 / 4, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 @@ -75,7 +75,7 @@ ClientConfig.init({ /** * {Number} size of one clever energy block in dots */ - worldEnergyBlockSize: 200, + worldEnergyBlockSize: 20, /** * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details @@ -95,9 +95,10 @@ ClientConfig.init({ */ worldEnergyMinPercent: .0002, /** - * {Number} Amount of random stones in a world + * {Number} Percent of stones in a world. Percent from world size: + * stoneAmount = worldStonesPercent * worldWidth * worldHeight */ - worldStonesAmount: 1500, + worldStonesPercent: .1, /** * {Number} Color index for stones in a world. See Organism.MAX_COLORS * constant for details From d63d85fa77ac3c984db5f68edbdb161248ee9f13 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 28 Mar 2018 00:36:01 +0300 Subject: [PATCH 11/21] updated energy calculation mechanism --- client/src/manager/plugins/Energy.js | 37 +++++++++++-------- client/src/manager/plugins/status/Status.js | 12 +----- .../manager/plugins/status/charts/Charts.js | 3 +- .../manager/plugins/status/console/Console.js | 3 +- client/src/share/Config.js | 10 ++--- 5 files changed, 29 insertions(+), 36 deletions(-) diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index 6ef17db..935af0b 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -13,7 +13,6 @@ const POSID = Helper.posId; class Energy { constructor(manager) { this._manager = manager; - this._cleverActive = true; this._onIterationCb = this._onIteration.bind(this); Helper.override(manager, 'onIteration', this._onIterationCb); @@ -26,17 +25,18 @@ class Energy { } _onIteration(counter) { - this._cleverActive && this._addEnergyBlock(); - if (Config.worldEnergyCheckPeriod === 0 || counter % Config.worldEnergyCheckPeriod !== 0) {return} - const energy = this._getEnergyPercent(); + let energy = this._getEnergyPercent(); + this._manager.fire(EVENTS.WORLD_ENERGY, energy); - if (energy < Config.worldEnergyMinPercent) {this._manager.fire(EVENTS.WORLD_ENERGY_UP, this._cleverActive = true)} - else if (energy > Config.worldEnergyMaxPercent) {this._manager.fire(EVENTS.WORLD_ENERGY_UP, this._cleverActive = false)} + if (energy > Config.worldEnergyMinPercent) {return} + const maxEnergy = Config.worldEnergyMaxPercent * Config.worldWidth * Config.worldHeight; + let amount = 0; + while ((amount = this._addEnergyBlock(amount, maxEnergy)) < maxEnergy) {} } - _addEnergyBlock() { + _addEnergyBlock(amount, maxEnergy) { const width = Config.worldWidth; const height = Config.worldHeight; const color = Organism.getColor(Config.worldEnergyColorIndex); @@ -48,27 +48,32 @@ class Energy { for (let i = 0; i < block; i++) { x = x + Helper.rand(3) - 1; y = y + Helper.rand(3) - 1; - if (x < 0 || x >= width || y < 0 || y >= height) {return} - if (world.isFree(x, y)) {world.setDot(x, y, color)} + if (x < 0 || x >= width || y < 0 || y >= height) {return amount} + if (world.isFree(x, y)) { + world.setDot(x, y, color); + if (++amount > maxEnergy) {return amount} + } } + + return amount; } _getEnergyPercent() { - let energy = 0; - const world = this._manager.world; - const width = Config.worldWidth; + let energy = 0; + const world = this._manager.world; + const width = Config.worldWidth; const height = Config.worldHeight; - const poses = this._manager.positions; - const objs = this._manager.objects; + const poses = this._manager.positions; + const objs = this._manager.objects; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { const posId = POSID(x, y); - if (typeof poses[posId] === 'undefined' && typeof objs[posId] === 'undefined') {energy += world.getDot(x, y)} + if (typeof poses[posId] === 'undefined' && typeof objs[posId] === 'undefined' && world.getDot(x, y) > 0) {++energy} } } - return energy / (width * height * 0xffffffff); + return energy / (width * height); } } diff --git a/client/src/manager/plugins/status/Status.js b/client/src/manager/plugins/status/Status.js index bbb013c..0ed60b6 100644 --- a/client/src/manager/plugins/status/Status.js +++ b/client/src/manager/plugins/status/Status.js @@ -37,7 +37,7 @@ class Status extends Configurable { super(manager, {Config, cfg: statCfg}, apiCfg); this._status = { - lps :0, ips :0, orgs :0, energy :0, oenergy :0, eenergy:0, wenergy:0, wenergyup:true, changes:0, fit:0, age:0, code:0, + lps :0, ips :0, orgs :0, energy :0, oenergy :0, eenergy:0, wenergy:0, changes :0, fit:0, age:0, code:0, kill:0, killenergy:0, killage:0, killeat:0, killover:0, killout:0, killin :0, killclone:0 }; this._stamp = 0; @@ -56,7 +56,6 @@ class Status extends Configurable { this._times = 0; this._kill = new Array(9); this._worldEnergy = 0.0; - this._worldEnergyUp = true; this._statusCfg = statCfg; this._firstCall = true; @@ -75,7 +74,6 @@ class Status extends Configurable { this._onKillInCb = this._onKillHandlerOrg.bind(this, 7); this._onKillCloneCb = this._onKillHandlerOrg.bind(this, 8); this._onWorldEnergyCb = this._onWorldEnergy.bind(this); - this._onWorldEnergyUpCb = this._onWorldEnergyUp.bind(this); Helper.override(manager, 'onLoop', this._onLoopCb); manager.on(EVENTS.IPS, this._onIpsCb); @@ -92,7 +90,6 @@ class Status extends Configurable { manager.on(EVENTS.KILL_STEP_IN, this._onKillInCb); manager.on(EVENTS.KILL_CLONE, this._onKillCloneCb); manager.on(EVENTS.WORLD_ENERGY, this._onWorldEnergyCb); - manager.on(EVENTS.WORLD_ENERGY_UP, this._onWorldEnergyUpCb); _fill(this._kill, 0); } @@ -100,7 +97,6 @@ class Status extends Configurable { destroy() { const man = this.parent; - man.off(EVENTS.WORLD_ENERGY_UP, this._onWorldEnergyUpCb); man.off(EVENTS.WORLD_ENERGY, this._onWorldEnergyCb); man.off(EVENTS.KILL_CLONE, this._onKillCloneCb); man.off(EVENTS.KILL_STEP_IN, this._onKillInCb); @@ -117,7 +113,6 @@ class Status extends Configurable { man.off(EVENTS.IPS, this._onIpsCb); Helper.unoverride(man, 'onLoop', this._onLoopCb); - this._onWorldEnergyUpCb = null; this._onWorldEnergyCb = null; this._onKillOrgCb = null; this._onKillTourCb = null; @@ -199,7 +194,6 @@ class Status extends Configurable { status.killclone = fix(this._kill[8], 2); status.wenergy = fix(this._worldEnergy, 5); - status.wenergyup = this._worldEnergyUp; !this._firstCall && this.onStatus(status, orgs.size); this._onAfterLoop(stamp); @@ -259,10 +253,6 @@ class Status extends Configurable { _onWorldEnergy(percent) { this._worldEnergy = percent; } - - _onWorldEnergyUp(up) { - this._worldEnergyUp = up; - } } module.exports = Status; \ No newline at end of file diff --git a/client/src/manager/plugins/status/charts/Charts.js b/client/src/manager/plugins/status/charts/Charts.js index ccccb0f..3066047 100644 --- a/client/src/manager/plugins/status/charts/Charts.js +++ b/client/src/manager/plugins/status/charts/Charts.js @@ -167,14 +167,13 @@ class Charts extends Status { const enrg = `enrg:${status.eenergy}`; const onrg = `onrg:${status.oenergy}`; const wnrg = `wnrg:${status.wenergy}`; - const wnrgup = status.wenergyup ? '\u2191' : '\u2193'; const code = `cod:${status.code}`; const age = `age:${status.age}`; const kill = `kil:${status.kill}`; const kilo = `kilo:${status.killeat}`; const orgs = `org:${status.orgs}`; - this._headerEl.textContent = `${man.clientId ? 'id:' + man.clientId : ''} ${conns === '' ? '' : 'con:' + conns} ${ips} ${wnrg} ${wnrgup} ${enrg} ${onrg} ${code} ${age} ${kill} ${kilo} ${orgs}`; + this._headerEl.textContent = `${man.clientId ? 'id:' + man.clientId : ''} ${conns === '' ? '' : 'con:' + conns} ${ips} ${wnrg} ${enrg} ${onrg} ${code} ${age} ${kill} ${kilo} ${orgs}`; } /** diff --git a/client/src/manager/plugins/status/console/Console.js b/client/src/manager/plugins/status/console/Console.js index 80865fc..07ea2f4 100644 --- a/client/src/manager/plugins/status/console/Console.js +++ b/client/src/manager/plugins/status/console/Console.js @@ -50,14 +50,13 @@ class Console extends Status { const senergy = format(status.energy, 'nrg', 19); const spenergy = format(status.oenergy, 'onrg', 15); const seenergy = format(status.eenergy, 'enrg', 16); - const wenergy = format(status.wenergy + (status.wenergyup ? '\u2191' : '\u2193'), 'wnrg', 14); const skill = format(status.kill, 'kil', 12); const schanges = format(status.changes, 'che', 12); const sage = format(status.age, 'age', 11); const scode = format(status.code, 'cod', 12); // TODO: under Node.js should use Server/Console.xxx() - console.log(`%c${conns}${sips}${slps}${sorgs}%c${senergy}${spenergy}${seenergy}${wenergy}${skill}${schanges}${sage}${scode}`, GREEN, RED); + console.log(`%c${conns}${sips}${slps}${sorgs}%c${senergy}${spenergy}${seenergy}${skill}${schanges}${sage}${scode}`, GREEN, RED); } } diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 97044b1..2ce0a53 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 4, + worldWidth: 1920 / 6, /** * {Number} World height */ - worldHeight: 1080 / 4, + worldHeight: 1080 / 6, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 @@ -87,18 +87,18 @@ ClientConfig.init({ * be less then worldEnergyMinPercent. These two configs create cyclical * energy adding to the world. */ - worldEnergyMaxPercent: .0009, + worldEnergyMaxPercent: .5, /** * {Number} Opposite to worldEnergyMaxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - worldEnergyMinPercent: .0002, + worldEnergyMinPercent: .1, /** * {Number} Percent of stones in a world. Percent from world size: * stoneAmount = worldStonesPercent * worldWidth * worldHeight */ - worldStonesPercent: .1, + worldStonesPercent: .3, /** * {Number} Color index for stones in a world. See Organism.MAX_COLORS * constant for details From 955dc2c933f7477410950f6fd3b90a015ab99b60 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 28 Mar 2018 23:26:24 +0300 Subject: [PATCH 12/21] new default configs --- client/src/manager/plugins/organisms/Config.js | 12 ++++++------ client/src/share/Config.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 148c4cc..5c2ee3e 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -52,7 +52,11 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 200, + orgCloneMinAge: 700, + /** + * {Number} Minimum energy for cloning + */ + orgCloneMinEnergy: 1000000, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -60,10 +64,6 @@ const Config = { * orgMaxOrgs config. */ orgKillOnClone: false, - /** - * {Number} Minimum energy for cloning - */ - orgCloneMinEnergy: 100000, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -100,7 +100,7 @@ const Config = { * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 500, + orgAlivePeriod: 1000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 2ce0a53..79477c0 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 6, + worldWidth: 1920 / 10, /** * {Number} World height */ - worldHeight: 1080 / 6, + worldHeight: 1080 / 10, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 From cd4ce7d4d87c6ad7c9e9f547cd4463301c1e6c9a Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 30 Mar 2018 12:38:18 +0300 Subject: [PATCH 13/21] speed optimization test --- client/src/manager/Manager.js | 9 +- client/src/manager/ManagerSpec.js | 40 +++--- .../src/manager/plugins/organisms/Config.js | 2 +- .../src/manager/plugins/organisms/Organism.js | 7 +- .../manager/plugins/organisms/Organisms.js | 130 +++++++----------- .../manager/plugins/organisms/dos/Organism.js | 2 +- .../plugins/organisms/dos/Organisms.js | 4 +- .../plugins/organisms/garmin/Organism.js | 2 +- client/src/manager/plugins/status/Status.js | 13 +- client/src/vm/VM.js | 2 +- common/src/FastArray.js | 114 +++++++++++++++ 11 files changed, 206 insertions(+), 119 deletions(-) create mode 100644 common/src/FastArray.js diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index 67acfb0..6e6f634 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -13,7 +13,7 @@ * @author flatline */ const Observer = require('./../../../common/src/Observer'); -const Queue = require('./../../../common/src/Queue'); +const FastArray = require('./../../../common/src/FastArray'); const Config = require('./../share/Config').Config; const OConfig = require('./plugins/organisms/Config'); const Plugins = require('./Plugins'); @@ -38,11 +38,11 @@ class Manager extends Observer { constructor(hasView = true) { super(EVENT_AMOUNT); /** - * {Queue} Queue of organisms in current Manager. Should be used by plugins. - * Organisms plugin walk through this queue and run organism's code all the + * {FastArray} Array of organisms in current Manager. Should be used by plugins. + * Organisms plugin walk through this array and run organism's code all the * time. */ - this.organisms = new Queue(); + this.organisms = new FastArray(OConfig.orgMaxOrgs); /** * {Object} positions of organisms in a world. Is used to prevent collisions * and track all world objects @@ -50,6 +50,7 @@ class Manager extends Observer { this.positions = {}; /** * {Object} Map of world objects like stones, water,... + * TODO: it should be a part of positions object. Remove it! */ this.objects = {}; /** diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index 1104b1a..65e367a 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -91,7 +91,7 @@ describe("client/src/manager/Manager", () => { }); it("Checking manager creation and it's properties", (done) => { const man = new Manager(false); - expect(man.organisms.size).toBe(0); + expect(man.organisms.length).toBe(0); expect(Object.keys(man.positions).length).toBe(0); expect(man.codeRuns).toBe(0); expect(!!man.api.version).toBe(true); @@ -288,18 +288,18 @@ describe("client/src/manager/Manager", () => { console.log = () => {}; expect(man1.clientId).toBe(null); expect(man2.clientId).toBe(null); - expect(man1.organisms.size).toBe(0); - expect(man2.organisms.size).toBe(0); + expect(man1.organisms.length).toBe(0); + expect(man2.organisms.length).toBe(0); man1.on(EVENTS.LOOP, () => { if (blocked) {return} - expect(man1.organisms.size).toBe(1); + expect(man1.organisms.length).toBe(1); if (iterated1 && iterated2) {destroy(); return} iterated1 = true; }); man2.on(EVENTS.LOOP, () => { if (blocked) {return} - expect(man2.organisms.size).toBe(1); + expect(man2.organisms.length).toBe(1); if (iterated2 && iterated1) {destroy(); return} iterated2 = true; }); @@ -335,10 +335,10 @@ describe("client/src/manager/Manager", () => { OConfig.orgStartAmount = 1; OConfig.orgRainMutationPeriod = 0; OConfig.orgCloneMutationPercent = 0; - expect(man.organisms.size).toBe(0); + expect(man.organisms.length).toBe(0); man.on(EVENTS.LOOP, () => { if (iterated) {return} - expect(man.organisms.size).toBe(1); + expect(man.organisms.length).toBe(1); man.stop(() => { man.destroy(() => { OConfig.orgCloneMutationPercent = percent; @@ -399,10 +399,10 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { - org1 = man1.organisms.first.val; + org1 = man1.organisms.lastAdded(); org1.vm.insertLine(); org1.vm.updateLine(0, 0b00001011000000000000000000000000); // onStepRight() - } else if (man2.organisms.size === 2) { + } else if (man2.organisms.length === 2) { destroy(); } if (iterated1 > 10000) {throw 'Error sending organism between Managers'} @@ -466,7 +466,7 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null && org2 !== null) { - org1 = man1.organisms.first.val; + org1 = man1.organisms.lastAdded(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() man1.on(EVENTS.STEP_OUT, () => { expect(doneInc < 3).toBe(true); @@ -474,14 +474,14 @@ describe("client/src/manager/Manager", () => { }); man2.on(EVENTS.STEP_IN, () => { ++doneInc; - expect(man1.organisms.size).toBe(1); - expect(man1.organisms.first.val.x).toBe(0); + expect(man1.organisms.length).toBe(1); + expect(man1.organisms.lastAdded().x).toBe(0); }); } else if (org1 !== null && org2 !== null && doneInc === 2) { - expect(man1.organisms.size).toBe(1); - expect(man1.organisms.first.val.x).toBe(0); - expect(man2.organisms.size).toBe(1); - expect(man2.organisms.first.val.x).toBe(0); + expect(man1.organisms.length).toBe(1); + expect(man1.organisms.lastAdded().x).toBe(0); + expect(man2.organisms.length).toBe(1); + expect(man2.organisms.lastAdded().x).toBe(0); destroy(); doneInc++; } @@ -489,7 +489,7 @@ describe("client/src/manager/Manager", () => { iterated1++; }); man2.on(EVENTS.LOOP, () => { - !iterated2 && (org2 = man2.organisms.first.val); + !iterated2 && (org2 = man2.organisms.lastAdded()); iterated2++; }); @@ -554,10 +554,10 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { - expect(man2.organisms.size).toBe(1); - org1 = man1.organisms.first.val; + expect(man2.organisms.length).toBe(1); + org1 = man1.organisms.lastAdded(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() - } else if (man2.organisms.size === 2) { + } else if (man2.organisms.length === 2) { destroy(); } if (iterated1 > 10000) {throw 'Error sending organism between Servers'} diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 5c2ee3e..0c75757 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -100,7 +100,7 @@ const Config = { * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 1000, + orgAlivePeriod: 10000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 3d86e85..dddcda8 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -70,7 +70,7 @@ class Organism extends Observer { * @param {String} id Unique identifier of organism * @param {Number} x Unique X coordinate * @param {Number} y Unique Y coordinate - * @param {Object} item Reference to the Queue item, where + * @param {Number} item Reference to the item index, where * this organism is located * @param {Function} operatorCls Class of operators * @param {Organism} parent Parent organism if cloning is needed @@ -88,7 +88,6 @@ class Organism extends Observer { this._iterations = -1; this._changes = 0; this._item = item; - this._maxEnergy = 0; this._energyChanges = 0; this._fnId = 0; } @@ -115,7 +114,6 @@ class Organism extends Observer { set energy(e) {if (this.vm !== null) { this._energy = e; ++this._energyChanges % UPDATE_COLOR_PERIOD === 0 && this._updateColor()}} set startEnergy(e) {this._startEnergy = e} set changes(c) {this._changes = c} - set maxEnergy(e) {this._maxEnergy = e} /** * Runs one code iteration (amount of lines set in Config.codeYieldPeriod) and returns @@ -239,7 +237,8 @@ class Organism extends Observer { } _updateColor() { - this._color = Organism.getColor((this._energy * MAX_COLORS) / this._maxEnergy); + // TODO: implement organism update color logic here + //this._color = Organism.getColor(MAX_COLORS); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 7bb5954..bec0c0c 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -54,20 +54,23 @@ class Organisms extends Configurable { */ createEmptyOrg(...args) {} + /** + * Is called at the end of run() method + * @abstract + */ + onOrganism() {} + constructor(manager) { super(manager, {Config, cfg: OConfig}, { getAmount : ['_apiGetAmount', 'Shows amount of organisms within current Client(Manager)'], - getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in a Queue'] + getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in an array'] }); this.organisms = manager.organisms; this.objects = manager.objects; - this.randOrgItem = this.organisms.first; this.positions = manager.positions; this.world = manager.world; this._mutator = new Mutator(manager, this); - this._maxEnergy = 0; - this._oldMaxEnergy = 0; this._onIterationCb = this._onIteration.bind(this); this._onLoopCb = this._onLoop.bind(this); @@ -77,12 +80,14 @@ class Organisms extends Configurable { } destroy() { - let item = this.organisms.first; - let org; - while (item && (org = item.val)) {org.destroy(); item = item.next} + const orgs = this.organisms; + const len = orgs.length; + for (let i = 0; i < len; i++) {orgs.get(i).destroy()} Helper.unoverride(this.parent, 'onIteration', this._onIterationCb); Helper.unoverride(this.parent, 'onLoop', this._onLoopCb); + this.organisms = null; + this.objects = null; this._mutator.destroy(); this._mutator = null; this._onIterationCb = null; @@ -91,19 +96,6 @@ class Organisms extends Configurable { super.destroy(); } - /** - * Is called at the end of run() method. Updates maxEnergy value for population - * @param {Organism} org Current organism - */ - onOrganism(org) { - if (org.energy > this._oldMaxEnergy) {this._oldMaxEnergy = org.energy} - if (org === this.organisms.last.val) { - this._maxEnergy = this._oldMaxEnergy; - this._oldMaxEnergy = 0; - } - org.maxEnergy = this._maxEnergy; - } - addOrgHandlers(org) { org.on(ORG_EVENTS.DESTROY, this._onDestroyOrg.bind(this)); org.on(ORG_EVENTS.KILL_NO_ENERGY, this._onKillNoEnergyOrg.bind(this)); @@ -135,10 +127,9 @@ class Organisms extends Configurable { createOrg(x, y, parent = null) { if (x === -1) {return false} const orgs = this.organisms; - orgs.add(null); - let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.last, parent); + let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, parent); - orgs.last.val = org; + orgs.set(org); this.addOrgHandlers(org); this.world.setDot(x, y, org.color); this.positions[org.posId] = org; @@ -150,19 +141,12 @@ class Organisms extends Configurable { /** * Returns random organism of current population - * @return {Organism|null} + * @return {Organism|false} */ - randOrg() { - const offs = Helper.rand(this.organisms.size) + 1; - let item = this.randOrgItem; - - for (let i = 0; i < offs; i++) { - if ((item = item.next) === null) { - item = this.organisms.first; - } - } - - return (this.randOrgItem = item).val; + _randOrg() { + const org = this.organisms.get(Helper.rand(this.organisms.size)); + if (org === 0) {return false} + return org; } /** @@ -172,13 +156,14 @@ class Organisms extends Configurable { * @param {Number} stamp Time stamp of current iteration */ _onIteration(counter, stamp) { - let item = this.organisms.first; - let org; + const orgs = this.organisms; + const len = orgs.size; + let org; - while (org = item && item.val) { + for (let i = 0; i < len; i++) { + if ((org = orgs.get(i)) === 0) {continue} org.run(); - org.energy > 0 && this.onOrganism(org); - item = item.next; + //this.onOrganism(org); } this._updateTournament(counter); @@ -191,9 +176,12 @@ class Organisms extends Configurable { } _tournament(org1 = null, org2 = null) { - org1 = org1 || this.randOrg(); - org2 = org2 || this.randOrg(); + org1 = org1 || this._randOrg(); + org2 = org2 || this._randOrg(); + if (org1 === false && org2 !== false) {return org2} + if (org2 === false && org1 !== false) {return org1} + if (org1 === false && org2 === false) {return false} if (org1.energy < 1 && org2.energy < 1) {return false} if ((org2.energy > 0 && org1.energy < 1) || this.compare(org2, org1)) { return org2; @@ -208,7 +196,7 @@ class Organisms extends Configurable { let y; [x, y] = this.world.getNearFreePos(org.x, org.y); if (x === -1 || this.createOrg(x, y, org) === false) {return false} - let child = this.organisms.last.val; + let child = this.organisms.lastAdded(); this.onClone(org, child); if (org.energy < 1 || child.energy < 1) {return false} @@ -219,7 +207,7 @@ class Organisms extends Configurable { _crossover(org1, org2) { if (!this._clone(org1, true)) {return false} - let child = this.organisms.last.val; + let child = this.organisms.lastAdded(); if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); @@ -245,37 +233,20 @@ class Organisms extends Configurable { * @return {Number} Amount of organisms within current Manager */ _apiGetAmount() { - return this.parent.organisms.size; + return this.parent.organisms.length; } /** - * Return organism instance by id or it's index in a Queue + * Return organism instance by id or it's index in an array * @param {Number|String} index Index or id * @return {Organism} Organism instance or null * @api */ _apiGetOrganism(index) { - if (Helper.isNumeric(index)) { - return this.organisms.get(index); - } - - let item = this.organisms.first; - let org; - - while (org = item && item.val) { - if (org.id === index) {return org} - item = item.next; - } - - return null; + return this.organisms.get(index); } _onDestroyOrg(org) { - if (this.randOrgItem === org.item) { - if ((this.randOrgItem = org.item.next) === null) { - this.randOrgItem = this.organisms.first; - } - } this.organisms.del(org.item); this.world.setDot(org.x, org.y, 0); this.positions[org.posId] = undefined; @@ -295,12 +266,12 @@ class Organisms extends Configurable { //const orgAmount = this.organisms.size; //if (OConfig.orgKillOnClone && orgAmount >= maxOrgs) {this._killInTour()} - //if (orgAmount >= maxOrgs && (OConfig.orgKillOnClone || Math.random() <= (org.energy / org.vm.size) / this._maxEnergy)) {this.randOrg().destroy()} + //if (orgAmount >= maxOrgs && (OConfig.orgKillOnClone || Math.random() <= (org.energy / org.vm.size) / this._maxEnergy)) {this._randOrg().destroy()} // if (this.organisms.size >= OConfig.orgMaxOrgs && Math.random() <= ((org.energy / 10000000000000) * (org.iterations / OConfig.orgAlivePeriod))) { - // this.randOrg().destroy(); + // this._randOrg().destroy(); // } //if (this.organisms.size < maxOrgs) {this._clone(org)} - //if (this.organisms.size >= maxOrgs && Math.random() <= (org.energy / org.vm.size) / this._maxEnergy) {this.randOrg().destroy()} + //if (this.organisms.size >= maxOrgs && Math.random() <= (org.energy / org.vm.size) / this._maxEnergy) {this._randOrg().destroy()} // // This is very important part of application! Cloning should be available only if // amount of organisms is less then maximum or if current organism has ate other just @@ -310,14 +281,14 @@ class Organisms extends Configurable { // to clone them. // if (org.energy < OConfig.orgCloneMinEnergy) {return} - if (OConfig.orgKillOnClone && this.organisms.size >= OConfig.orgMaxOrgs) {this.randOrg().destroy()} - if (this.organisms.size < OConfig.orgMaxOrgs) {this._clone(org)} + if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) {this._randOrg().destroy()} + if (this.organisms.length < OConfig.orgMaxOrgs) {this._clone(org)} } _killInTour() { - let org1 = this.randOrg(); - let org2 = this.randOrg(); - if (org1.energy < 1 || org2.energy < 1 || org1 === org2 || this.organisms.size < 1) {return false} + let org1 = this._randOrg(); + let org2 = this._randOrg(); + if (org1 === false || org2 === false || org1.energy < 1 || org2.energy < 1 || org1 === org2 || this.organisms.length < 1) {return false} const winner = this._tournament(org1, org2); if (winner === false) {return false} @@ -336,12 +307,13 @@ class Organisms extends Configurable { */ _updateTournament(counter) { const period = OConfig.orgTournamentPeriod; - return counter % period === 0 && this.organisms.size > 0 || period !== 0 && this._killInTour(); + return counter % period === 0 && this.organisms.length > 0 || period !== 0 && this._killInTour(); } _updateRandomOrgs(counter) { - if (counter % OConfig.orgRandomOrgPeriod !== 0 || OConfig.orgRandomOrgPeriod === 0 || this.organisms.size < 1) {return false} - const vm = this.randOrg().vm; + if (counter % OConfig.orgRandomOrgPeriod !== 0 || OConfig.orgRandomOrgPeriod === 0 || this.organisms.length < 1) {return false} + const vm = this._randOrg().vm; + if (typeof vm === 'undefined') {return false} const size = Helper.rand(vm.size) + 1; const pos = Helper.rand(vm.size - size); @@ -351,14 +323,14 @@ class Organisms extends Configurable { } _updateCrossover(counter) { - const orgAmount = this.organisms.size; + const orgAmount = this.organisms.length; if (counter % OConfig.orgCrossoverPeriod !== 0 || OConfig.orgCrossoverPeriod === 0 || orgAmount < 1) {return false} // // We have to have a possibility to crossover not only with best // organisms, but with low fit also // - let org1 = Helper.rand(2) === 0 ? this._tournament() : this.randOrg(); - let org2 = Helper.rand(2) === 0 ? this._tournament() : this.randOrg(); + let org1 = Helper.rand(2) === 0 ? this._tournament() : this._randOrg(); + let org2 = Helper.rand(2) === 0 ? this._tournament() : this._randOrg(); if (org1 === false || org2 === false || org1.energy < 1 || org2.energy < 1) {return false} this._crossover(org1, org2); @@ -374,7 +346,7 @@ class Organisms extends Configurable { } _updateCreate() { - if (this.organisms.size < 1) {this._createPopulation()} + if (this.organisms.length < 1) {this._createPopulation()} } } diff --git a/client/src/manager/plugins/organisms/dos/Organism.js b/client/src/manager/plugins/organisms/dos/Organism.js index db11544..9c395a4 100644 --- a/client/src/manager/plugins/organisms/dos/Organism.js +++ b/client/src/manager/plugins/organisms/dos/Organism.js @@ -14,7 +14,7 @@ class OrganismDos extends Organism { * @param {String} id Unique identifier of organism * @param {Number} x Unique X coordinate * @param {Number} y Unique Y coordinate - * @param {Object} item Reference to the Queue item, where + * @param {Object} item Reference to the item index, where * this organism is located * @param {Organism} parent Parent organism if cloning is needed */ diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index a3b71fb..b2006fc 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -242,8 +242,8 @@ class Organisms extends BaseOrganisms { * @param {Object} ret Return object */ _onStepIn(x, y, orgJson, ret) { - if (ret.ret = this.world.isFree(x, y) && this.organisms.size < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent) && this.createOrg(x, y)) { - const org = this.organisms.last.val; + if (ret.ret = this.world.isFree(x, y) && this.organisms.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent) && this.createOrg(x, y)) { + const org = this.organisms.lastAdded(); org.unserialize(orgJson); const energy = (org.energy * OConfig.orgStepEnergySpendPercent + .5) << 0; // diff --git a/client/src/manager/plugins/organisms/garmin/Organism.js b/client/src/manager/plugins/organisms/garmin/Organism.js index 2ed9a63..1f93219 100644 --- a/client/src/manager/plugins/organisms/garmin/Organism.js +++ b/client/src/manager/plugins/organisms/garmin/Organism.js @@ -16,7 +16,7 @@ class OrganismGarmin extends Organism { * @param {String} id Unique identifier of organism * @param {Number} x Unique X coordinate * @param {Number} y Unique Y coordinate - * @param {Object} item Reference to the Queue item, where + * @param {Object} item Reference to the item index, where * this organism is located * @param {Observer} obs Observer for sending external events * @param {Organism} parent Parent organism if cloning is needed diff --git a/client/src/manager/plugins/status/Status.js b/client/src/manager/plugins/status/Status.js index 0ed60b6..94655b4 100644 --- a/client/src/manager/plugins/status/Status.js +++ b/client/src/manager/plugins/status/Status.js @@ -133,24 +133,25 @@ class Status extends Configurable { } _onBeforeLoop(orgs) { - const size = orgs.size || 1; + const size = orgs.length || 1; let energy = 0; let startEnergy = 0; let iterations = 0; let fitness = 0; let changes = 0; let codeSize = 0; - let item = orgs.first; + const len = orgs.size; let org; - while(item && (org = item.val)) { + for (let i = 0; i < len; i++) { + if ((org = orgs.get(i)) === 0) {continue} + energy += org.energy; startEnergy += org.startEnergy; iterations += org.iterations; changes += org.changes; fitness += org.fitness(); codeSize += org.vm.size; - item = item.next; } this._energy = energy / size; @@ -166,7 +167,7 @@ class Status extends Configurable { if (stamp - this._stamp < this._statusCfg.period) {return} const orgs = this.parent.organisms; const status = this._status; - const orgAmount = orgs.size || 1; + const orgAmount = orgs.length || 1; const fix = Status._toFixed; this._onBeforeLoop(orgs); @@ -195,7 +196,7 @@ class Status extends Configurable { status.wenergy = fix(this._worldEnergy, 5); - !this._firstCall && this.onStatus(status, orgs.size); + !this._firstCall && this.onStatus(status, orgs.length); this._onAfterLoop(stamp); this._firstCall = false; } diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index df075bd..912075d 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -38,7 +38,7 @@ class VM extends Observer { */ this._operatorCls = operatorCls; this._vars = parent && parent.vars && parent.vars.slice() || this._getVars(); - this._code = parent && parent.code.slice() || []; + this._code = parent && parent.code.slice() || [102010341,226191885,200109152,129239321,120230511,212700737,146086204,169006534,70810654,236109088,21009195,234433901,101041014,153424224,172525892,163739837,155055718,77473223,160792938,204092844,4306977,186406410,128227592,43980086,130041897,170032548,169377297,43538070,192001244,179556805,174174625,228493827,100127000,117130125,117350792,64579162,230088461,180523805,22716019,44503895,111912075,106541750,185900561,49424461,314484569,248020267,284600795,196179104,81616173,220252955,66643426,138471815,249522957,225747005,235973814,78136757,245329089,149223185,196325976,90216701,8462368,243745810,275565066,315780670,126426118,115017256,77957900,43382097,219086631,104748276,164034927,187161306,258273627,274605007,251246552,109875154,162762758,359649722,21631269,160939590,135635862,347922125,47028039,103268861,33481886,328856887,320791974,102564578,325584338,240155556,310956581,332262718,281115585,255416298,56526016,216202570,58797126,275216084,179188444,35510775,107078419,162372242,159561416,104749340,49147506,293127740,25086557,14592669,218266840,206369309,356664114,282757190,32154896,250704101,162011880,27817768,73719754,321995331,227372609,173701786,140441376,65150789,243661913,279503892,361150067,197003070,265075520,335490183,359239278,208746301,251849157,322961773,250102086,177132823,10844881,221170368,42612495,164266783,213415703,50989721,253159322,75201397,75251243,284287480,239248288,343706359,234422168,73881170,32873066,140694443,230224009,329578189,302029688,260641276,221145114,271848517,112587146,27508187,160255454,217141050,289882814,110551028,362065745,266639784,189905639,328721510,22595828,92652025,16331860,84397251,110717070,167809194,282893655,149087879,341641799,305877171,47949897,30226804,29326378,5264065,3678030,30424703,274541192,15582110,315125937,10197952,64891919,13488022,177812387,162546279,200029263,142513059,119173917,197197175,245368115,147431662,247202501,356282075,67619626,177488883,185579907,60773224,43475771,250230335,183756732,102482623,58855704,258031147,29380608,332941197,267519551,158300456,20657085,163286523,226819902,308407044,328653284,317906531,276205476,256029358,79858422,89507380,145382882,171365579,246648979,32492304,159618173,3495690,124775704,358284547,263102533,88173398,223264957,200192193,21895446,23743162,192632381,6808375,66977796,93933517,269180908,260451782,303919301,296916921,62045740,247446069,62373497,108595985,341153042,298156406,20044425,104442678,78640255,355434367,120774734,148331569,287988242,8160318,89074002,172314486,213954846,342087621,262752812,308777822,67506084,280464307,285708168,15893307,222003070,194495371,262797388,304341003,253569188,278781631,218966877,5287177,74769522,183066598,352253018,34275085,52652201,207034345,177281005,47776967,296444150,260109248,270954962,175777346,167008262,211047529,246835341,172653707,275430467,96022556,82811972,277058972,6631344,66068938,223872328,5351498]; this._line = parent && parent.line || 0; /** * {Array} Array of two numbers. first - line number where we have diff --git a/common/src/FastArray.js b/common/src/FastArray.js new file mode 100644 index 0000000..24b5122 --- /dev/null +++ b/common/src/FastArray.js @@ -0,0 +1,114 @@ +/** + * Implementation of fast array. First assumption of this class is in fixed array + * size. Second that get() method will be called must more times, then set() or + * del() or resize(). Resize is possible, but should be rare to keep it fast. Is + * used for storing organisms population. This class doesn't check size overflow + * due performance issue. Removing element means setting 0 to specified index. + * This class should not be used for storing numbers! + * + * @author flatline + */ +class FastArray { + constructor(size) { + /** + * {Array} Source container for custom objects + */ + this._arr = new Array(size); + /** + * {Array} Array of free indexes in _arr. Every time + * user calls del() method _arr obtains hole in it. + * Index of this hole wil be stored in this array + */ + this._freeIndexes = new Array(size); + /** + * {Number} Index of last free index in _freeIndexes array + */ + this._index = size - 1; + /** + * {Number} Allocated size of array. This is maximum amount + * of elements, which may be stored in FastArray + */ + this._size = size; + + for (let i = 0; i < size; i++) { + this._freeIndexes[i] = i; + this._arr[i] = 0; + } + } + + destroy() { + this._arr = null; + this._freeIndexes = null; + this._size = 0; + } + + /** + * Analog of Array.length + * @returns {Number} Amount of not empty elements in FastArray. + * Not all cells in an array may be filled by values. + */ + get length() {return this._size - this._index - 1} + + /** + * Returns allocated size + * @returns {Number} + */ + get size() {return this._size} + + /** + * Returns next free index in FastArray + * @returns {Number} + */ + get freeIndex() { + return this._freeIndexes[this._index]; + } + + /** + * Sets value to FastArray. You can't set value index due to + * optimization reason. Only a value + * @param {*} v Any value except number + */ + set(v) {this._arr[this._freeIndexes[this._index--]] = v} + + /** + * Returns a value by index + * @param {Number} i Value index + * @returns {*} + */ + get(i) {return this._arr[i]} + + /** + * Removes a value by index + * @param {Number} i Value index + */ + del(i) { + if (this._arr !== 0) + this._arr[i] = 0; + this._freeIndexes[++this._index] = i; + } + + /** + * Returns last added value by set() method + * @returns {*} Value + */ + lastAdded() { + return this._arr[this._freeIndexes[this._index + 1]]; + } + + /** + * Resizes an array. Values will not be removed during resize. + * This method is very slow and should be called not often. + * @param {Number} size New array size + */ + resize(size) { + const indexes = this._freeIndexes; + const arr = this._arr; + this._index = -1; + arr.length = indexes.length = (this._size = size); + for (let i = 0; i < size; i++) { + (arr[i] === 0) && (indexes[++this._index] = i); + } + } +} + +module.exports = FastArray; \ No newline at end of file From 1072b65da621c81b72f912bf238279755280322b Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 30 Mar 2018 17:48:59 +0300 Subject: [PATCH 14/21] speed optimization organisms colors changed to red all the time --- .../src/manager/plugins/organisms/Organism.js | 4 +- .../plugins/organisms/dos/Operators.js | 64 ++++++++++++++----- .../plugins/organisms/dos/Organisms.js | 4 -- client/src/share/Config.js | 4 +- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 3d86e85..535e123 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -193,6 +193,7 @@ class Organism extends Observer { fitness() { // TODO: check these variants //return (OConfig.codeMaxSize + 1 - this.vm.size) * (this._energy - this._startEnergy) * (this._changes || 1); + //return (OConfig.codeMaxSize + 1 - this.vm.size) * (this._energy - this._startEnergy) * (this._changes || 1); //return (OConfig.codeMaxSize + 1 - this.vm.size) * (this._energy - this._startEnergy); //return (OConfig.codeMaxSize + 1 - this.vm.size) * ((this._energy - this._startEnergy) / this._iterations); return this._energy / (this.vm.size || 1); @@ -239,7 +240,8 @@ class Organism extends Observer { } _updateColor() { - this._color = Organism.getColor((this._energy * MAX_COLORS) / this._maxEnergy); + // TODO: color update strategy will be here... + //this._color = Organism.getColor(MAX_COLORS)); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 527188b..2dab080 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -217,10 +217,54 @@ class OperatorsDos extends Operators { return ++line; } - onEatLeft(num, line, org) {this.vars[Num.getVar0(num)] = this._eat(org, num, org.x - 1, org.y); return ++line} - onEatRight(num, line, org) {this.vars[Num.getVar0(num)] = this._eat(org, num, org.x + 1, org.y); return ++line} - onEatUp(num, line, org) {this.vars[Num.getVar0(num)] = this._eat(org, num, org.x, org.y - 1); return ++line} - onEatDown(num, line, org) {this.vars[Num.getVar0(num)] = this._eat(org, num, org.x, org.y + 1); return ++line} + onEatLeft(num, line, org) { + const amount = this.vars[Num.getVar1(num)]; + if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} + const ret = this._ret; + + ret.ret = amount; + this.obs.fire(EVENTS.EAT, org, org.x - 1, org.y, ret); + org.energy += ret.ret; + this.vars[Num.getVar0(num)] = ret.ret; + + return ++line; + } + onEatRight(num, line, org) { + const amount = this.vars[Num.getVar1(num)]; + if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} + const ret = this._ret; + + ret.ret = amount; + this.obs.fire(EVENTS.EAT, org, org.x + 1, org.y, ret); + org.energy += ret.ret; + this.vars[Num.getVar0(num)] = ret.ret; + + return ++line; + } + onEatUp(num, line, org) { + const amount = this.vars[Num.getVar1(num)]; + if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} + const ret = this._ret; + + ret.ret = amount; + this.obs.fire(EVENTS.EAT, org, org.x, org.y - 1, ret); + org.energy += ret.ret; + this.vars[Num.getVar0(num)] = ret.ret; + + return ++line; + } + onEatDown(num, line, org) { + const amount = this.vars[Num.getVar1(num)]; + if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} + const ret = this._ret; + + ret.ret = amount; + this.obs.fire(EVENTS.EAT, org, org.x, org.y + 1, ret); + org.energy += ret.ret; + this.vars[Num.getVar0(num)] = ret.ret; + + return ++line; + } onStepLeft(num, line, org) {this.vars[Num.getVar0(num)] = this._step(org, org.x, org.y, org.x - 1, org.y, org.x - 1); return ++line} onStepRight(num, line, org) {this.vars[Num.getVar0(num)] = this._step(org, org.x, org.y, org.x + 1, org.y, org.x + 1); return ++line} @@ -272,18 +316,6 @@ class OperatorsDos extends Operators { return ++line; } - _eat(org, num, x, y) { - const amount = this.vars[Num.getVar1(num)]; - if (amount === 0) {return 0} - const ret = this._ret; - - ret.ret = amount; - this.obs.fire(EVENTS.EAT, org, x, y, ret); - org.energy += ret.ret; - - return ret.ret; - } - _step(org, x1, y1, x2, y2, step) { this.obs.fire(EVENTS.STEP, org, x1, y1, x2, y2); return org.x === x2 && org.y === y2 ? step : 0; diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index a3b71fb..e604ddb 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -128,10 +128,6 @@ class Organisms extends BaseOrganisms { } _onEat(org, x, y, ret) { - // - // Amount of eat energy depends on organism size. Small organisms - // eat less, big - more - // const eat = ret.ret; [x, y] = NORMALIZE_NO_DIR(x, y); const posId = POSID(x, y); diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 79477c0..f37200f 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -53,11 +53,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 10, + worldWidth: 1920, /** * {Number} World height */ - worldHeight: 1080 / 10, + worldHeight: 1080, /** * {Number} Turns on cyclic world mode. It means that organisms may go outside * it's border, but still be inside. For example, if the world has 10x10 From bd55bd8af4a7e29f01ac3339fad91b224fe4ead0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 30 Mar 2018 19:33:31 +0300 Subject: [PATCH 15/21] removed objects map optimized positions map --- client/src/manager/Manager.js | 10 +++--- client/src/manager/ManagerSpec.js | 2 +- client/src/manager/plugins/Energy.js | 14 +++----- client/src/manager/plugins/Stones.js | 5 ++- .../manager/plugins/organisms/Organisms.js | 11 +++---- .../plugins/organisms/dos/Organisms.js | 32 ++++++------------- 6 files changed, 26 insertions(+), 48 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index 67acfb0..190f614 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -37,6 +37,8 @@ class Manager extends Observer { */ constructor(hasView = true) { super(EVENT_AMOUNT); + const width = Config.worldWidth; + const height = Config.worldHeight; /** * {Queue} Queue of organisms in current Manager. Should be used by plugins. * Organisms plugin walk through this queue and run organism's code all the @@ -47,11 +49,8 @@ class Manager extends Observer { * {Object} positions of organisms in a world. Is used to prevent collisions * and track all world objects */ - this.positions = {}; - /** - * {Object} Map of world objects like stones, water,... - */ - this.objects = {}; + this.positions = []; + for (let x = 0; x < width; x++) {this.positions[x] = (new Array(height)).fill(0)} /** * {Object} This field is used as a container for public API of the Manager. * It may be used in a user console by the Operator of construct. Plugins @@ -197,7 +196,6 @@ class Manager extends Observer { this._world = null; this.api = null; this._codeRuns = 0; - this.objects = null; this.positions = null; this.organisms.destroy(); this.organisms = null; diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index 1104b1a..254c847 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -92,7 +92,7 @@ describe("client/src/manager/Manager", () => { it("Checking manager creation and it's properties", (done) => { const man = new Manager(false); expect(man.organisms.size).toBe(0); - expect(Object.keys(man.positions).length).toBe(0); + expect(man.positions.length).toBe(Config.worldWidth); expect(man.codeRuns).toBe(0); expect(!!man.api.version).toBe(true); expect(man.api.visualize).toBe(undefined); diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index 935af0b..ca492f4 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -8,8 +8,6 @@ const Config = require('./../../share/Config').Config; const Organism = require('./../../manager/plugins/organisms/Organism').Organism; const EVENTS = require('./../../share/Events').EVENTS; -const POSID = Helper.posId; - class Energy { constructor(manager) { this._manager = manager; @@ -59,17 +57,15 @@ class Energy { } _getEnergyPercent() { - let energy = 0; - const world = this._manager.world; - const width = Config.worldWidth; + let energy = 0; + const world = this._manager.world; + const width = Config.worldWidth; const height = Config.worldHeight; - const poses = this._manager.positions; - const objs = this._manager.objects; + const poses = this._manager.positions; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { - const posId = POSID(x, y); - if (typeof poses[posId] === 'undefined' && typeof objs[posId] === 'undefined' && world.getDot(x, y) > 0) {++energy} + if (poses[x][y] === 0 && world.getDot(x, y) > 0) {++energy} } } diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js index 7697fe4..ae155c8 100644 --- a/client/src/manager/plugins/Stones.js +++ b/client/src/manager/plugins/Stones.js @@ -9,11 +9,10 @@ const Organism = require('./../../manager/plugins/organisms/Organism').Organ const OBJECT_TYPES = require('./../../view/World').OBJECT_TYPES; const STONE_BLOCK_SIZE = 300; -const POSID = Helper.posId; // // We have to add stone type to global types storage // -OBJECT_TYPES.TYPE_STONE = Object.keys(OBJECT_TYPES).length; +OBJECT_TYPES.TYPE_STONE = -(Object.keys(OBJECT_TYPES).length + 1); class Stones { constructor(manager) { @@ -55,7 +54,7 @@ class Stones { if (x < 0 || x >= width || y < 0 || y >= height) {return amount} if (world.isFree(x, y)) { if (world.setDot(x, y, color)) { - man.objects[POSID(x, y)] = stone; + man.positions[x][y] = stone; if (++amount >= stones) {return amount} } } diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 7bb5954..7473a46 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -17,8 +17,6 @@ const ORG_EVENTS = require('./../../../../src/manager/plugins/organisms/Organi const Mutator = require('./Mutator'); const Num = require('./../../../vm/Num'); -const POSID = Helper.posId; - // TODO: inherit this class from Configurable class Organisms extends Configurable { /** @@ -60,7 +58,6 @@ class Organisms extends Configurable { getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in a Queue'] }); this.organisms = manager.organisms; - this.objects = manager.objects; this.randOrgItem = this.organisms.first; this.positions = manager.positions; this.world = manager.world; @@ -126,8 +123,8 @@ class Organisms extends Configurable { if (x1 === x2 && y1 === y2) {return false} world.setDot(x1, y1, 0); - this.positions[POSID(x1, y1)] = undefined; - this.positions[POSID(x2, y2)] = org; + this.positions[x1][y1] = 0; + this.positions[x2][y2] = org; return true; } @@ -141,7 +138,7 @@ class Organisms extends Configurable { orgs.last.val = org; this.addOrgHandlers(org); this.world.setDot(x, y, org.color); - this.positions[org.posId] = org; + this.positions[x][y] = org; this.parent.fire(EVENTS.BORN_ORGANISM, org); //Console.info(org.id, ' born'); @@ -278,7 +275,7 @@ class Organisms extends Configurable { } this.organisms.del(org.item); this.world.setDot(org.x, org.y, 0); - this.positions[org.posId] = undefined; + this.positions[org.x][org.y] = 0; this.parent.fire(EVENTS.KILL, org); //Console.info(org.id, ' die'); } diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index e604ddb..11273d9 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -30,11 +30,6 @@ const OBJECT = 3; */ const NORMALIZE = Helper.normalize; const NORMALIZE_NO_DIR = Helper.normalizeNoDir; -/** - * {Function} Is created to speed up this function call. constants are run - * much faster, then Helper.posId() - */ -const POSID = Helper.posId; class Organisms extends BaseOrganisms { constructor(manager) { @@ -118,31 +113,25 @@ class Organisms extends BaseOrganisms { } _onGetEnergy(x, y, ret) { - const posId = POSID(x, y); - - if (typeof(this.positions[posId]) === 'undefined') { + if (this.positions[x][y] <= 0) { ret.ret = this.world.getDot(x, y) } else { - ret.ret = this.positions[posId].energy; + ret.ret = this.positions[x][y].energy; } } _onEat(org, x, y, ret) { const eat = ret.ret; [x, y] = NORMALIZE_NO_DIR(x, y); - const posId = POSID(x, y); + const victimOrg = this.positions[x][y]; // // World object found. We can't eat objects // - if (typeof(this.objects[posId]) !== 'undefined') { - ret.ret = 0; - return; - } + if (victimOrg < 0) {ret.ret = 0; return} // // Energy found // - const victimOrg = this.positions[posId]; - if (typeof victimOrg === 'undefined') { + if (victimOrg === 0) { if (eat >= 0) { ret.ret = this.world.grabDot(x, y, eat); this.parent.fire(EVENTS.EAT_ENERGY, ret.ret); @@ -215,14 +204,13 @@ class Organisms extends BaseOrganisms { } _onCheckAt(x, y, ret) { - const posId = POSID(x, y); - [x, y] = NORMALIZE_NO_DIR(x, y); + [x, y] = NORMALIZE_NO_DIR(x, y); - if (typeof(this.objects[posId]) !== 'undefined') { - ret.ret = OBJECT + this.objects[posId]; - } else if (typeof(this.positions[posId]) === 'undefined') { + if (this.positions[x][y] < 0) { // world object + ret.ret = OBJECT + -this.positions[x][y]; + } else if (this.positions[x][y] === 0) { // energy ret.ret = this.world.getDot(x, y) > 0 ? ENERGY : EMPTY; - } else { + } else { // organism ret.ret = ORGANISM; } } From 20993d7db99ca73887aca5d7a7bf45520e622c64 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 30 Mar 2018 20:24:31 +0300 Subject: [PATCH 16/21] comments mistakes were fixed --- client/src/manager/plugins/organisms/Organism.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index d7dd838..64ae058 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -70,7 +70,7 @@ class Organism extends Observer { * @param {String} id Unique identifier of organism * @param {Number} x Unique X coordinate * @param {Number} y Unique Y coordinate - * @param {Number} item Reference to the item index, where + * @param {Object} item Reference to the Queue item, where * this organism is located * @param {Function} operatorCls Class of operators * @param {Organism} parent Parent organism if cloning is needed From c5800f2115b16dd5c053f0fa7eb15187ab2eb740 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 30 Mar 2018 23:09:53 +0300 Subject: [PATCH 17/21] Fixed #131 --- client/src/manager/plugins/Energy.js | 17 +++++++------- client/src/manager/plugins/Stones.js | 23 +++++++++---------- .../src/manager/plugins/organisms/Config.js | 4 ++-- .../plugins/organisms/dos/Operators.js | 8 +++---- client/src/share/Config.js | 4 ++-- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index ca492f4..79ff0ae 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -35,13 +35,14 @@ class Energy { } _addEnergyBlock(amount, maxEnergy) { - const width = Config.worldWidth; - const height = Config.worldHeight; - const color = Organism.getColor(Config.worldEnergyColorIndex); - let block = Config.worldEnergyBlockSize; - const world = this._manager.world; - let x = Helper.rand(width); - let y = Helper.rand(height); + const startAmount = amount; + const width = Config.worldWidth; + const height = Config.worldHeight; + const color = Organism.getColor(Config.worldEnergyColorIndex); + let block = Config.worldEnergyBlockSize; + const world = this._manager.world; + let x = Helper.rand(width); + let y = Helper.rand(height); for (let i = 0; i < block; i++) { x = x + Helper.rand(3) - 1; @@ -53,7 +54,7 @@ class Energy { } } - return amount; + return amount > startAmount ? amount : Infinity; } _getEnergyPercent() { diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js index ae155c8..204d79d 100644 --- a/client/src/manager/plugins/Stones.js +++ b/client/src/manager/plugins/Stones.js @@ -33,20 +33,19 @@ class Stones { const stones = Config.worldStonesPercent * Config.worldWidth * Config.worldHeight; let amount = 0; - while (amount < stones) { - amount = this._addStoneBlock(amount, stones); - } + while ((amount = this._addStoneBlock(amount, stones)) < stones) {} } _addStoneBlock(amount, stones) { - const width = Config.worldWidth; - const height = Config.worldHeight; - const color = Organism.getColor(Config.worldStoneColorIndex); - const man = this._manager; - const world = man.world; - const stone = OBJECT_TYPES.TYPE_STONE; - let x = Helper.rand(width); - let y = Helper.rand(height); + const startAmount = amount; + const width = Config.worldWidth; + const height = Config.worldHeight; + const color = Organism.getColor(Config.worldStoneColorIndex); + const man = this._manager; + const world = man.world; + const stone = OBJECT_TYPES.TYPE_STONE; + let x = Helper.rand(width); + let y = Helper.rand(height); for (let i = 0; i < STONE_BLOCK_SIZE; i++) { x = x + Helper.rand(3) - 1; @@ -60,7 +59,7 @@ class Stones { } } - return amount; + return amount > startAmount ? amount : Infinity; } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 5c2ee3e..48a70b1 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -126,11 +126,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 1000, + orgMaxOrgs: 100, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 1000, + orgStartAmount: 100, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 2dab080..e99548c 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -217,7 +217,7 @@ class OperatorsDos extends Operators { return ++line; } - onEatLeft(num, line, org) { + onEatLeft(num, line, org) { const amount = this.vars[Num.getVar1(num)]; if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} const ret = this._ret; @@ -229,7 +229,7 @@ class OperatorsDos extends Operators { return ++line; } - onEatRight(num, line, org) { + onEatRight(num, line, org) { const amount = this.vars[Num.getVar1(num)]; if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} const ret = this._ret; @@ -241,7 +241,7 @@ class OperatorsDos extends Operators { return ++line; } - onEatUp(num, line, org) { + onEatUp(num, line, org) { const amount = this.vars[Num.getVar1(num)]; if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} const ret = this._ret; @@ -253,7 +253,7 @@ class OperatorsDos extends Operators { return ++line; } - onEatDown(num, line, org) { + onEatDown(num, line, org) { const amount = this.vars[Num.getVar1(num)]; if (amount === 0) {this.vars[Num.getVar0(num)] = 0; return ++line} const ret = this._ret; diff --git a/client/src/share/Config.js b/client/src/share/Config.js index f37200f..98d4399 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -87,7 +87,7 @@ ClientConfig.init({ * be less then worldEnergyMinPercent. These two configs create cyclical * energy adding to the world. */ - worldEnergyMaxPercent: .5, + worldEnergyMaxPercent: .9, /** * {Number} Opposite to worldEnergyMaxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the @@ -98,7 +98,7 @@ ClientConfig.init({ * {Number} Percent of stones in a world. Percent from world size: * stoneAmount = worldStonesPercent * worldWidth * worldHeight */ - worldStonesPercent: .3, + worldStonesPercent: .25, /** * {Number} Color index for stones in a world. See Organism.MAX_COLORS * constant for details From c5d479f55e3b258b8b4267233f1170f83d611608 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 31 Mar 2018 00:37:02 +0300 Subject: [PATCH 18/21] Fixed an issue with incorrect energy percent calculation Changed default configuration n --- client/src/manager/plugins/Energy.js | 3 +-- client/src/manager/plugins/organisms/Config.js | 6 +++--- client/src/share/Config.js | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index 79ff0ae..1f68022 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -62,11 +62,10 @@ class Energy { const world = this._manager.world; const width = Config.worldWidth; const height = Config.worldHeight; - const poses = this._manager.positions; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { - if (poses[x][y] === 0 && world.getDot(x, y) > 0) {++energy} + if (world.getDot(x, y) > 0) {++energy} } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 48a70b1..ffe2f38 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -56,7 +56,7 @@ const Config = { /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 1000000, + orgCloneMinEnergy: 100000, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -126,11 +126,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 100, + orgMaxOrgs: 200, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 100, + orgStartAmount: 200, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 98d4399..1468b5e 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -93,7 +93,7 @@ ClientConfig.init({ * all energy in a world after which clever energy will turn on (be added to the * world again). */ - worldEnergyMinPercent: .1, + worldEnergyMinPercent: .3, /** * {Number} Percent of stones in a world. Percent from world size: * stoneAmount = worldStonesPercent * worldWidth * worldHeight From ca687c93539cefe1e146b4f3645b99e983cf9e74 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 31 Mar 2018 12:07:20 +0300 Subject: [PATCH 19/21] fixed one broken test fixed an issue with wrong energy calculation --- client/src/manager/plugins/Energy.js | 39 ++++++++++++------- client/src/manager/plugins/Stones.js | 18 ++++++--- .../plugins/organisms/dos/OrganismSpec.js | 2 +- client/src/share/Config.js | 2 +- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js index 1f68022..938057a 100644 --- a/client/src/manager/plugins/Energy.js +++ b/client/src/manager/plugins/Energy.js @@ -29,32 +29,45 @@ class Energy { this._manager.fire(EVENTS.WORLD_ENERGY, energy); if (energy > Config.worldEnergyMinPercent) {return} + const maxEnergy = Config.worldEnergyMaxPercent * Config.worldWidth * Config.worldHeight; - let amount = 0; - while ((amount = this._addEnergyBlock(amount, maxEnergy)) < maxEnergy) {} + let amount = 0; + let attempts = 0; + while (amount < maxEnergy && attempts < 100) { + const startAmount = amount; + amount = this._addEnergyBlock(amount, maxEnergy); + if (amount === startAmount) { + attempts++; + } else { + attempts = 0; + } + } } _addEnergyBlock(amount, maxEnergy) { - const startAmount = amount; - const width = Config.worldWidth; - const height = Config.worldHeight; - const color = Organism.getColor(Config.worldEnergyColorIndex); - let block = Config.worldEnergyBlockSize; - const world = this._manager.world; - let x = Helper.rand(width); - let y = Helper.rand(height); + const width = Config.worldWidth; + const height = Config.worldHeight; + const color = Organism.getColor(Config.worldEnergyColorIndex); + let block = Config.worldEnergyBlockSize; + const world = this._manager.world; + let x = Helper.rand(width); + let y = Helper.rand(height); for (let i = 0; i < block; i++) { x = x + Helper.rand(3) - 1; y = y + Helper.rand(3) - 1; - if (x < 0 || x >= width || y < 0 || y >= height) {return amount} + if (x < 0 || x >= width || y < 0 || y >= height) { + return amount + } if (world.isFree(x, y)) { world.setDot(x, y, color); - if (++amount > maxEnergy) {return amount} + if (++amount > maxEnergy) { + return amount + } } } - return amount > startAmount ? amount : Infinity; + return amount; } _getEnergyPercent() { diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js index 204d79d..344b717 100644 --- a/client/src/manager/plugins/Stones.js +++ b/client/src/manager/plugins/Stones.js @@ -31,13 +31,21 @@ class Stones { _onLoop(counter) { if (counter > 1 || Config.worldStonesPercent === .0) {return} - const stones = Config.worldStonesPercent * Config.worldWidth * Config.worldHeight; - let amount = 0; - while ((amount = this._addStoneBlock(amount, stones)) < stones) {} + const stones = Config.worldStonesPercent * Config.worldWidth * Config.worldHeight; + let amount = 0; + let attempts = 0; + while (amount < stones && attempts < 100) { + const startAmount = amount; + amount = this._addStoneBlock(amount, stones); + if (startAmount === amount) { + attempts++; + } else { + attempts = 0; + } + } } _addStoneBlock(amount, stones) { - const startAmount = amount; const width = Config.worldWidth; const height = Config.worldHeight; const color = Organism.getColor(Config.worldStoneColorIndex); @@ -59,7 +67,7 @@ class Stones { } } - return amount > startAmount ? amount : Infinity; + return amount; } } diff --git a/client/src/manager/plugins/organisms/dos/OrganismSpec.js b/client/src/manager/plugins/organisms/dos/OrganismSpec.js index c116ac0..460d1b0 100644 --- a/client/src/manager/plugins/organisms/dos/OrganismSpec.js +++ b/client/src/manager/plugins/organisms/dos/OrganismSpec.js @@ -160,7 +160,7 @@ describe("client/src/organism/OrganismDos", () => { const color = org.color; expect(org.color).toBe(color); org.energy++; - expect(org.color).not.toBe(color); + expect(org.color).toBe(color); }); }); diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 1468b5e..0767836 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -87,7 +87,7 @@ ClientConfig.init({ * be less then worldEnergyMinPercent. These two configs create cyclical * energy adding to the world. */ - worldEnergyMaxPercent: .9, + worldEnergyMaxPercent: .7, /** * {Number} Opposite to worldEnergyMaxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the From ba9bfd117089a4eef525da349d1c3bc0a913dcb9 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 1 Apr 2018 01:49:05 +0300 Subject: [PATCH 20/21] from now organism color shows his age (green - young, red - old) fixed very critical issue with burning of child t the end of life --- .../src/manager/plugins/organisms/Config.js | 10 ++++---- .../src/manager/plugins/organisms/Organism.js | 5 +--- .../manager/plugins/organisms/Organisms.js | 22 +++++++++--------- .../plugins/organisms/dos/Organisms.js | 6 +++-- client/src/share/Config.js | 2 +- common/src/Queue.js | 23 +++++++++++++++++++ 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ffe2f38..ed7ac4d 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -52,11 +52,11 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 700, + orgCloneMinAge: 300, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 100000, + orgCloneMinEnergy: 2000000, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -126,17 +126,17 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 200, + orgMaxOrgs: 1000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 200, + orgStartAmount: 1000, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created * by operator and not by evolution. */ - orgStartEnergy: 1000000, + orgStartEnergy: 90000000, /** * {Number} Amount of bits for storing a numeric constant inside byte code */ diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 64ae058..c8c7224 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -47,8 +47,6 @@ class Organism extends Observer { return r << 16 | g << 8 | b; } - static getMaxColors() {return MAX_COLORS} - /** * Is called before every run. Should return true, if everything * is okay and we don't need to interrupt running. If true, then @@ -238,8 +236,7 @@ class Organism extends Observer { } _updateColor() { - // TODO: color update strategy will be here... - //this._color = Organism.getColor(MAX_COLORS)); + this._color = Organism.getColor(this._iterations * (MAX_COLORS / OConfig.orgAlivePeriod)); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 7473a46..771fda9 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -131,18 +131,17 @@ class Organisms extends Configurable { createOrg(x, y, parent = null) { if (x === -1) {return false} - const orgs = this.organisms; - orgs.add(null); - let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.last, parent); + const item = this.organisms.addAfter(this.randOrgItem, null); + let org = this.createEmptyOrg(++this._orgId + '', x, y, item, parent); - orgs.last.val = org; + item.val = org; this.addOrgHandlers(org); this.world.setDot(x, y, org.color); this.positions[x][y] = org; this.parent.fire(EVENTS.BORN_ORGANISM, org); //Console.info(org.id, ' born'); - return true; + return item; } /** @@ -203,20 +202,22 @@ class Organisms extends Configurable { if (this.onBeforeClone(org) === false) {return false} let x; let y; + let item; [x, y] = this.world.getNearFreePos(org.x, org.y); - if (x === -1 || this.createOrg(x, y, org) === false) {return false} - let child = this.organisms.last.val; + if (x === -1 || (item = this.createOrg(x, y, org)) === false) {return false} + let child = item.val; this.onClone(org, child); if (org.energy < 1 || child.energy < 1) {return false} this.parent.fire(EVENTS.CLONE, org, child, isCrossover); - return true; + return item; } _crossover(org1, org2) { - if (!this._clone(org1, true)) {return false} - let child = this.organisms.last.val; + const item = this._clone(org1, true); + if (item === false) {return false} + let child = item.val; if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); @@ -306,7 +307,6 @@ class Organisms extends Configurable { // organisms before cloning. They should kill each other to have a possibility // to clone them. // - if (org.energy < OConfig.orgCloneMinEnergy) {return} if (OConfig.orgKillOnClone && this.organisms.size >= OConfig.orgMaxOrgs) {this.randOrg().destroy()} if (this.organisms.size < OConfig.orgMaxOrgs) {this._clone(org)} } diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 11273d9..659788d 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -226,8 +226,10 @@ class Organisms extends BaseOrganisms { * @param {Object} ret Return object */ _onStepIn(x, y, orgJson, ret) { - if (ret.ret = this.world.isFree(x, y) && this.organisms.size < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent) && this.createOrg(x, y)) { - const org = this.organisms.last.val; + if (ret.ret = this.world.isFree(x, y) && this.organisms.size < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent)) { + const item = this.createOrg(x, y); + if (item === false) {return} + const org = item.val; org.unserialize(orgJson); const energy = (org.energy * OConfig.orgStepEnergySpendPercent + .5) << 0; // diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 0767836..27a3ef1 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -93,7 +93,7 @@ ClientConfig.init({ * all energy in a world after which clever energy will turn on (be added to the * world again). */ - worldEnergyMinPercent: .3, + worldEnergyMinPercent: .28, /** * {Number} Percent of stones in a world. Percent from world size: * stoneAmount = worldStonesPercent * worldWidth * worldHeight diff --git a/common/src/Queue.js b/common/src/Queue.js index 9c22dec..58caf91 100644 --- a/common/src/Queue.js +++ b/common/src/Queue.js @@ -50,6 +50,29 @@ class Queue { this._first.val = val; } + /** + * The same like add(), but inserts after specified item in a queue + * @param {Object} item Item, after which val will be inserted + * @param {*} val Value to insert + * @return {Object} Inserted item + */ + addAfter(item, val) { + if (item === this._last) {this.add(val); return this._last} + if (this._size++ > 0) { + const newItem = { + prev: item, + next: item.next, + val + }; + item.next.prev = newItem; + item.next = newItem; + return newItem; + } + this._first.val = val; + + return this._first; + } + /** * Removes specified item from the queue. 'item' parameter is not * the same as value inside this item. Remember remove position may From 41a437efc666ed16c02e90c33366967211629f6a Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 3 Apr 2018 13:41:03 +0300 Subject: [PATCH 21/21] fixed an issue with infinite alive period and huge amount of mutations fixed an issue with incorrect color of organisms in case of infinite alive period fixed random distribution of organisms by age optimized _randOrg() method --- .../src/manager/plugins/organisms/Config.js | 20 +++++----- .../src/manager/plugins/organisms/Mutator.js | 7 +++- .../src/manager/plugins/organisms/Organism.js | 2 +- .../manager/plugins/organisms/Organisms.js | 37 +++++++++++-------- client/src/share/Config.js | 4 +- common/src/Observer.js | 3 +- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ed7ac4d..931954f 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,12 +15,12 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .001, .001, .00001, .00000001, .0001, // var, const, if, loop, operator, - .0001, .2, .2, .2, .2, // lookAt, eatLeft, eatRight, eatUp, eatDown, - 2, 2, 2, 2, // stepLeft, stepRight, stepUp, stepDown, - .001, .001, // fromMem, toMem, - .0001, .0001, // myX, myY, - .001, .001, .001, .001 // checkLeft, checkRight, checkUp, checkDown + .0001, .0001, .00001, .00000001, .0001, // var, const, if, loop, operator, + .00001, 2, 2, 2, 2, // lookAt, eatLeft, eatRight, eatUp, eatDown, + 2, 2, 2, 2, // stepLeft, stepRight, stepUp, stepDown, + .001, .001, // fromMem, toMem, + .0001, .0001, // myX, myY, + .001, .001, .001, .001 // checkLeft, checkRight, checkUp, checkDown ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -52,18 +52,18 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 300, + orgCloneMinAge: 3000, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 2000000, + orgCloneMinEnergy: 20000000, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false * mean, that new organism will not be cloned, if amount of organisms is >= * orgMaxOrgs config. */ - orgKillOnClone: false, + orgKillOnClone: true, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -100,7 +100,7 @@ const Config = { * {Number} Amount of iterations when organism is alive. It will die after * this period. If 0, then will not be used and organism may leave forever */ - orgAlivePeriod: 1000, + orgAlivePeriod: 0, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, diff --git a/client/src/manager/plugins/organisms/Mutator.js b/client/src/manager/plugins/organisms/Mutator.js index 65de19c..e7152a5 100644 --- a/client/src/manager/plugins/organisms/Mutator.js +++ b/client/src/manager/plugins/organisms/Mutator.js @@ -15,6 +15,11 @@ const Helper = require('./../../../../../common/src/Helper'); const Num = require('./../../../vm/Num'); const ADD_MUTAION_INDEX = 6; +/** + * {Number} Default alive period, which is used if orgAlivePeriod + * config is set to zero + */ +const MAX_ALIVE_PERIOD = 10000; class Mutator { static _onChange(org) { @@ -54,7 +59,7 @@ class Mutator { static _onMutationPeriod(org) { if (!OConfig.orgRainPerOrg) {return} - org.mutationPeriod = Helper.rand(OConfig.orgAlivePeriod - 1) + 1; + org.mutationPeriod = OConfig.orgAlivePeriod < 1 ? Helper.rand(MAX_ALIVE_PERIOD) + 1 : Helper.rand(OConfig.orgAlivePeriod - 1) + 1; org.changes++; } diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index c8c7224..c1a7ff2 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -236,7 +236,7 @@ class Organism extends Observer { } _updateColor() { - this._color = Organism.getColor(this._iterations * (MAX_COLORS / OConfig.orgAlivePeriod)); + this._color = Organism.getColor(OConfig.orgAlivePeriod === 0 ? MAX_COLORS : this._iterations * (MAX_COLORS / OConfig.orgAlivePeriod)); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 771fda9..28e0631 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -16,6 +16,10 @@ const ORG_EVENTS = require('./../../../../src/manager/plugins/organisms/Organi //const Backup = require('./../backup/Backup'); const Mutator = require('./Mutator'); const Num = require('./../../../vm/Num'); +/** + * {Number} Random range for selection of random organism from a Queue + */ +const RAND_RANGE = 5; // TODO: inherit this class from Configurable class Organisms extends Configurable { @@ -98,7 +102,6 @@ class Organisms extends Configurable { this._maxEnergy = this._oldMaxEnergy; this._oldMaxEnergy = 0; } - org.maxEnergy = this._maxEnergy; } addOrgHandlers(org) { @@ -131,6 +134,7 @@ class Organisms extends Configurable { createOrg(x, y, parent = null) { if (x === -1) {return false} + this._randOrg(); const item = this.organisms.addAfter(this.randOrgItem, null); let org = this.createEmptyOrg(++this._orgId + '', x, y, item, parent); @@ -148,8 +152,8 @@ class Organisms extends Configurable { * Returns random organism of current population * @return {Organism|null} */ - randOrg() { - const offs = Helper.rand(this.organisms.size) + 1; + _randOrg() { + const offs = Helper.rand(RAND_RANGE) + 1; let item = this.randOrgItem; for (let i = 0; i < offs; i++) { @@ -173,7 +177,7 @@ class Organisms extends Configurable { while (org = item && item.val) { org.run(); - org.energy > 0 && this.onOrganism(org); + this.onOrganism(org); item = item.next; } @@ -187,8 +191,8 @@ class Organisms extends Configurable { } _tournament(org1 = null, org2 = null) { - org1 = org1 || this.randOrg(); - org2 = org2 || this.randOrg(); + org1 = org1 || this._randOrg(); + org2 = org2 || this._randOrg(); if (org1.energy < 1 && org2.energy < 1) {return false} if ((org2.energy > 0 && org1.energy < 1) || this.compare(org2, org1)) { @@ -293,12 +297,12 @@ class Organisms extends Configurable { //const orgAmount = this.organisms.size; //if (OConfig.orgKillOnClone && orgAmount >= maxOrgs) {this._killInTour()} - //if (orgAmount >= maxOrgs && (OConfig.orgKillOnClone || Math.random() <= (org.energy / org.vm.size) / this._maxEnergy)) {this.randOrg().destroy()} + //if (orgAmount >= maxOrgs && (OConfig.orgKillOnClone || Math.random() <= (org.energy / org.vm.size) / this._maxEnergy)) {this._randOrg().destroy()} // if (this.organisms.size >= OConfig.orgMaxOrgs && Math.random() <= ((org.energy / 10000000000000) * (org.iterations / OConfig.orgAlivePeriod))) { - // this.randOrg().destroy(); + // this._randOrg().destroy(); // } //if (this.organisms.size < maxOrgs) {this._clone(org)} - //if (this.organisms.size >= maxOrgs && Math.random() <= (org.energy / org.vm.size) / this._maxEnergy) {this.randOrg().destroy()} + //if (this.organisms.size >= maxOrgs && Math.random() <= (org.energy / org.vm.size) / this._maxEnergy) {this._randOrg().destroy()} // // This is very important part of application! Cloning should be available only if // amount of organisms is less then maximum or if current organism has ate other just @@ -307,13 +311,16 @@ class Organisms extends Configurable { // organisms before cloning. They should kill each other to have a possibility // to clone them. // - if (OConfig.orgKillOnClone && this.organisms.size >= OConfig.orgMaxOrgs) {this.randOrg().destroy()} + if (OConfig.orgKillOnClone && this.organisms.size >= OConfig.orgMaxOrgs) { + const randOrg = this._randOrg(); + if (randOrg !== org && Math.random() <= org.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} + } if (this.organisms.size < OConfig.orgMaxOrgs) {this._clone(org)} } _killInTour() { - let org1 = this.randOrg(); - let org2 = this.randOrg(); + let org1 = this._randOrg(); + let org2 = this._randOrg(); if (org1.energy < 1 || org2.energy < 1 || org1 === org2 || this.organisms.size < 1) {return false} const winner = this._tournament(org1, org2); if (winner === false) {return false} @@ -338,7 +345,7 @@ class Organisms extends Configurable { _updateRandomOrgs(counter) { if (counter % OConfig.orgRandomOrgPeriod !== 0 || OConfig.orgRandomOrgPeriod === 0 || this.organisms.size < 1) {return false} - const vm = this.randOrg().vm; + const vm = this._randOrg().vm; const size = Helper.rand(vm.size) + 1; const pos = Helper.rand(vm.size - size); @@ -354,8 +361,8 @@ class Organisms extends Configurable { // We have to have a possibility to crossover not only with best // organisms, but with low fit also // - let org1 = Helper.rand(2) === 0 ? this._tournament() : this.randOrg(); - let org2 = Helper.rand(2) === 0 ? this._tournament() : this.randOrg(); + let org1 = Helper.rand(2) === 0 ? this._tournament() : this._randOrg(); + let org2 = Helper.rand(2) === 0 ? this._tournament() : this._randOrg(); if (org1 === false || org2 === false || org1.energy < 1 || org2.energy < 1) {return false} this._crossover(org1, org2); diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 27a3ef1..d70a4bb 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -75,7 +75,7 @@ ClientConfig.init({ /** * {Number} size of one clever energy block in dots */ - worldEnergyBlockSize: 20, + worldEnergyBlockSize: 10, /** * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details @@ -87,7 +87,7 @@ ClientConfig.init({ * be less then worldEnergyMinPercent. These two configs create cyclical * energy adding to the world. */ - worldEnergyMaxPercent: .7, + worldEnergyMaxPercent: .3, /** * {Number} Opposite to worldEnergyMaxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the diff --git a/common/src/Observer.js b/common/src/Observer.js index 97e879c..6e525a0 100644 --- a/common/src/Observer.js +++ b/common/src/Observer.js @@ -53,9 +53,8 @@ class Observer { /** * This method is a most frequently called one. So we have to * optimize it as much as possible - * @param {Number} event Event number + * @param {Number} event Event number. Not string * @param {*} args List of arguments - * @param args */ fire(event, ...args) { const handlers = this._handlers[event] || {};